revamp error handling on tcp connection receive loop

- treat crypto decoding errors as errors instead of warnings
- introduce helper for handling protocol messages
- put conn.Shutdown in one place
This commit is contained in:
Matthias Radestock committed 2015-01-22 16:21:48 +00:00
1 parent 6253be6ecf
commit 3baa3c09a4
1 file changed
+63 -64
+63 -64
View File
@@ -534,80 +534,79 @@ func (conn *LocalConnection) receiveTCP(decoder *gob.Decoder) {
var msg []byte
conn.extendReadDeadline()
if err = decoder.Decode(&msg); err != nil {
conn.Shutdown(err)
return
break
}
msg, err = receiver.Decode(msg)
if err != nil {
checkWarn(err)
// remote peer may be using wrong password. Or there could
// be some sort of injection attack going on. Just ignore
// the traffic rather than shutting down.
continue
break
}
if len(msg) < 1 {
conn.log("ignoring blank msg")
continue
}
payload := msg[1:]
switch ProtocolTag(msg[0]) {
case ProtocolConnectionEstablished:
// We sent fast heartbeats to the remote peer, which has
// now received at least one of them and told us via this
// message. We can now consider the connection as
// established from our end.
conn.SetEstablished()
case ProtocolStartFragmentationTest:
conn.Forward(false, &ForwardedFrame{
srcPeer: conn.local,
dstPeer: conn.remote,
frame: FragTest},
nil)
case ProtocolFragmentationReceived:
conn.setStackFrag(true)
case ProtocolNonce:
if usingPassword {
conn.Decryptor.ReceiveNonce(payload)
} else {
conn.log("ignoring unexpected nonce on unencrypted connection")
}
case ProtocolFetchAll:
// There are exactly two messages that relate to topology
// updates.
//
// 1. FetchAll. This carries no payload. The receiver
// responds with the entire topology model as the receiver
// has it.
//
// 2. Update. This carries a topology payload. The
// receiver merges it with its own topology model. If the
// payload is a subset of the receiver's topology, no
// further action is taken. Otherwise, the receiver sends
// out to all its connections an "improved" update.
conn.SendProtocolMsg(ProtocolMsg{ProtocolUpdate, conn.Router.Peers.EncodeAllPeers()})
case ProtocolUpdate:
newUpdate, err := conn.Router.Peers.ApplyUpdate(payload)
if _, ok := err.(UnknownPeersError); err != nil && ok {
// That update contained a peer we didn't know about;
// request full update
conn.SendProtocolMsg(ProtocolMsg{ProtocolFetchAll, nil})
continue
}
if err != nil {
conn.Shutdown(err)
return
}
if len(newUpdate) != 0 {
conn.Router.ConnectionMaker.Refresh()
conn.Router.Routes.Recalculate()
conn.Router.Ourself.SendProtocolMsg(ProtocolMsg{ProtocolUpdate, newUpdate})
}
case ProtocolPMTUVerified:
conn.verifyPMTU <- int(binary.BigEndian.Uint16(payload))
default:
conn.log("received unknown msg:\n", msg)
if err = conn.handleProtocolMsg(ProtocolTag(msg[0]), msg[1:]); err != nil {
break
}
}
conn.Shutdown(err)
}
func (conn *LocalConnection) handleProtocolMsg(tag ProtocolTag, payload []byte) error {
switch tag {
case ProtocolConnectionEstablished:
// We sent fast heartbeats to the remote peer, which has now
// received at least one of them and told us via this message.
// We can now consider the connection as established from our
// end.
conn.SetEstablished()
case ProtocolStartFragmentationTest:
conn.Forward(false, &ForwardedFrame{
srcPeer: conn.local,
dstPeer: conn.remote,
frame: FragTest},
nil)
case ProtocolFragmentationReceived:
conn.setStackFrag(true)
case ProtocolNonce:
if conn.SessionKey == nil {
return fmt.Errorf("unexpected nonce on unencrypted connection")
}
conn.Decryptor.ReceiveNonce(payload)
case ProtocolFetchAll:
// There are exactly two messages that relate to topology
// updates.
//
// 1. FetchAll. This carries no payload. The receiver responds
// with the entire topology model as the receiver has it.
//
// 2. Update. This carries a topology payload. The receiver
// merges it with its own topology model. If the payload is a
// subset of the receiver's topology, no further action is
// taken. Otherwise, the receiver sends out to all its
// connections an "improved" update.
conn.SendProtocolMsg(ProtocolMsg{ProtocolUpdate, conn.Router.Peers.EncodeAllPeers()})
case ProtocolUpdate:
newUpdate, err := conn.Router.Peers.ApplyUpdate(payload)
if _, ok := err.(UnknownPeersError); err != nil && ok {
// That update contained a peer we didn't know about;
// request full update
conn.SendProtocolMsg(ProtocolMsg{ProtocolFetchAll, nil})
break
}
if err != nil {
return err
}
if len(newUpdate) != 0 {
conn.Router.ConnectionMaker.Refresh()
conn.Router.Routes.Recalculate()
conn.Router.Ourself.SendProtocolMsg(ProtocolMsg{ProtocolUpdate, newUpdate})
}
case ProtocolPMTUVerified:
conn.verifyPMTU <- int(binary.BigEndian.Uint16(payload))
default:
conn.log("ignoring unknown protocol tag:", tag)
}
return nil
}
func (conn *LocalConnection) extendReadDeadline() {