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  }