github.com/anacrolix/torrent@v1.61.0/tracker/udp_test.go (about) 1 package tracker 2 3 import ( 4 "bytes" 5 "context" 6 "crypto/rand" 7 "errors" 8 "fmt" 9 "io" 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, _ := io.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 }