diff --git a/muxer.go b/muxer.go index b9df2c5..3dec693 100644 --- a/muxer.go +++ b/muxer.go @@ -24,6 +24,7 @@ var NoOpHandler = func(s Stream) { s.Close() } // Conn is a stream-multiplexing connection to a remote peer. type Conn interface { + // Close closes the stream muxer and the the underlying net.Conn. io.Closer // IsClosed returns whether a connection is fully closed, so it can diff --git a/test/ttest.go b/test/ttest.go index 39f1c78..07ffc54 100644 --- a/test/ttest.go +++ b/test/ttest.go @@ -11,6 +11,7 @@ import ( "reflect" "runtime" "runtime/debug" + "strings" "sync" "testing" "time" @@ -417,6 +418,30 @@ func SubtestStreamReset(t *testing.T, tr smux.Transport) { <-done } +// check that Close also closes the underlying net.Conn +func SubtestWriteAfterClose(t *testing.T, tr smux.Transport) { + a, b := tcpPipe(t) + + muxa, err := tr.NewConn(a, true) + checkErr(t, err) + + muxb, err := tr.NewConn(b, false) + checkErr(t, err) + + err = muxa.Close() + checkErr(t, err) + err = muxb.Close() + checkErr(t, err) + + // make sure the underlying net.Conn was closed + if _, err := a.Write([]byte("foobar")); err == nil || !strings.Contains(err.Error(), "use of closed network connection") { + t.Fatal("write should have failed") + } + if _, err := b.Write([]byte("foobar")); err == nil || !strings.Contains(err.Error(), "use of closed network connection") { + t.Fatal("write should have failed") + } +} + func SubtestStress1Conn1Stream1Msg(t *testing.T, tr smux.Transport) { SubtestStress(t, Options{ tr: tr, @@ -487,6 +512,7 @@ func SubtestAll(t *testing.T, tr smux.Transport) { tests := []TransportTest{ SubtestSimpleWrite, + SubtestWriteAfterClose, SubtestStress1Conn1Stream1Msg, SubtestStress1Conn1Stream100Msg, SubtestStress1Conn100Stream100Msg,