From 5b3f5eabb5c777910667a6d8297332d223a4af8c Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Thu, 28 Sep 2023 10:58:15 -0700 Subject: [PATCH] control/controlclient: fix leaked http2 goroutines on shutdown If a noise dial was happening concurrently with shutdown, the http2 goroutines could leak. Updates tailscale/corp#14950 Updates tailscale/corp#14515 Updates tailscale/corp#14139 Updates tailscale/corp#13175 Signed-off-by: Brad Fitzpatrick --- control/controlclient/noise.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/control/controlclient/noise.go b/control/controlclient/noise.go index a9dd20180..a5439062f 100644 --- a/control/controlclient/noise.go +++ b/control/controlclient/noise.go @@ -177,6 +177,7 @@ type NoiseClient struct { // mu only protects the following variables. mu sync.Mutex + closed bool last *noiseConn // or nil nextID int connPool map[int]*noiseConn // active connections not yet closed; see noiseConn.Close @@ -373,6 +374,7 @@ func (nc *NoiseClient) connClosed(id int) { // It is a no-op and returns nil if the connection is already closed. func (nc *NoiseClient) Close() error { nc.mu.Lock() + nc.closed = true conns := nc.connPool nc.connPool = nil nc.mu.Unlock() @@ -472,6 +474,10 @@ func (nc *NoiseClient) dial(ctx context.Context) (*noiseConn, error) { nc.mu.Lock() defer nc.mu.Unlock() + if nc.closed { + ncc.Close() + return nil, errors.New("noise client closed") + } mak.Set(&nc.connPool, ncc.id, ncc) nc.last = ncc return ncc, nil