From eeaf9f67a9f6f1ba37439ef79b0345c8f5213337 Mon Sep 17 00:00:00 2001 From: Matt Joiner Date: Tue, 13 Feb 2018 00:23:07 +1100 Subject: [PATCH] tracker: Support peers6 key in http responses --- tracker/http.go | 56 +++++++++++++++++++++++++++++++------------- tracker/http_test.go | 49 ++++++++++++++++++++++++++++---------- 2 files changed, 77 insertions(+), 28 deletions(-) diff --git a/tracker/http.go b/tracker/http.go index d207f852..6c9dcafc 100644 --- a/tracker/http.go +++ b/tracker/http.go @@ -16,39 +16,50 @@ import ( ) type httpResponse struct { - FailureReason string `bencode:"failure reason"` - Interval int32 `bencode:"interval"` - TrackerId string `bencode:"tracker id"` - Complete int32 `bencode:"complete"` - Incomplete int32 `bencode:"incomplete"` - Peers interface{} `bencode:"peers"` + FailureReason string `bencode:"failure reason"` + Interval int32 `bencode:"interval"` + TrackerId string `bencode:"tracker id"` + Complete int32 `bencode:"complete"` + Incomplete int32 `bencode:"incomplete"` + Peers Peers `bencode:"peers"` + // BEP 7 + Peers6 krpc.CompactIPv6NodeAddrs `bencode:"peers6"` } -func (r *httpResponse) UnmarshalPeers() (ret []Peer, err error) { - switch v := r.Peers.(type) { +type Peers []Peer + +func (me *Peers) UnmarshalBencode(b []byte) (err error) { + var _v interface{} + err = bencode.Unmarshal(b, &_v) + if err != nil { + return + } + switch v := _v.(type) { case string: - var cps krpc.CompactIPv4NodeAddrs - err = cps.UnmarshalBinary([]byte(v)) + vars.Add("http responses with string peers", 1) + var cnas krpc.CompactIPv4NodeAddrs + err = cnas.UnmarshalBinary([]byte(v)) if err != nil { return } - ret = make([]Peer, 0, len(cps)) - for _, cp := range cps { - ret = append(ret, Peer{ + for _, cp := range cnas { + *me = append(*me, Peer{ IP: cp.IP[:], Port: int(cp.Port), }) } return case []interface{}: + vars.Add("http responses with list peers", 1) for _, i := range v { var p Peer p.fromDictInterface(i.(map[string]interface{})) - ret = append(ret, p) + *me = append(*me, p) } return default: - err = fmt.Errorf("unsupported peers value type: %T", r.Peers) + vars.Add("http responses with unhandled peers type", 1) + err = fmt.Errorf("unsupported type: %T", _v) return } } @@ -100,9 +111,22 @@ func announceHTTP(cl *http.Client, userAgent string, ar *AnnounceRequest, _url * err = errors.New(trackerResponse.FailureReason) return } + vars.Add("successful http announces", 1) ret.Interval = trackerResponse.Interval ret.Leechers = trackerResponse.Incomplete ret.Seeders = trackerResponse.Complete - ret.Peers, err = trackerResponse.UnmarshalPeers() + if len(trackerResponse.Peers) != 0 { + vars.Add("http responses with nonempty peers key", 1) + } + ret.Peers = trackerResponse.Peers + if len(trackerResponse.Peers6) != 0 { + vars.Add("http responses with nonempty peers6 key", 1) + } + for _, na := range trackerResponse.Peers6 { + ret.Peers = append(ret.Peers, Peer{ + IP: na.IP, + Port: na.Port, + }) + } return } diff --git a/tracker/http_test.go b/tracker/http_test.go index d658d62c..c90a35ef 100644 --- a/tracker/http_test.go +++ b/tracker/http_test.go @@ -13,16 +13,41 @@ var defaultHTTPUserAgent = "Go-Torrent" func TestUnmarshalHTTPResponsePeerDicts(t *testing.T) { var hr httpResponse - require.NoError(t, bencode.Unmarshal([]byte("d5:peersl"+ - "d2:ip7:1.2.3.47:peer id20:thisisthe20bytepeeri4:porti9999ee"+ - "d7:peer id20:thisisthe20bytepeeri2:ip39:2001:0db8:85a3:0000:0000:8a2e:0370:73344:porti9998ee"+ - "ee"), &hr)) - ps, err := hr.UnmarshalPeers() - require.NoError(t, err) - require.Len(t, ps, 2) - assert.Equal(t, []byte("thisisthe20bytepeeri"), ps[0].ID) - assert.EqualValues(t, 9999, ps[0].Port) - assert.EqualValues(t, 9998, ps[1].Port) - assert.NotNil(t, ps[0].IP) - assert.NotNil(t, ps[1].IP) + require.NoError(t, bencode.Unmarshal( + []byte("d5:peersl"+ + "d2:ip7:1.2.3.47:peer id20:thisisthe20bytepeeri4:porti9999ee"+ + "d7:peer id20:thisisthe20bytepeeri2:ip39:2001:0db8:85a3:0000:0000:8a2e:0370:73344:porti9998ee"+ + "e"+ + "6:peers618:123412341234123456"+ + "e"), + &hr)) + + require.Len(t, hr.Peers, 2) + assert.Equal(t, []byte("thisisthe20bytepeeri"), hr.Peers[0].ID) + assert.EqualValues(t, 9999, hr.Peers[0].Port) + assert.EqualValues(t, 9998, hr.Peers[1].Port) + assert.NotNil(t, hr.Peers[0].IP) + assert.NotNil(t, hr.Peers[1].IP) + + assert.Len(t, hr.Peers6, 1) + assert.EqualValues(t, "1234123412341234", hr.Peers6[0].IP) + assert.EqualValues(t, 0x3536, hr.Peers6[0].Port) +} + +func TestUnmarshalHttpResponseNoPeers(t *testing.T) { + var hr httpResponse + require.NoError(t, bencode.Unmarshal( + []byte("d6:peers618:123412341234123456e"), + &hr, + )) + require.Len(t, hr.Peers, 0) + assert.Len(t, hr.Peers6, 1) +} + +func TestUnmarshalHttpResponsePeers6NotCompact(t *testing.T) { + var hr httpResponse + require.Error(t, bencode.Unmarshal( + []byte("d6:peers6lee"), + &hr, + )) }