From 847de9ccc31c468943cc89339e5e15666c602353 Mon Sep 17 00:00:00 2001 From: Gaylor Bosson Date: Fri, 3 May 2019 15:11:37 +0200 Subject: [PATCH] Drop connection if an unknown error occurs This fixes a potential infinite loop when an unknown error occurs and will happen every time the connection is handled. This was causing an infinite loop in some situation. Fixes dedis/cothority#1851 --- network/router.go | 6 ++++++ network/router_test.go | 45 ++++++++++++++++++++++++++++++++++++++++++ network/tcp.go | 2 ++ 3 files changed, 53 insertions(+) diff --git a/network/router.go b/network/router.go index 301c0216..f00e55ab 100644 --- a/network/router.go +++ b/network/router.go @@ -334,6 +334,12 @@ func (r *Router) handleConn(remote *ServerIdentity, c Conn) { r.triggerConnectionErrorHandlers(remote) return } + if err == ErrUnknown { + // The error might not be recoverable so the connection is dropped + log.Lvlf5("%v drops %v connection: unknown", r.ServerIdentity, remote) + r.triggerConnectionErrorHandlers(remote) + return + } // Temporary error, continue. log.Lvl3(r.ServerIdentity, "Error with connection", address, "=>", err) continue diff --git a/network/router_test.go b/network/router_test.go index 5a2f3066..cddcce70 100644 --- a/network/router_test.go +++ b/network/router_test.go @@ -560,3 +560,48 @@ func waitTimeout(timeout time.Duration, repeat int, } } + +type testConn struct{} + +func (c *testConn) Receive() (*Envelope, error) { + return nil, ErrUnknown +} + +func (c *testConn) Close() error { + return nil +} + +func (c *testConn) Local() Address { + return "" +} + +func (c *testConn) Remote() Address { + return "" +} + +func (c *testConn) Rx() uint64 { + return 0 +} + +func (c *testConn) Tx() uint64 { + return 0 +} + +func (c *testConn) Send(msg Message) (uint64, error) { + return 0, nil +} + +func (c *testConn) Type() ConnType { + return "testConn" +} + +// This test insures that an unknown error cannot end up as an infinite loop +// when handling a connection +func TestRouterHandleUnknownError(t *testing.T) { + router, err := NewTestRouterTCP(0) + require.NoError(t, err) + + router.wg.Add(1) + // The test will leak 1 goroutine if the connection is not dropped + go router.handleConn(router.ServerIdentity, &testConn{}) +} diff --git a/network/tcp.go b/network/tcp.go index 96d840e4..fc00661e 100644 --- a/network/tcp.go +++ b/network/tcp.go @@ -266,6 +266,8 @@ func handleError(err error) error { if netErr.Timeout() { return ErrTimeout } + + log.Errorf("Unknown error caught: %s", err.Error()) return ErrUnknown }