peer: improves disconnect handling

This commit attempts to resolve some potential deadlock
scenarios during a peer disconnect.

Currently, writeMessage returns a nil error when disconnecting.
This should have minimal impact on the writeHanlder, as the
subsequent loop selects on the quit chan, and will cause it to
exit. However, if this happens when sending the init message,
the Start() method will attempt to proceed even though the peer
has been disconnected.

In addition, this commit changes the behavior of synchronous
write errors, by using a non-blocking select. Though unlikely,
this prevents any cases where multiple errors are returned, and
the errors are not being pulled from the other side of the errChan.
This removes any naked sends on the errChan from stalling the peer's
shutdown.
This commit is contained in:
Conner Fromknecht 2018-05-07 18:32:00 -07:00
parent 27ca61aedf
commit 0691b21a30
No known key found for this signature in database
GPG Key ID: 39DE78FBE6ACB0EF

13
peer.go

@ -30,6 +30,9 @@ import (
var (
numNodes int32
// ErrPeerExiting signals that the peer received a disconnect request.
ErrPeerExiting = errors.Errorf("peer exiting")
)
const (
@ -1105,7 +1108,7 @@ func (p *peer) logWireMessage(msg lnwire.Message, read bool) {
func (p *peer) writeMessage(msg lnwire.Message) error {
// Simply exit if we're shutting down.
if atomic.LoadInt32(&p.disconnect) != 0 {
return nil
return ErrPeerExiting
}
// TODO(roasbeef): add message summaries
@ -1154,8 +1157,8 @@ out:
atomic.StoreInt64(&p.pingLastSend, now)
}
// Write out the message to the socket, closing the
// 'sentChan' if it's non-nil, The 'sentChan' allows
// Write out the message to the socket, responding with
// error if `errChan` is non-nil. The `errChan` allows
// callers to optionally synchronize sends with the
// writeHandler.
err := p.writeMessage(outMsg.msg)
@ -1169,7 +1172,7 @@ out:
}
case <-p.quit:
exitErr = errors.Errorf("peer exiting")
exitErr = ErrPeerExiting
break out
}
}
@ -1263,7 +1266,7 @@ func (p *peer) queueMsg(msg lnwire.Message, errChan chan error) {
case <-p.quit:
peerLog.Tracef("Peer shutting down, could not enqueue msg.")
if errChan != nil {
errChan <- fmt.Errorf("peer shutting down")
errChan <- ErrPeerExiting
}
}
}