@@ -10,6 +10,7 @@ import (
1010 "os"
1111 "strconv"
1212 "strings"
13+ "sync"
1314 "syscall"
1415)
1516
@@ -39,6 +40,39 @@ func NewUnixSocketConfig(socketPath string) UnixSocketConfig {
3940 return usc
4041}
4142
43+ type sysdEnvData struct {
44+ pid int
45+ fdNames []string
46+ fdNamesStr string
47+ numFds int
48+ }
49+
50+ var sysdEnvParser = struct {
51+ sysdOnce sync.Once
52+ data sysdEnvData
53+ err error
54+ }{}
55+
56+ func parse () (sysdEnvData , error ) {
57+ p := & sysdEnvParser
58+ p .sysdOnce .Do (func () {
59+ p .data .pid , p .err = strconv .Atoi (os .Getenv ("LISTEN_PID" ))
60+ if p .err != nil {
61+ p .err = fmt .Errorf ("invalid LISTEN_PID, err: %w" , p .err )
62+ return
63+ }
64+ p .data .numFds , p .err = strconv .Atoi (os .Getenv ("LISTEN_FDS" ))
65+ if p .err != nil {
66+ p .err = fmt .Errorf ("invalid LISTEN_FDS, err: %w" , p .err )
67+ return
68+ }
69+ p .data .fdNamesStr = os .Getenv ("LISTEN_FDNAMES" )
70+ p .data .fdNames = strings .Split (p .data .fdNamesStr , ":" )
71+
72+ })
73+ return p .data , p .err
74+ }
75+
4276// SysdConfig has the configuration for the socket activated fd
4377type SysdConfig struct {
4478 // Integer value starting at 0. Either index or name is required
@@ -54,7 +88,7 @@ type SysdConfig struct {
5488// DefaultSysdConfig has the default values for SysdConfig
5589var DefaultSysdConfig = SysdConfig {
5690 CheckPID : true ,
57- UnsetEnv : false ,
91+ UnsetEnv : true ,
5892}
5993
6094// NewSysDConfigWithFDIdx creates SysdConfig with defaults and fdIdx
@@ -112,53 +146,47 @@ func (s *SysdConfig) GetListener() (net.Listener, error) {
112146 defer UnsetSystemdListenVars ()
113147 }
114148
115- if s .CheckPID {
116- pid , err := strconv .Atoi (os .Getenv ("LISTEN_PID" ))
117- if err != nil {
118- return nil , fmt .Errorf ("invalid LISTEN_PID, err: %w" , err )
119- }
120- if pid != os .Getpid () {
121- return nil , fmt .Errorf ("unexpected PID, current:%v, LISTEN_PID: %v" , os .Getpid (), pid )
122- }
123- }
124-
125- numFds , err := strconv .Atoi (os .Getenv ("LISTEN_FDS" ))
149+ envData , err := parse ()
126150 if err != nil {
127- return nil , fmt . Errorf ( "invalid LISTEN_FDS, err: %w" , err )
151+ return nil , err
128152 }
129153
130- fdNames := strings .Split (os .Getenv ("LISTEN_FDNAMES" ), ":" )
154+ if s .CheckPID {
155+ if envData .pid != os .Getpid () {
156+ return nil , fmt .Errorf ("unexpected PID, current:%v, LISTEN_PID: %v" , os .Getpid (), envData .pid )
157+ }
158+ }
131159
132160 if s .FDIndex != nil {
133161 idx := * s .FDIndex
134- if idx < 0 || idx >= numFds {
135- return nil , fmt .Errorf ("invalid fd index, expected between 0 and %v, got: %v" , numFds , idx )
162+ if idx < 0 || idx >= envData . numFds {
163+ return nil , fmt .Errorf ("invalid fd index, expected between 0 and %v, got: %v" , envData . numFds , idx )
136164 }
137165 fd := StartFD + idx
138- if idx < len (fdNames ) {
139- return makeFdListener (fd , fdNames [idx ])
166+ if idx < len (envData . fdNames ) {
167+ return makeFdListener (fd , envData . fdNames [idx ])
140168 }
141169 return makeFdListener (fd , fmt .Sprintf ("sysdfd_%d" , fd ))
142170 }
143171
144172 if s .FDName != nil {
145- for idx , name := range fdNames {
173+ for idx , name := range envData . fdNames {
146174 if name == * s .FDName {
147175 fd := StartFD + idx
148176 return makeFdListener (fd , name )
149177 }
150178 }
151- return nil , fmt .Errorf ("fdName not found: %q, LISTEN_FDNAMES:%q" , * s .FDName , os . Getenv ( "LISTEN_FDNAMES" ) )
179+ return nil , fmt .Errorf ("fdName not found: %q, LISTEN_FDNAMES:%q" , * s .FDName , envData . fdNamesStr )
152180 }
153181
154182 return nil , errors .New ("neither FDIndex nor FDName set" )
155183}
156184
157185// UnknownAddress Error is returned when address does not match any known syntax
158- type UnknownAddress string
186+ type UnknownAddress struct {}
159187
160188func (u UnknownAddress ) Error () string {
161- return fmt . Sprintf ( "unknown address: %q" , string ( u ))
189+ return "unknown address"
162190}
163191
164192// GetListener gets a unix or systemd socket listener
@@ -182,15 +210,15 @@ func GetListener(addr string) (net.Listener, error) {
182210 return sysdc .GetListener ()
183211 }
184212
185- return nil , UnknownAddress ( addr )
213+ return nil , UnknownAddress {}
186214}
187215
188216// ListenAndServe is the drop-in replacement for `http.ListenAndServe`.
189217// Supports unix and systemd sockets in addition
190218func ListenAndServe (addr string , h http.Handler ) error {
191219
192220 listener , err := GetListener (addr )
193- if _ , ok := err .(UnknownAddress ); err != nil && ! ok {
221+ if _ , isUnknown := err .(UnknownAddress ); err != nil && ! isUnknown {
194222 return err
195223 }
196224
@@ -211,7 +239,7 @@ func ListenAndServe(addr string, h http.Handler) error {
211239
212240// UnsetSystemdListenVars unsets the LISTEN* environment variables so they are not passed to any child processes
213241func UnsetSystemdListenVars () {
214- os .Unsetenv ("LISTEN_PID" )
215- os .Unsetenv ("LISTEN_FDS" )
216- os .Unsetenv ("LISTEN_FDNAMES" )
242+ _ = os .Unsetenv ("LISTEN_PID" )
243+ _ = os .Unsetenv ("LISTEN_FDS" )
244+ _ = os .Unsetenv ("LISTEN_FDNAMES" )
217245}
0 commit comments