]> Sergey Matveev's repositories - btrtrc.git/blob - tracker/tracker.go
Fix race in concurrent connects in UDP tracker
[btrtrc.git] / tracker / tracker.go
1 package tracker
2
3 import (
4         "context"
5         "errors"
6         "net/http"
7         "net/url"
8         "time"
9
10         "github.com/anacrolix/dht/v2/krpc"
11         trHttp "github.com/anacrolix/torrent/tracker/http"
12         "github.com/anacrolix/torrent/tracker/shared"
13         "github.com/anacrolix/torrent/tracker/udp"
14 )
15
16 const (
17         None      = shared.None
18         Started   = shared.Started
19         Stopped   = shared.Stopped
20         Completed = shared.Completed
21 )
22
23 type AnnounceRequest = udp.AnnounceRequest
24
25 type AnnounceResponse = trHttp.AnnounceResponse
26
27 type Peer = trHttp.Peer
28
29 type AnnounceEvent = udp.AnnounceEvent
30
31 var (
32         ErrBadScheme = errors.New("unknown scheme")
33 )
34
35 type Announce struct {
36         TrackerUrl string
37         Request    AnnounceRequest
38         HostHeader string
39         HTTPProxy  func(*http.Request) (*url.URL, error)
40         ServerName string
41         UserAgent  string
42         UdpNetwork string
43         // If the port is zero, it's assumed to be the same as the Request.Port.
44         ClientIp4 krpc.NodeAddr
45         // If the port is zero, it's assumed to be the same as the Request.Port.
46         ClientIp6 krpc.NodeAddr
47         Context   context.Context
48 }
49
50 // The code *is* the documentation.
51 const DefaultTrackerAnnounceTimeout = 15 * time.Second
52
53 func (me Announce) Do() (res AnnounceResponse, err error) {
54         cl, err := NewClient(me.TrackerUrl, NewClientOpts{
55                 Http: trHttp.NewClientOpts{
56                         Proxy:      me.HTTPProxy,
57                         ServerName: me.ServerName,
58                 },
59                 UdpNetwork: me.UdpNetwork,
60         })
61         if err != nil {
62                 return
63         }
64         defer cl.Close()
65         if me.Context == nil {
66                 // This is just to maintain the old behaviour that should be a timeout of 15s. Users can
67                 // override it by providing their own Context. See comments elsewhere about longer timeouts
68                 // acting as rate limiting overloaded trackers.
69                 ctx, cancel := context.WithTimeout(context.Background(), DefaultTrackerAnnounceTimeout)
70                 defer cancel()
71                 me.Context = ctx
72         }
73         return cl.Announce(me.Context, me.Request, trHttp.AnnounceOpt{
74                 UserAgent:  me.UserAgent,
75                 HostHeader: me.HostHeader,
76                 ClientIp4:  me.ClientIp4.IP,
77                 ClientIp6:  me.ClientIp6.IP,
78         })
79 }