pkg/listeners/listeners_unix.go
86d8758e
 // +build !windows,!solaris
69246e15
 
34c29277
 package listeners
69246e15
 
 import (
0f2b3191
 	"crypto/tls"
69246e15
 	"fmt"
62806cc8
 	"net"
c7c2cd4e
 	"os"
ead2f800
 	"strconv"
69246e15
 
34c29277
 	"github.com/coreos/go-systemd/activation"
8e034802
 	"github.com/docker/go-connections/sockets"
1009e6a4
 	"github.com/sirupsen/logrus"
69246e15
 )
 
34c29277
 // Init creates new listeners for the server.
5ee0a941
 // TODO: Clean up the fact that socketGroup and tlsConfig aren't always used.
 func Init(proto, addr, socketGroup string, tlsConfig *tls.Config) ([]net.Listener, error) {
 	ls := []net.Listener{}
 
69246e15
 	switch proto {
 	case "fd":
5ee0a941
 		fds, err := listenFD(addr, tlsConfig)
62806cc8
 		if err != nil {
 			return nil, err
 		}
5ee0a941
 		ls = append(ls, fds...)
69246e15
 	case "tcp":
5ee0a941
 		l, err := sockets.NewTCPSocket(addr, tlsConfig)
0bfbc6e7
 		if err != nil {
62806cc8
 			return nil, err
 		}
6f9fa646
 		ls = append(ls, l)
69246e15
 	case "unix":
bdf4cad1
 		gid, err := lookupGID(socketGroup)
e5d77c64
 		if err != nil {
169c0139
 			if socketGroup != "" {
 				if socketGroup != defaultSocketGroup {
 					return nil, err
 				}
 				logrus.Warnf("could not change group %s to %s: %v", addr, defaultSocketGroup, err)
c7c2cd4e
 			}
 			gid = os.Getgid()
e5d77c64
 		}
 		l, err := sockets.NewUnixSocket(addr, gid)
6f9fa646
 		if err != nil {
20012e42
 			return nil, fmt.Errorf("can't create unix socket %s: %v", addr, err)
081c6c76
 		}
6f9fa646
 		ls = append(ls, l)
62806cc8
 	default:
619bf567
 		return nil, fmt.Errorf("invalid protocol format: %q", proto)
081c6c76
 	}
 
5ee0a941
 	return ls, nil
ead2f800
 }
ed39fbeb
 
931645c4
 // listenFD returns the specified socket activated files as a slice of
 // net.Listeners or all of the activated files if "*" is given.
0f2b3191
 func listenFD(addr string, tlsConfig *tls.Config) ([]net.Listener, error) {
 	var (
 		err       error
 		listeners []net.Listener
 	)
931645c4
 	// socket activation
0f2b3191
 	if tlsConfig != nil {
34c29277
 		listeners, err = activation.TLSListeners(false, tlsConfig)
0f2b3191
 	} else {
34c29277
 		listeners, err = activation.Listeners(false)
0f2b3191
 	}
931645c4
 	if err != nil {
 		return nil, err
 	}
 
fb04043c
 	if len(listeners) == 0 {
619bf567
 		return nil, fmt.Errorf("no sockets found via socket activation: make sure the service was started by systemd")
931645c4
 	}
 
 	// default to all fds just like unix:// and tcp://
fb04043c
 	if addr == "" || addr == "*" {
 		return listeners, nil
931645c4
 	}
 
fb04043c
 	fdNum, err := strconv.Atoi(addr)
 	if err != nil {
619bf567
 		return nil, fmt.Errorf("failed to parse systemd fd address: should be a number: %v", addr)
fb04043c
 	}
931645c4
 	fdOffset := fdNum - 3
fb04043c
 	if len(listeners) < int(fdOffset)+1 {
619bf567
 		return nil, fmt.Errorf("too few socket activated files passed in by systemd")
931645c4
 	}
fb04043c
 	if listeners[fdOffset] == nil {
619bf567
 		return nil, fmt.Errorf("failed to listen on systemd activated file: fd %d", fdOffset+3)
fb04043c
 	}
 	for i, ls := range listeners {
 		if i == fdOffset || ls == nil {
 			continue
 		}
 		if err := ls.Close(); err != nil {
390fe752
 			return nil, fmt.Errorf("failed to close systemd activated file: fd %d: %v", fdOffset+3, err)
fb04043c
 		}
931645c4
 	}
 	return []net.Listener{listeners[fdOffset]}, nil
 }