Skip to content

Commit

Permalink
lib/protocol: Ensure starting & closing a connection are exclusive (f…
Browse files Browse the repository at this point in the history
…ixes syncthing#9102) (syncthing#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.
  • Loading branch information
calmh authored Sep 12, 2023
1 parent caedb19 commit f47de83
Showing 1 changed file with 5 additions and 0 deletions.
5 changes: 5 additions & 0 deletions lib/protocol/protocol.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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 {
Expand Down

0 comments on commit f47de83

Please sign in to comment.