]> Sergey Matveev's repositories - btrtrc.git/blob - tracker/udp_test.go
Don't dial in UDP tracking
[btrtrc.git] / tracker / udp_test.go
1 package tracker
2
3 import (
4         "bytes"
5         "context"
6         "crypto/rand"
7         "errors"
8         "fmt"
9         "io/ioutil"
10         "net"
11         "net/url"
12         "sync"
13         "testing"
14         "time"
15
16         "github.com/anacrolix/dht/v2/krpc"
17         _ "github.com/anacrolix/envpprof"
18         "github.com/anacrolix/torrent/tracker/udp"
19         "github.com/stretchr/testify/assert"
20         "github.com/stretchr/testify/require"
21 )
22
23 var trackers = []string{
24         "udp://tracker.opentrackr.org:1337/announce",
25         "udp://tracker.openbittorrent.com:6969/announce",
26 }
27
28 func TestAnnounceLocalhost(t *testing.T) {
29         t.Parallel()
30         srv := server{
31                 t: map[[20]byte]torrent{
32                         {0xa3, 0x56, 0x41, 0x43, 0x74, 0x23, 0xe6, 0x26, 0xd9, 0x38, 0x25, 0x4a, 0x6b, 0x80, 0x49, 0x10, 0xa6, 0x67, 0xa, 0xc1}: {
33                                 Seeders:  1,
34                                 Leechers: 2,
35                                 Peers: krpc.CompactIPv4NodeAddrs{
36                                         {[]byte{1, 2, 3, 4}, 5},
37                                         {[]byte{6, 7, 8, 9}, 10},
38                                 },
39                         },
40                 },
41         }
42         var err error
43         srv.pc, err = net.ListenPacket("udp", "localhost:0")
44         require.NoError(t, err)
45         defer srv.pc.Close()
46         go func() {
47                 require.NoError(t, srv.serveOne())
48         }()
49         req := AnnounceRequest{
50                 NumWant: -1,
51                 Event:   Started,
52         }
53         rand.Read(req.PeerId[:])
54         copy(req.InfoHash[:], []uint8{0xa3, 0x56, 0x41, 0x43, 0x74, 0x23, 0xe6, 0x26, 0xd9, 0x38, 0x25, 0x4a, 0x6b, 0x80, 0x49, 0x10, 0xa6, 0x67, 0xa, 0xc1})
55         go func() {
56                 require.NoError(t, srv.serveOne())
57         }()
58         ar, err := Announce{
59                 TrackerUrl: fmt.Sprintf("udp://%s/announce", srv.pc.LocalAddr().String()),
60                 Request:    req,
61         }.Do()
62         require.NoError(t, err)
63         assert.EqualValues(t, 1, ar.Seeders)
64         assert.EqualValues(t, 2, len(ar.Peers))
65 }
66
67 func TestUDPTracker(t *testing.T) {
68         t.Parallel()
69         if testing.Short() {
70                 t.SkipNow()
71         }
72         req := AnnounceRequest{
73                 NumWant: -1,
74         }
75         rand.Read(req.PeerId[:])
76         copy(req.InfoHash[:], []uint8{0xa3, 0x56, 0x41, 0x43, 0x74, 0x23, 0xe6, 0x26, 0xd9, 0x38, 0x25, 0x4a, 0x6b, 0x80, 0x49, 0x10, 0xa6, 0x67, 0xa, 0xc1})
77         ctx, cancel := context.WithTimeout(context.Background(), DefaultTrackerAnnounceTimeout)
78         defer cancel()
79         if dl, ok := t.Deadline(); ok {
80                 var cancel func()
81                 ctx, cancel = context.WithDeadline(context.Background(), dl.Add(-time.Second))
82                 defer cancel()
83         }
84         ar, err := Announce{
85                 TrackerUrl: trackers[0],
86                 Request:    req,
87                 Context:    ctx,
88         }.Do()
89         // Skip any net errors as we don't control the server.
90         var ne net.Error
91         if errors.As(err, &ne) {
92                 t.Skip(err)
93         }
94         require.NoError(t, err)
95         t.Logf("%+v", ar)
96 }
97
98 func TestAnnounceRandomInfoHashThirdParty(t *testing.T) {
99         t.Parallel()
100         if testing.Short() {
101                 // This test involves contacting third party servers that may have
102                 // unpredictable results.
103                 t.SkipNow()
104         }
105         req := AnnounceRequest{
106                 Event: Stopped,
107         }
108         rand.Read(req.PeerId[:])
109         rand.Read(req.InfoHash[:])
110         wg := sync.WaitGroup{}
111         ctx, cancel := context.WithTimeout(context.Background(), DefaultTrackerAnnounceTimeout)
112         defer cancel()
113         if dl, ok := t.Deadline(); ok {
114                 var cancel func()
115                 ctx, cancel = context.WithDeadline(ctx, dl.Add(-time.Second))
116                 defer cancel()
117         }
118         for _, url := range trackers {
119                 wg.Add(1)
120                 go func(url string) {
121                         defer wg.Done()
122                         resp, err := Announce{
123                                 TrackerUrl: url,
124                                 Request:    req,
125                                 Context:    ctx,
126                         }.Do()
127                         if err != nil {
128                                 t.Logf("error announcing to %s: %s", url, err)
129                                 return
130                         }
131                         if resp.Leechers != 0 || resp.Seeders != 0 || len(resp.Peers) != 0 {
132                                 // The info hash we generated was random in 2^160 space. If we
133                                 // get a hit, something is weird.
134                                 t.Fatal(resp)
135                         }
136                         t.Logf("announced to %s", url)
137                         cancel()
138                 }(url)
139         }
140         wg.Wait()
141         cancel()
142 }
143
144 // Check that URLPath option is done correctly.
145 func TestURLPathOption(t *testing.T) {
146         conn, err := net.ListenPacket("udp", "localhost:0")
147         if err != nil {
148                 panic(err)
149         }
150         defer conn.Close()
151         announceErr := make(chan error)
152         go func() {
153                 _, err := Announce{
154                         TrackerUrl: (&url.URL{
155                                 Scheme: "udp",
156                                 Host:   conn.LocalAddr().String(),
157                                 Path:   "/announce",
158                         }).String(),
159                 }.Do()
160                 defer conn.Close()
161                 announceErr <- err
162         }()
163         var b [512]byte
164         // conn.SetReadDeadline(time.Now().Add(time.Second))
165         _, addr, _ := conn.ReadFrom(b[:])
166         r := bytes.NewReader(b[:])
167         var h udp.RequestHeader
168         udp.Read(r, &h)
169         w := &bytes.Buffer{}
170         udp.Write(w, udp.ResponseHeader{
171                 Action:        udp.ActionConnect,
172                 TransactionId: h.TransactionId,
173         })
174         udp.Write(w, udp.ConnectionResponse{42})
175         conn.WriteTo(w.Bytes(), addr)
176         n, _, _ := conn.ReadFrom(b[:])
177         r = bytes.NewReader(b[:n])
178         udp.Read(r, &h)
179         udp.Read(r, &AnnounceRequest{})
180         all, _ := ioutil.ReadAll(r)
181         if string(all) != "\x02\x09/announce" {
182                 t.FailNow()
183         }
184         w = &bytes.Buffer{}
185         udp.Write(w, udp.ResponseHeader{
186                 Action:        udp.ActionAnnounce,
187                 TransactionId: h.TransactionId,
188         })
189         udp.Write(w, udp.AnnounceResponseHeader{})
190         conn.WriteTo(w.Bytes(), addr)
191         require.NoError(t, <-announceErr)
192 }