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