diff --git a/lib/protocol/protocol.go b/lib/protocol/protocol.go index 21d1127d..e283db47 100644 --- a/lib/protocol/protocol.go +++ b/lib/protocol/protocol.go @@ -182,11 +182,12 @@ type rawConnection struct { nextID int32 nextIDMut sync.Mutex - outbox chan asyncMessage - closed chan struct{} - closeOnce sync.Once - sendCloseOnce sync.Once - compression Compression + sentClusterConfig chan struct{} + outbox chan asyncMessage + closed chan struct{} + closeOnce sync.Once + sendCloseOnce sync.Once + compression Compression } type asyncResult struct { @@ -220,15 +221,16 @@ func NewConnection(deviceID DeviceID, reader io.Reader, writer io.Writer, receiv cw := &countingWriter{Writer: writer} c := rawConnection{ - id: deviceID, - name: name, - receiver: nativeModel{receiver}, - cr: cr, - cw: cw, - awaiting: make(map[int32]chan asyncResult), - outbox: make(chan asyncMessage), - closed: make(chan struct{}), - compression: compress, + id: deviceID, + name: name, + receiver: nativeModel{receiver}, + cr: cr, + cw: cw, + awaiting: make(map[int32]chan asyncResult), + sentClusterConfig: make(chan struct{}), + outbox: make(chan asyncMessage), + closed: make(chan struct{}), + compression: compress, } return wireFormatConnection{&c} @@ -322,9 +324,20 @@ func (c *rawConnection) Request(folder string, name string, offset int64, size i return res.val, res.err } -// ClusterConfig send the cluster configuration message to the peer and returns any error +// ClusterConfig sends the cluster configuration message to the peer. +// It must be called just once (as per BEP). func (c *rawConnection) ClusterConfig(config ClusterConfig) { - c.send(&config, nil) + select { + case <-c.sentClusterConfig: + return + case <-c.closed: + return + default: + } + if err := c.writeMessage(asyncMessage{&config, nil}); err != nil { + c.internalClose(err) + } + close(c.sentClusterConfig) } func (c *rawConnection) Closed() bool { @@ -628,13 +641,20 @@ func (c *rawConnection) handleResponse(resp Response) { } func (c *rawConnection) send(msg message, done chan struct{}) bool { + defer func() { + if done != nil { + close(done) + } + }() + select { + case <-c.sentClusterConfig: + case <-c.closed: + return false + } select { case c.outbox <- asyncMessage{msg, done}: return true case <-c.closed: - if done != nil { - close(done) - } return false } }