]> Sergey Matveev's repositories - btrtrc.git/commitdiff
tracker: Allow resolving announce URL host in advance, and passing the desired Host...
authorMatt Joiner <anacrolix@gmail.com>
Thu, 19 May 2016 14:48:46 +0000 (00:48 +1000)
committerMatt Joiner <anacrolix@gmail.com>
Thu, 19 May 2016 14:48:46 +0000 (00:48 +1000)
Also did some clean-up of the announce code, the concept of a client is going away.

tracker/http.go
tracker/tracker.go
tracker/udp.go

index 0f5c6c30df28a5c9a0d27b747212bd86cf606c80..20678b8c1d90ac0f734b27c4dbe454ee13422a24 100644 (file)
@@ -10,26 +10,12 @@ import (
        "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"`
        Interval      int32       `bencode:"interval"`
@@ -56,9 +42,8 @@ func (r *httpResponse) UnmarshalPeers() (ret []Peer, err error) {
        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 @@ func (c *httpClient) Announce(ar *AnnounceRequest) (ret AnnounceResponse, err er
        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())
index 3c6633018f0e9c953381cc85ef46d63942748718..c57d8052700a96642d8e78b0de8324a38788bd6c 100644 (file)
@@ -46,42 +46,26 @@ const (
        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)
-
 }
index 6d1228a38b991ba9047aea4165ecb118a4e39b56..07c7f0ae2d0d19a9c38442f8745483b499dcf625 100644 (file)
@@ -60,16 +60,6 @@ type AnnounceResponseHeader struct {
        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 @@ func timeout(contiguousTimeouts int) (d time.Duration) {
        return
 }
 
-type udpClient struct {
+type udpAnnounce struct {
        contiguousTimeouts   int
        connectionIdReceived time.Time
        connectionId         int64
@@ -93,14 +83,14 @@ type udpClient struct {
        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 @@ func (c *udpClient) Announce(req *AnnounceRequest) (res AnnounceResponse, err er
 
 // 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 @@ func write(w io.Writer, data interface{}) error {
 
 // 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 @@ func readBody(r io.Reader, data ...interface{}) (err error) {
        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 @@ func (c *udpClient) connect() (err error) {
        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)
+}