@@ -53,7 +53,9 @@ type addrsManager struct {
5353 addrsUpdatedChan chan struct {}
5454
5555 // triggerAddrsUpdateChan is used to trigger an addresses update.
56- triggerAddrsUpdateChan chan struct {}
56+ triggerAddrsUpdateChan chan chan struct {}
57+ // started is used to check whether the addrsManager has started.
58+ started atomic.Bool
5759 // triggerReachabilityUpdate is notified when reachable addrs are updated.
5860 triggerReachabilityUpdate chan struct {}
5961
@@ -87,7 +89,7 @@ func newAddrsManager(
8789 observedAddrsManager : observedAddrsManager ,
8890 natManager : natmgr ,
8991 addrsFactory : addrsFactory ,
90- triggerAddrsUpdateChan : make (chan struct {}, 1 ),
92+ triggerAddrsUpdateChan : make (chan chan struct {}, 1 ),
9193 triggerReachabilityUpdate : make (chan struct {}, 1 ),
9294 addrsUpdatedChan : addrsUpdatedChan ,
9395 interfaceAddrs : & interfaceAddrsCache {},
@@ -115,7 +117,6 @@ func (a *addrsManager) Start() error {
115117 return fmt .Errorf ("error starting addrs reachability tracker: %s" , err )
116118 }
117119 }
118-
119120 return a .startBackgroundWorker ()
120121}
121122
@@ -140,16 +141,24 @@ func (a *addrsManager) NetNotifee() network.Notifiee {
140141 // Updating addrs in sync provides the nice property that
141142 // host.Addrs() just after host.Network().Listen(x) will return x
142143 return & network.NotifyBundle {
143- ListenF : func (network.Network , ma.Multiaddr ) { a .triggerAddrsUpdate () },
144- ListenCloseF : func (network.Network , ma.Multiaddr ) { a .triggerAddrsUpdate () },
144+ ListenF : func (network.Network , ma.Multiaddr ) { a .updateAddrsSync () },
145+ ListenCloseF : func (network.Network , ma.Multiaddr ) { a .updateAddrsSync () },
145146 }
146147}
147148
148- func (a * addrsManager ) triggerAddrsUpdate () {
149- a .updateAddrs (false , nil )
149+ func (a * addrsManager ) updateAddrsSync () {
150+ // This prevents a deadlock where addrs updates before starting the manager are ignored
151+ if ! a .started .Load () {
152+ return
153+ }
154+ ch := make (chan struct {})
150155 select {
151- case a .triggerAddrsUpdateChan <- struct {}{}:
152- default :
156+ case a .triggerAddrsUpdateChan <- ch :
157+ select {
158+ case <- ch :
159+ case <- a .ctx .Done ():
160+ }
161+ case <- a .ctx .Done ():
153162 }
154163}
155164
@@ -177,7 +186,7 @@ func (a *addrsManager) startBackgroundWorker() error {
177186 }
178187 err2 := autonatReachabilitySub .Close ()
179188 if err2 != nil {
180- err2 = fmt .Errorf ("error closing autonat reachability: %w" , err1 )
189+ err2 = fmt .Errorf ("error closing autonat reachability: %w" , err2 )
181190 }
182191 err = fmt .Errorf ("error subscribing to autonat reachability: %s" , err )
183192 return errors .Join (err , err1 , err2 )
@@ -200,9 +209,11 @@ func (a *addrsManager) startBackgroundWorker() error {
200209 }
201210 default :
202211 }
212+ // this ensures that listens concurrent with Start are reflected correctly after Start exits.
213+ a .started .Store (true )
203214 // update addresses before starting the worker loop. This ensures that any address updates
204215 // before calling addrsManager.Start are correctly reported after Start returns.
205- a .updateAddrs (true , relayAddrs )
216+ a .updateAddrs (relayAddrs )
206217
207218 a .wg .Add (1 )
208219 go a .background (autoRelayAddrsSub , autonatReachabilitySub , emitter , relayAddrs )
@@ -227,13 +238,18 @@ func (a *addrsManager) background(autoRelayAddrsSub, autonatReachabilitySub even
227238 ticker := time .NewTicker (addrChangeTickrInterval )
228239 defer ticker .Stop ()
229240 var previousAddrs hostAddrs
241+ var notifCh chan struct {}
230242 for {
231- currAddrs := a .updateAddrs (true , relayAddrs )
243+ currAddrs := a .updateAddrs (relayAddrs )
244+ if notifCh != nil {
245+ close (notifCh )
246+ notifCh = nil
247+ }
232248 a .notifyAddrsChanged (emitter , previousAddrs , currAddrs )
233249 previousAddrs = currAddrs
234250 select {
235251 case <- ticker .C :
236- case <- a .triggerAddrsUpdateChan :
252+ case notifCh = <- a .triggerAddrsUpdateChan :
237253 case <- a .triggerReachabilityUpdate :
238254 case e := <- autoRelayAddrsSub .Out ():
239255 if evt , ok := e .(event.EvtAutoRelayAddrsUpdated ); ok {
@@ -250,26 +266,18 @@ func (a *addrsManager) background(autoRelayAddrsSub, autonatReachabilitySub even
250266}
251267
252268// updateAddrs updates the addresses of the host and returns the new updated
253- // addrs
254- func (a * addrsManager ) updateAddrs (updateRelayAddrs bool , relayAddrs []ma.Multiaddr ) hostAddrs {
255- // Must lock while doing both recompute and update as this method is called from
256- // multiple goroutines.
257- a .addrsMx .Lock ()
258- defer a .addrsMx .Unlock ()
259-
269+ // addrs. This must only be called from the background goroutine or from the Start method otherwise
270+ // we may end up with stale addrs.
271+ func (a * addrsManager ) updateAddrs (relayAddrs []ma.Multiaddr ) hostAddrs {
260272 localAddrs := a .getLocalAddrs ()
261273 var currReachableAddrs , currUnreachableAddrs , currUnknownAddrs []ma.Multiaddr
262274 if a .addrsReachabilityTracker != nil {
263275 currReachableAddrs , currUnreachableAddrs , currUnknownAddrs = a .getConfirmedAddrs (localAddrs )
264276 }
265- if ! updateRelayAddrs {
266- relayAddrs = a .currentAddrs .relayAddrs
267- } else {
268- // Copy the callers slice
269- relayAddrs = slices .Clone (relayAddrs )
270- }
277+ relayAddrs = slices .Clone (relayAddrs )
271278 currAddrs := a .getAddrs (slices .Clone (localAddrs ), relayAddrs )
272279
280+ a .addrsMx .Lock ()
273281 a .currentAddrs = hostAddrs {
274282 addrs : append (a .currentAddrs .addrs [:0 ], currAddrs ... ),
275283 localAddrs : append (a .currentAddrs .localAddrs [:0 ], localAddrs ... ),
@@ -278,6 +286,7 @@ func (a *addrsManager) updateAddrs(updateRelayAddrs bool, relayAddrs []ma.Multia
278286 unknownAddrs : append (a .currentAddrs .unknownAddrs [:0 ], currUnknownAddrs ... ),
279287 relayAddrs : append (a .currentAddrs .relayAddrs [:0 ], relayAddrs ... ),
280288 }
289+ a .addrsMx .Unlock ()
281290
282291 return hostAddrs {
283292 localAddrs : localAddrs ,
@@ -315,7 +324,8 @@ func (a *addrsManager) notifyAddrsChanged(emitter event.Emitter, previous, curre
315324 if areAddrsDifferent (previous .reachableAddrs , current .reachableAddrs ) ||
316325 areAddrsDifferent (previous .unreachableAddrs , current .unreachableAddrs ) ||
317326 areAddrsDifferent (previous .unknownAddrs , current .unknownAddrs ) {
318- log .Debugf ("host reachable addrs updated: %s" , current .localAddrs )
327+ log .Debugf ("host reachable addrs updated: reachable: %s, unreachable: %s, unknown: %s" ,
328+ current .reachableAddrs , current .unreachableAddrs , current .unknownAddrs )
319329 if err := emitter .Emit (event.EvtHostReachableAddrsChanged {
320330 Reachable : slices .Clone (current .reachableAddrs ),
321331 Unreachable : slices .Clone (current .unreachableAddrs ),
0 commit comments