]> Sergey Matveev's repositories - btrtrc.git/blob - reuse_test.go
Include PeerConn prefix for log messages
[btrtrc.git] / reuse_test.go
1 package torrent
2
3 import (
4         "context"
5         "errors"
6         "net"
7         "sync/atomic"
8         "syscall"
9         "testing"
10
11         "github.com/anacrolix/log"
12         qt "github.com/frankban/quicktest"
13 )
14
15 // Show that multiple connections from the same local TCP port to the same remote port will fail.
16 func TestTcpPortReuseIsABadIdea(t *testing.T) {
17         remote, err := net.Listen("tcp", "localhost:0")
18         c := qt.New(t)
19         c.Assert(err, qt.IsNil)
20         defer remote.Close()
21         dialer := net.Dialer{}
22         dialer.Control = func(network, address string, c syscall.RawConn) (err error) {
23                 return c.Control(func(fd uintptr) {
24                         err = setReusePortSockOpts(fd)
25                 })
26         }
27         first, err := dialer.Dial("tcp", remote.Addr().String())
28         c.Assert(err, qt.IsNil)
29         defer first.Close()
30         dialer.LocalAddr = first.LocalAddr()
31         _, err = dialer.Dial("tcp", remote.Addr().String())
32         c.Assert(errors.Is(err, syscall.EADDRINUSE), qt.IsTrue)
33 }
34
35 // Show that multiple connections from the same local utp socket to the same remote port will
36 // succeed. This is necessary for ut_holepunch to work.
37 func TestUtpLocalPortIsReusable(t *testing.T) {
38         const network = "udp"
39         c := qt.New(t)
40         remote, err := NewUtpSocket(network, "localhost:0", nil, log.Default)
41         c.Assert(err, qt.IsNil)
42         defer remote.Close()
43         var remoteAccepts int32
44         doneAccepting := make(chan struct{})
45         go func() {
46                 defer close(doneAccepting)
47                 for {
48                         c, err := remote.Accept()
49                         if err != nil {
50                                 if atomic.LoadInt32(&remoteAccepts) != 2 {
51                                         t.Logf("error accepting on remote: %v", err)
52                                 }
53                                 break
54                         }
55                         // This is not a leak, bugger off.
56                         defer c.Close()
57                         atomic.AddInt32(&remoteAccepts, 1)
58                 }
59         }()
60         local, err := NewUtpSocket(network, "localhost:0", nil, log.Default)
61         c.Assert(err, qt.IsNil)
62         defer local.Close()
63         first, err := local.DialContext(context.Background(), network, remote.Addr().String())
64         c.Assert(err, qt.IsNil)
65         defer first.Close()
66         second, err := local.DialContext(context.Background(), network, remote.Addr().String())
67         c.Assert(err, qt.IsNil)
68         defer second.Close()
69         remote.Close()
70         <-doneAccepting
71         c.Assert(atomic.LoadInt32(&remoteAccepts), qt.Equals, int32(2))
72 }