mirror of
https://github.com/octoleo/syncthing.git
synced 2024-11-08 22:31:04 +00:00
This commit is contained in:
parent
51f65bd23a
commit
c87411851d
@ -171,11 +171,12 @@ type rawConnection struct {
|
||||
nextID int32
|
||||
nextIDMut sync.Mutex
|
||||
|
||||
outbox chan asyncMessage
|
||||
sendClose chan asyncMessage
|
||||
closed chan struct{}
|
||||
once sync.Once
|
||||
compression Compression
|
||||
outbox chan asyncMessage
|
||||
closed chan struct{}
|
||||
closeOnce sync.Once
|
||||
sendCloseOnce sync.Once
|
||||
writerExited chan struct{}
|
||||
compression Compression
|
||||
}
|
||||
|
||||
type asyncResult struct {
|
||||
@ -216,7 +217,6 @@ func NewConnection(deviceID DeviceID, reader io.Reader, writer io.Writer, receiv
|
||||
cw: cw,
|
||||
awaiting: make(map[int32]chan asyncResult),
|
||||
outbox: make(chan asyncMessage),
|
||||
sendClose: make(chan asyncMessage),
|
||||
closed: make(chan struct{}),
|
||||
compression: compress,
|
||||
}
|
||||
@ -643,11 +643,6 @@ func (c *rawConnection) writerLoop() {
|
||||
return
|
||||
}
|
||||
|
||||
case m := <-c.sendClose:
|
||||
c.writeMessage(m)
|
||||
close(m.done)
|
||||
return // No message must be sent after the Close message.
|
||||
|
||||
case <-c.closed:
|
||||
return
|
||||
}
|
||||
@ -813,41 +808,38 @@ func (c *rawConnection) shouldCompressMessage(msg message) bool {
|
||||
// BEP message is sent before terminating the actual connection. The error
|
||||
// argument specifies the reason for closing the connection.
|
||||
func (c *rawConnection) Close(err error) {
|
||||
c.once.Do(func() {
|
||||
c.sendCloseOnce.Do(func() {
|
||||
done := make(chan struct{})
|
||||
c.sendClose <- asyncMessage{&Close{err.Error()}, done}
|
||||
<-done
|
||||
|
||||
// No more sends are necessary, therefore closing the underlying
|
||||
// connection can happen at the same time as the internal cleanup.
|
||||
// And this prevents a potential deadlock due to calling c.receiver.Closed
|
||||
go c.commonClose(err)
|
||||
c.send(&Close{err.Error()}, done)
|
||||
select {
|
||||
case <-done:
|
||||
case <-c.closed:
|
||||
}
|
||||
})
|
||||
|
||||
// No more sends are necessary, therefore further steps to close the
|
||||
// connection outside of this package can proceed immediately.
|
||||
// And this prevents a potential deadlock due to calling c.receiver.Closed
|
||||
go c.internalClose(err)
|
||||
}
|
||||
|
||||
// internalClose is called if there is an unexpected error during normal operation.
|
||||
func (c *rawConnection) internalClose(err error) {
|
||||
c.once.Do(func() {
|
||||
c.commonClose(err)
|
||||
})
|
||||
}
|
||||
c.closeOnce.Do(func() {
|
||||
l.Debugln("close due to", err)
|
||||
close(c.closed)
|
||||
|
||||
// commonClose is a utility function that must only be called from within
|
||||
// rawConnection.once.Do (i.e. in Close and close).
|
||||
func (c *rawConnection) commonClose(err error) {
|
||||
l.Debugln("close due to", err)
|
||||
close(c.closed)
|
||||
|
||||
c.awaitingMut.Lock()
|
||||
for i, ch := range c.awaiting {
|
||||
if ch != nil {
|
||||
close(ch)
|
||||
delete(c.awaiting, i)
|
||||
c.awaitingMut.Lock()
|
||||
for i, ch := range c.awaiting {
|
||||
if ch != nil {
|
||||
close(ch)
|
||||
delete(c.awaiting, i)
|
||||
}
|
||||
}
|
||||
}
|
||||
c.awaitingMut.Unlock()
|
||||
c.awaitingMut.Unlock()
|
||||
|
||||
c.receiver.Closed(c, err)
|
||||
c.receiver.Closed(c, err)
|
||||
})
|
||||
}
|
||||
|
||||
// The pingSender makes sure that we've sent a message within the last
|
||||
|
Loading…
Reference in New Issue
Block a user