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