From f47de839141482b8689398504671c53fd9c4e2a9 Mon Sep 17 00:00:00 2001 From: Jakob Borg Date: Tue, 12 Sep 2023 14:48:15 +0200 Subject: [PATCH] lib/protocol: Ensure starting & closing a connection are exclusive (fixes #9102) (#9103) In principle a connection can close while it's in progress with starting, and then it's undefined if we wait for goroutines to exit etc. With this change, we will wait for start to complete before starting to stop everything. --- lib/protocol/protocol.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/protocol/protocol.go b/lib/protocol/protocol.go index 8e5f653d9f8..a22c157bb59 100644 --- a/lib/protocol/protocol.go +++ b/lib/protocol/protocol.go @@ -208,6 +208,7 @@ type rawConnection struct { closeOnce sync.Once sendCloseOnce sync.Once compression Compression + startStopMut sync.Mutex // start and stop must be serialized loopWG sync.WaitGroup // Need to ensure no leftover routines in testing } @@ -295,6 +296,8 @@ func newRawConnection(deviceID DeviceID, reader io.Reader, writer io.Writer, clo // Start creates the goroutines for sending and receiving of messages. It must // be called exactly once after creating a connection. func (c *rawConnection) Start() { + c.startStopMut.Lock() + defer c.startStopMut.Unlock() c.loopWG.Add(5) go func() { c.readerLoop() @@ -963,6 +966,8 @@ func (c *rawConnection) Close(err error) { // internalClose is called if there is an unexpected error during normal operation. func (c *rawConnection) internalClose(err error) { + c.startStopMut.Lock() + defer c.startStopMut.Unlock() c.closeOnce.Do(func() { l.Debugf("close connection to %s at %s due to %v", c.deviceID.Short(), c.ConnectionInfo, err) if cerr := c.closer.Close(); cerr != nil {