From 70c821348920535845de489a6b759b32df45419f Mon Sep 17 00:00:00 2001 From: sukun Date: Sat, 17 Feb 2024 09:10:00 +0530 Subject: [PATCH 1/2] server: fix deadlock when closing concurrently with transport --- server.go | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/server.go b/server.go index a87a3647f33..b3c85543662 100644 --- a/server.go +++ b/server.go @@ -98,7 +98,7 @@ type baseServer struct { protocol.Version, ) quicConn - closeOnce sync.Once + closeMx sync.Mutex errorChan chan struct{} // is closed when the server is closed closeErr error running chan struct{} // closed as soon as run() returns @@ -338,15 +338,19 @@ func (s *baseServer) Close() error { } func (s *baseServer) close(e error, notifyOnClose bool) { - s.closeOnce.Do(func() { - s.closeErr = e - close(s.errorChan) + s.closeMx.Lock() + if s.closeErr != nil { + s.closeMx.Unlock() + return + } + s.closeErr = e + close(s.errorChan) + <-s.running + s.closeMx.Unlock() - <-s.running - if notifyOnClose { - s.onClose() - } - }) + if notifyOnClose { + s.onClose() + } } // Addr returns the server's network address From 121b82c836008f0b984dc40d0e6903f07c473294 Mon Sep 17 00:00:00 2001 From: sukun Date: Sun, 3 Mar 2024 13:56:30 +0530 Subject: [PATCH 2/2] add test for checking no deadlock --- transport_test.go | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/transport_test.go b/transport_test.go index 4e89dcfbb8a..aeeb1153c98 100644 --- a/transport_test.go +++ b/transport_test.go @@ -122,6 +122,27 @@ var _ = Describe("Transport", func() { tr.Close() }) + It("closes transport concurrently with listener", func() { + // try 10 times to trigger race conditions + for i := 0; i < 10; i++ { + packetChan := make(chan packetToRead) + tr := &Transport{Conn: newMockPacketConn(packetChan)} + ln, err := tr.Listen(&tls.Config{}, nil) + Expect(err).ToNot(HaveOccurred()) + ch := make(chan bool) + // Close transport and listener concurrently. + go func() { + ch <- true + Expect(ln.Close()).To(Succeed()) + ch <- true + }() + <-ch + close(packetChan) + Expect(tr.Close()).To(Succeed()) + <-ch + } + }) + It("drops unparseable QUIC packets", func() { addr := &net.UDPAddr{IP: net.IPv4(9, 8, 7, 6), Port: 1234} packetChan := make(chan packetToRead)