From 283544c7f3ada24378fd6e0ac2f82cd927bc95e6 Mon Sep 17 00:00:00 2001 From: Emmanuel Odeke Date: Tue, 14 Nov 2017 21:49:08 -0700 Subject: [PATCH] p2p: use fake net.Pipe since only >=Go1.10 implements SetDeadline Fixes https://github.com/tendermint/tendermint/issues/851 Go1.9 and below's net.Pipe did not implement the SetDeadline method so after commit https://github.com/golang/go/commit/e2dd8ca946be884bb877e074a21727f1a685a706 this problem was exposed since now we check for errors. To counter this problem, implement a simple composition for net.Conn that always returns nil on SetDeadline instead of tripping out. Added build tags so that anyone using go1.10 when it is released will be able to automatically use net.Pipe's net.Conns --- p2p/conn_go110.go | 15 +++++++++++++++ p2p/connection_test.go | 12 ++++++------ p2p/switch.go | 26 +++++++++++++++++++++++++- p2p/switch_test.go | 4 ++-- 4 files changed, 48 insertions(+), 9 deletions(-) create mode 100644 p2p/conn_go110.go diff --git a/p2p/conn_go110.go b/p2p/conn_go110.go new file mode 100644 index 000000000..2fca7c3df --- /dev/null +++ b/p2p/conn_go110.go @@ -0,0 +1,15 @@ +// +build go1.10 + +package p2p + +// Go1.10 has a proper net.Conn implementation that +// has the SetDeadline method implemented as per +// https://github.com/golang/go/commit/e2dd8ca946be884bb877e074a21727f1a685a706 +// lest we run into problems like +// https://github.com/tendermint/tendermint/issues/851 + +import "net" + +func netPipe() (net.Conn, net.Conn) { + return net.Pipe() +} diff --git a/p2p/connection_test.go b/p2p/connection_test.go index 959992238..d74deabfa 100644 --- a/p2p/connection_test.go +++ b/p2p/connection_test.go @@ -31,7 +31,7 @@ func createMConnectionWithCallbacks(conn net.Conn, onReceive func(chID byte, msg func TestMConnectionSend(t *testing.T) { assert, require := assert.New(t), require.New(t) - server, client := net.Pipe() + server, client := netPipe() defer server.Close() defer client.Close() @@ -58,7 +58,7 @@ func TestMConnectionSend(t *testing.T) { func TestMConnectionReceive(t *testing.T) { assert, require := assert.New(t), require.New(t) - server, client := net.Pipe() + server, client := netPipe() defer server.Close() defer client.Close() @@ -96,7 +96,7 @@ func TestMConnectionReceive(t *testing.T) { func TestMConnectionStatus(t *testing.T) { assert, require := assert.New(t), require.New(t) - server, client := net.Pipe() + server, client := netPipe() defer server.Close() defer client.Close() @@ -113,7 +113,7 @@ func TestMConnectionStatus(t *testing.T) { func TestMConnectionStopsAndReturnsError(t *testing.T) { assert, require := assert.New(t), require.New(t) - server, client := net.Pipe() + server, client := netPipe() defer server.Close() defer client.Close() @@ -144,7 +144,7 @@ func TestMConnectionStopsAndReturnsError(t *testing.T) { } func newClientAndServerConnsForReadErrors(require *require.Assertions, chOnErr chan struct{}) (*MConnection, *MConnection) { - server, client := net.Pipe() + server, client := netPipe() onReceive := func(chID byte, msgBytes []byte) {} onError := func(r interface{}) {} @@ -275,7 +275,7 @@ func TestMConnectionReadErrorUnknownMsgType(t *testing.T) { func TestMConnectionTrySend(t *testing.T) { assert, require := assert.New(t), require.New(t) - server, client := net.Pipe() + server, client := netPipe() defer server.Close() defer client.Close() diff --git a/p2p/switch.go b/p2p/switch.go index 2012897af..5771cf364 100644 --- a/p2p/switch.go +++ b/p2p/switch.go @@ -515,7 +515,7 @@ var PanicOnAddPeerErr = false func Connect2Switches(switches []*Switch, i, j int) { switchI := switches[i] switchJ := switches[j] - c1, c2 := net.Pipe() + c1, c2 := netPipe() doneCh := make(chan struct{}) go func() { err := switchI.addPeerWithConnection(c1) @@ -593,3 +593,27 @@ func (sw *Switch) addPeerWithConnectionAndConfig(conn net.Conn, config *PeerConf return nil } + +// Only Go1.10 has a proper net.Conn implementation that +// has the SetDeadline method implemented as per +// https://github.com/golang/go/commit/e2dd8ca946be884bb877e074a21727f1a685a706 +// lest we run into problems like +// https://github.com/tendermint/tendermint/issues/851 +// so for go versions < Go1.10 use our custom net.Conn creator +// that doesn't return an `Unimplemented error` for net.Conn. +// Before https://github.com/tendermint/tendermint/commit/49faa79bdce5663894b3febbf4955fb1d172df04 +// we hadn't cared about errors from SetDeadline so swallow them up anyways. +type pipe struct { + net.Conn +} + +func (p *pipe) SetDeadline(t time.Time) error { + return nil +} + +func netPipe() (net.Conn, net.Conn) { + p1, p2 := net.Pipe() + return &pipe{p1}, &pipe{p2} +} + +var _ net.Conn = (*pipe)(nil) diff --git a/p2p/switch_test.go b/p2p/switch_test.go index b06e05868..1ea79efef 100644 --- a/p2p/switch_test.go +++ b/p2p/switch_test.go @@ -160,7 +160,7 @@ func TestConnAddrFilter(t *testing.T) { defer s1.Stop() defer s2.Stop() - c1, c2 := net.Pipe() + c1, c2 := netPipe() s1.SetAddrFilter(func(addr net.Addr) error { if addr.String() == c1.RemoteAddr().String() { @@ -194,7 +194,7 @@ func TestConnPubKeyFilter(t *testing.T) { defer s1.Stop() defer s2.Stop() - c1, c2 := net.Pipe() + c1, c2 := netPipe() // set pubkey filter s1.SetPubKeyFilter(func(pubkey crypto.PubKeyEd25519) error {