github.com/docker/docker@v299999999.0.0-20200612211812-aaf470eca7b5+incompatible/daemon/listeners/listeners_linux.go (about)

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