@@ -12,13 +12,26 @@ import (
1212 "sync"
1313 "sync/atomic"
1414 "syscall"
15- "time"
1615
1716 "go.uber.org/zap"
1817
1918 "github.com/status-im/status-go/common"
2019)
2120
21+ // tcpListenConfig sets SO_REUSEADDR so rapid Stop/Start can rebind the same
22+ // cached ephemeral port without waiting for the kernel to release it.
23+ var tcpListenConfig = net.ListenConfig {
24+ Control : func (network , address string , c syscall.RawConn ) error {
25+ var optErr error
26+ if err := c .Control (func (fd uintptr ) {
27+ optErr = setReuseAddr (fd )
28+ }); err != nil {
29+ return err
30+ }
31+ return optErr
32+ },
33+ }
34+
2235type Config struct {
2336 Cert * tls.Certificate
2437 AddrPort netip.AddrPort
@@ -112,12 +125,17 @@ func (s *Server) getBindAddrPort() netip.AddrPort {
112125
113126func (s * Server ) createListener () (net.Listener , error ) {
114127 addr := s .getBindAddrPort ()
128+ addrStr := addr .String ()
129+
130+ ln , err := tcpListenConfig .Listen (context .Background (), "tcp" , addrStr )
131+ if err != nil {
132+ return nil , err
133+ }
134+
115135 if s .config .Cert == nil {
116- // HTTP mode
117- return net .Listen ("tcp" , addr .String ())
136+ return ln , nil
118137 }
119138
120- // HTTPS mode
121139 serverName := addr .Addr ().String ()
122140 if len (s .config .Cert .Leaf .DNSNames ) > 0 {
123141 serverName = s .config .Cert .Leaf .DNSNames [0 ]
@@ -128,7 +146,7 @@ func (s *Server) createListener() (net.Listener, error) {
128146 ServerName : serverName ,
129147 MinVersion : tls .VersionTLS12 ,
130148 }
131- return tls .Listen ( "tcp" , addr . String ( ), cfg )
149+ return tls .NewListener ( ln , cfg ), nil
132150}
133151
134152func (s * Server ) listen () error {
@@ -246,27 +264,9 @@ func (s *Server) IsRunning() bool {
246264}
247265
248266func (s * Server ) ToForeground () {
249- err := s .Start ()
250- if err == nil {
251- return
252- }
253-
254- // On rapid pause/resume cycles with ephemeral ports, the previous listener
255- // close can lag briefly and return EADDRINUSE for the cached port.
256- // Retry a few times to preserve stable URL reuse semantics.
257- if s .config != nil && s .config .AddrPort .Port () == 0 && s .cachedPort != 0 && errors .Is (err , syscall .EADDRINUSE ) {
258- for i := 0 ; i < 10 ; i ++ {
259- time .Sleep (20 * time .Millisecond )
260- err = s .Start ()
261- if err == nil {
262- return
263- }
264- if ! errors .Is (err , syscall .EADDRINUSE ) {
265- break
266- }
267- }
267+ if err := s .Start (); err != nil {
268+ s .logger .Error ("server start failed during foreground transition" , zap .Error (err ))
268269 }
269- s .logger .Error ("server start failed during foreground transition" , zap .Error (err ))
270270}
271271
272272func (s * Server ) ToBackground () {
0 commit comments