...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package activation
17
18 import (
19 "errors"
20 "net"
21 "os"
22 "strconv"
23 "strings"
24 "syscall"
25 )
26
27
28
29
30 func GetListener(index uint, family, laddr string) (listener net.Listener, err error) {
31 listener, err = einhornListener(index)
32 if listener != nil || err != nil {
33 return
34 }
35 listener, err = socketmasterListener(index)
36 if listener != nil || err != nil {
37 return
38 }
39 listener, err = systemdListener(index)
40 if listener != nil || err != nil {
41 return
42 }
43 if family == "unix" || family == "unixpacket" {
44 os.Remove(laddr)
45 }
46 return net.Listen(family, laddr)
47 }
48
49
50
51
52 var savedEnv map[string]string
53
54 func popEnv(name string) string {
55 if savedEnv == nil {
56 savedEnv = make(map[string]string, 1)
57 }
58 val := savedEnv[name]
59 if val != "" {
60 return val
61 }
62 val = os.Getenv(name)
63 savedEnv[name] = val
64 os.Unsetenv(name)
65 return val
66 }
67
68 func popEnvInt(name string) (int, error) {
69 str := popEnv(name)
70 if str == "" {
71 return -1, nil
72 }
73 return strconv.Atoi(str)
74 }
75
76 func fdListener(fd uintptr) (net.Listener, error) {
77 if err := syscall.SetNonblock(int(fd), true); err != nil {
78 return nil, err
79 }
80 file := os.NewFile(fd, "FD_"+strconv.Itoa(int(fd)))
81
82 defer file.Close()
83 return net.FileListener(file)
84 }
85
86 func systemdListener(index uint) (net.Listener, error) {
87
88
89
90 pid, err := popEnvInt("LISTEN_PID")
91 if err != nil || (pid != -1 && pid != os.Getpid()) {
92
93 return nil, err
94 }
95 nfds, err := popEnvInt("LISTEN_FDS")
96 if err != nil || nfds < int(index)+1 {
97 return nil, err
98 }
99 return fdListener(uintptr(3 + index))
100 }
101
102 func einhornListener(index uint) (net.Listener, error) {
103
104
105
106 ppid, err := popEnvInt("EINHORN_MASTER_PID")
107 if err != nil || (ppid != -1 && ppid != os.Getppid()) {
108
109 return nil, err
110 }
111 numfds, err := popEnvInt("EINHORN_FD_COUNT")
112 if err != nil || numfds < int(index)+1 {
113 return nil, err
114 }
115 name := "EINHORN_FD_" + strconv.Itoa(int(index))
116 fd, err := popEnvInt(name)
117 if err != nil {
118 return nil, err
119 } else if fd < 0 {
120 return nil, errors.New("Missing environment variable " + name)
121 }
122
123 os.Unsetenv("EINHORN_FDS")
124 return fdListener(uintptr(fd))
125 }
126
127 func socketmasterListener(index uint) (net.Listener, error) {
128
129
130
131 fdstr := popEnv("EINHORN_FDS")
132 if fdstr == "" {
133 return nil, nil
134 }
135 fds := strings.Split(fdstr, " ")
136 if len(fds) < int(index)+1 {
137 return nil, nil
138 }
139 fd, err := strconv.Atoi(fds[index])
140 if err != nil {
141 return nil, err
142 }
143 return fdListener(uintptr(fd))
144 }
145
146 type filer interface {
147 File() (*os.File, error)
148 }
149
View as plain text