summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJakob Borg <jakob@kastelo.net>2023-09-12 14:48:15 +0200
committerGitHub <noreply@github.com>2023-09-12 14:48:15 +0200
commitf47de839141482b8689398504671c53fd9c4e2a9 (patch)
tree3cd72ba6fef005cd1e1de3a8480b03fccb1734c2
parentcaedb19307a5337f76a5abdf4c9747ba1a3faa5c (diff)
lib/protocol: Ensure starting & closing a connection are exclusive (fixes #9102) (#9103)v1.25.0-rc.1
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.
-rw-r--r--lib/protocol/protocol.go5
1 files changed, 5 insertions, 0 deletions
diff --git a/lib/protocol/protocol.go b/lib/protocol/protocol.go
index 8e5f653d9..a22c157bb 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 {