fix repeated initialization of outgoingPathManager in Conn.AddPath (#5280)

In case of concurrent calls, this may still be called multiple times.

Co-authored-by: Marco Munizaga <git@marcopolo.io>
This commit is contained in:
Marten Seemann
2025-08-12 15:59:39 +02:00
parent c7cf12703d
commit 7e636553d6
2 changed files with 21 additions and 8 deletions

View File

@@ -2645,16 +2645,26 @@ func (c *Conn) LocalAddr() net.Addr { return c.conn.LocalAddr() }
// RemoteAddr returns the remote address of the QUIC connection.
func (c *Conn) RemoteAddr() net.Addr { return c.conn.RemoteAddr() }
// getPathManager lazily initializes the Conn's pathManagerOutgoing.
// May create multiple pathManagerOutgoing objects if called concurrently.
func (c *Conn) getPathManager() *pathManagerOutgoing {
c.pathManagerOutgoing.CompareAndSwap(nil,
func() *pathManagerOutgoing { // this function is only called if a swap is performed
return newPathManagerOutgoing(
c.connIDManager.GetConnIDForPath,
c.connIDManager.RetireConnIDForPath,
c.scheduleSending,
)
}(),
old := c.pathManagerOutgoing.Load()
if old != nil {
// Path manager is already initialized
return old
}
// Initialize the path manager
new := newPathManagerOutgoing(
c.connIDManager.GetConnIDForPath,
c.connIDManager.RetireConnIDForPath,
c.scheduleSending,
)
if c.pathManagerOutgoing.CompareAndSwap(old, new) {
return new
}
// Swap failed. A concurrent writer wrote first, use their value.
return c.pathManagerOutgoing.Load()
}

View File

@@ -128,6 +128,9 @@ type pathManagerOutgoing struct {
pathToSwitchTo *pathOutgoing
}
// newPathManagerOutgoing creates a new pathManagerOutgoing object. This
// function must be side-effect free as it may be called multiple times for a
// single connection.
func newPathManagerOutgoing(
getConnID func(pathID) (_ protocol.ConnectionID, ok bool),
retireConnID func(pathID),