tracker/http.go | 38 +++++++++++++++----------------------- tracker/tracker.go | 36 ++++++++++-------------------------- tracker/udp.go | 32 +++++++++++++++----------------- diff --git a/tracker/http.go b/tracker/http.go index 0f5c6c30df28a5c9a0d27b747212bd86cf606c80..20678b8c1d90ac0f734b27c4dbe454ee13422a24 100644 --- a/tracker/http.go +++ b/tracker/http.go @@ -10,25 +10,11 @@ "net/http" "net/url" "strconv" + "github.com/anacrolix/missinggo/httptoo" + "github.com/anacrolix/torrent/bencode" "github.com/anacrolix/torrent/util" ) - -func init() { - registerClientScheme("http", newHTTPClient) -} - -type httpClient struct { - url url.URL -} - -func (httpClient) Close() error { return nil } - -func newHTTPClient(url *url.URL) client { - return &httpClient{ - url: *url, - } -} type httpResponse struct { FailureReason string `bencode:"failure reason"` @@ -56,9 +42,8 @@ } return } -func (c *httpClient) Announce(ar *AnnounceRequest) (ret AnnounceResponse, err error) { - // retain query parameters from announce URL - q := c.url.Query() +func setAnnounceParams(_url *url.URL, ar *AnnounceRequest) { + q := _url.Query() q.Set("info_hash", string(ar.InfoHash[:])) q.Set("peer_id", string(ar.PeerId[:])) @@ -73,14 +58,21 @@ // http://stackoverflow.com/questions/17418004/why-does-tracker-server-not-understand-my-request-bittorrent-protocol q.Set("compact", "1") // According to https://wiki.vuze.com/w/Message_Stream_Encryption. q.Set("supportcrypto", "1") - var reqURL url.URL = c.url - reqURL.RawQuery = q.Encode() - resp, err := http.Get(reqURL.String()) + + _url.RawQuery = q.Encode() +} + +func announceHTTP(ar *AnnounceRequest, _url *url.URL, host string) (ret AnnounceResponse, err error) { + _url = httptoo.CopyURL(_url) + setAnnounceParams(_url, ar) + req, err := http.NewRequest("GET", _url.String(), nil) + req.Host = host + resp, err := http.DefaultClient.Do(req) if err != nil { return } defer resp.Body.Close() - buf := bytes.Buffer{} + var buf bytes.Buffer io.Copy(&buf, resp.Body) if resp.StatusCode != 200 { err = fmt.Errorf("response from tracker: %s: %s", resp.Status, buf.String()) diff --git a/tracker/tracker.go b/tracker/tracker.go index 3c6633018f0e9c953381cc85ef46d63942748718..c57d8052700a96642d8e78b0de8324a38788bd6c 100644 --- a/tracker/tracker.go +++ b/tracker/tracker.go @@ -46,42 +46,26 @@ Started // The local peer has just resumed this torrent. Stopped // The local peer is leaving the swarm. ) -type client interface { - Announce(*AnnounceRequest) (AnnounceResponse, error) - Close() error -} - var ( ErrBadScheme = errors.New("unknown scheme") - - schemes = make(map[string]func(*url.URL) client) ) -func registerClientScheme(scheme string, newFunc func(*url.URL) client) { - schemes[scheme] = newFunc +func Announce(urlStr string, req *AnnounceRequest) (res AnnounceResponse, err error) { + return AnnounceHost(urlStr, req, "") } -// Returns ErrBadScheme if the tracker scheme isn't recognised. -func newClient(rawurl string) (cl client, err error) { - url_s, err := url.Parse(rawurl) +func AnnounceHost(urlStr string, req *AnnounceRequest, host string) (res AnnounceResponse, err error) { + _url, err := url.Parse(urlStr) if err != nil { return } - newFunc, ok := schemes[url_s.Scheme] - if !ok { + switch _url.Scheme { + case "http", "https": + return announceHTTP(req, _url, host) + case "udp": + return announceUDP(req, _url) + default: err = ErrBadScheme return } - cl = newFunc(url_s) - return -} - -func Announce(urlStr string, req *AnnounceRequest) (res AnnounceResponse, err error) { - cl, err := newClient(urlStr) - if err != nil { - return - } - defer cl.Close() - return cl.Announce(req) - } diff --git a/tracker/udp.go b/tracker/udp.go index 6d1228a38b991ba9047aea4165ecb118a4e39b56..07c7f0ae2d0d19a9c38442f8745483b499dcf625 100644 --- a/tracker/udp.go +++ b/tracker/udp.go @@ -60,16 +60,6 @@ Leechers int32 Seeders int32 } -func init() { - registerClientScheme("udp", newUDPClient) -} - -func newUDPClient(url *url.URL) client { - return &udpClient{ - url: *url, - } -} - func newTransactionId() int32 { return int32(rand.Uint32()) } @@ -85,7 +75,7 @@ } return } -type udpClient struct { +type udpAnnounce struct { contiguousTimeouts int connectionIdReceived time.Time connectionId int64 @@ -93,14 +83,14 @@ socket net.Conn url url.URL } -func (c *udpClient) Close() error { +func (c *udpAnnounce) Close() error { if c.socket != nil { return c.socket.Close() } return nil } -func (c *udpClient) Announce(req *AnnounceRequest) (res AnnounceResponse, err error) { +func (c *udpAnnounce) Do(req *AnnounceRequest) (res AnnounceResponse, err error) { err = c.connect() if err != nil { return @@ -140,7 +130,7 @@ } // body is the binary serializable request body. trailer is optional data // following it, such as for BEP 41. -func (c *udpClient) write(h *RequestHeader, body interface{}, trailer []byte) (err error) { +func (c *udpAnnounce) write(h *RequestHeader, body interface{}, trailer []byte) (err error) { var buf bytes.Buffer err = binary.Write(&buf, binary.BigEndian, h) if err != nil { @@ -176,7 +166,7 @@ } // args is the binary serializable request body. trailer is optional data // following it, such as for BEP 41. -func (c *udpClient) request(action Action, args interface{}, options []byte) (responseBody *bytes.Buffer, err error) { +func (c *udpAnnounce) request(action Action, args interface{}, options []byte) (responseBody *bytes.Buffer, err error) { tid := newTransactionId() err = c.write(&RequestHeader{ ConnectionId: c.connectionId, @@ -232,11 +222,11 @@ } return } -func (c *udpClient) connected() bool { +func (c *udpAnnounce) connected() bool { return !c.connectionIdReceived.IsZero() && time.Now().Before(c.connectionIdReceived.Add(time.Minute)) } -func (c *udpClient) connect() (err error) { +func (c *udpAnnounce) connect() (err error) { if c.connected() { return nil } @@ -266,3 +256,11 @@ c.connectionId = res.ConnectionId c.connectionIdReceived = time.Now() return } + +func announceUDP(ar *AnnounceRequest, _url *url.URL) (AnnounceResponse, error) { + ua := udpAnnounce{ + url: *_url, + } + defer ua.Close() + return ua.Do(ar) +}