github.com/fabiokung/docker@v0.11.2-0.20170222101415-4534dcd49497/pkg/listeners/listeners_unix.go (about)

     1  // +build !windows,!solaris
     2  
     3  package listeners
     4  
     5  import (
     6  	"crypto/tls"
     7  	"fmt"
     8  	"net"
     9  	"strconv"
    10  
    11  	"github.com/coreos/go-systemd/activation"
    12  	"github.com/docker/go-connections/sockets"
    13  )
    14  
    15  // Init creates new listeners for the server.
    16  // TODO: Clean up the fact that socketGroup and tlsConfig aren't always used.
    17  func Init(proto, addr, socketGroup string, tlsConfig *tls.Config) ([]net.Listener, error) {
    18  	ls := []net.Listener{}
    19  
    20  	switch proto {
    21  	case "fd":
    22  		fds, err := listenFD(addr, tlsConfig)
    23  		if err != nil {
    24  			return nil, err
    25  		}
    26  		ls = append(ls, fds...)
    27  	case "tcp":
    28  		l, err := sockets.NewTCPSocket(addr, tlsConfig)
    29  		if err != nil {
    30  			return nil, err
    31  		}
    32  		ls = append(ls, l)
    33  	case "unix":
    34  		l, err := sockets.NewUnixSocket(addr, socketGroup)
    35  		if err != nil {
    36  			return nil, fmt.Errorf("can't create unix socket %s: %v", addr, err)
    37  		}
    38  		ls = append(ls, l)
    39  	default:
    40  		return nil, fmt.Errorf("invalid protocol format: %q", proto)
    41  	}
    42  
    43  	return ls, nil
    44  }
    45  
    46  // listenFD returns the specified socket activated files as a slice of
    47  // net.Listeners or all of the activated files if "*" is given.
    48  func listenFD(addr string, tlsConfig *tls.Config) ([]net.Listener, error) {
    49  	var (
    50  		err       error
    51  		listeners []net.Listener
    52  	)
    53  	// socket activation
    54  	if tlsConfig != nil {
    55  		listeners, err = activation.TLSListeners(false, tlsConfig)
    56  	} else {
    57  		listeners, err = activation.Listeners(false)
    58  	}
    59  	if err != nil {
    60  		return nil, err
    61  	}
    62  
    63  	if len(listeners) == 0 {
    64  		return nil, fmt.Errorf("no sockets found via socket activation: make sure the service was started by systemd")
    65  	}
    66  
    67  	// default to all fds just like unix:// and tcp://
    68  	if addr == "" || addr == "*" {
    69  		return listeners, nil
    70  	}
    71  
    72  	fdNum, err := strconv.Atoi(addr)
    73  	if err != nil {
    74  		return nil, fmt.Errorf("failed to parse systemd fd address: should be a number: %v", addr)
    75  	}
    76  	fdOffset := fdNum - 3
    77  	if len(listeners) < int(fdOffset)+1 {
    78  		return nil, fmt.Errorf("too few socket activated files passed in by systemd")
    79  	}
    80  	if listeners[fdOffset] == nil {
    81  		return nil, fmt.Errorf("failed to listen on systemd activated file: fd %d", fdOffset+3)
    82  	}
    83  	for i, ls := range listeners {
    84  		if i == fdOffset || ls == nil {
    85  			continue
    86  		}
    87  		if err := ls.Close(); err != nil {
    88  			return nil, fmt.Errorf("failed to close systemd activated file: fd %d: %v", fdOffset+3, err)
    89  		}
    90  	}
    91  	return []net.Listener{listeners[fdOffset]}, nil
    92  }