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