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
} |