10 "github.com/anacrolix/log"
11 qt "github.com/frankban/quicktest"
14 // Show that multiple connections from the same local TCP port to the same remote port will fail.
15 func TestTcpPortReuseIsABadIdea(t *testing.T) {
16 remote, err := net.Listen("tcp", "localhost:0")
18 c.Assert(err, qt.IsNil)
20 dialer := net.Dialer{}
21 // Show that we can't duplicate an existing connection even with various socket options.
22 dialer.Control = func(network, address string, c syscall.RawConn) (err error) {
23 return c.Control(func(fd uintptr) {
24 err = setReusePortSockOpts(fd)
27 // Tie up a local port to the remote.
28 first, err := dialer.Dial("tcp", remote.Addr().String())
29 c.Assert(err, qt.IsNil)
31 // Show that dialling the remote with the same local port fails.
32 dialer.LocalAddr = first.LocalAddr()
33 _, err = dialer.Dial("tcp", remote.Addr().String())
34 c.Assert(err, qt.IsNotNil)
35 // Show that not fixing the local port again allows connections to succeed.
36 dialer.LocalAddr = nil
37 second, err := dialer.Dial("tcp", remote.Addr().String())
38 c.Assert(err, qt.IsNil)
42 // Show that multiple connections from the same local utp socket to the same remote port will
43 // succeed. This is necessary for ut_holepunch to work.
44 func TestUtpLocalPortIsReusable(t *testing.T) {
47 remote, err := NewUtpSocket(network, "localhost:0", nil, log.Default)
48 c.Assert(err, qt.IsNil)
50 var remoteAccepts int32
51 doneAccepting := make(chan struct{})
53 defer close(doneAccepting)
55 c, err := remote.Accept()
57 if atomic.LoadInt32(&remoteAccepts) != 2 {
58 t.Logf("error accepting on remote: %v", err)
62 // This is not a leak, bugger off.
64 atomic.AddInt32(&remoteAccepts, 1)
67 local, err := NewUtpSocket(network, "localhost:0", nil, log.Default)
68 c.Assert(err, qt.IsNil)
70 first, err := local.DialContext(context.Background(), network, remote.Addr().String())
71 c.Assert(err, qt.IsNil)
73 second, err := local.DialContext(context.Background(), network, remote.Addr().String())
74 c.Assert(err, qt.IsNil)
78 c.Assert(atomic.LoadInt32(&remoteAccepts), qt.Equals, int32(2))