mirror of
https://github.com/sot-tech/mochi.git
synced 2026-05-21 07:14:48 -07:00
Initial torrentV2 hash support
This commit is contained in:
committed by
Lawrence, Rendall
parent
823b92fe83
commit
2f092bad45
@@ -5,6 +5,7 @@ package bittorrent
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/pkg/errors"
|
||||||
"net"
|
"net"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -12,6 +13,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// PeerID represents a peer ID.
|
// PeerID represents a peer ID.
|
||||||
|
// TODO: check if torrentV2 also changed this field size
|
||||||
type PeerID [20]byte
|
type PeerID [20]byte
|
||||||
|
|
||||||
// PeerIDFromBytes creates a PeerID from a byte slice.
|
// PeerIDFromBytes creates a PeerID from a byte slice.
|
||||||
@@ -51,32 +53,52 @@ func PeerIDFromString(s string) PeerID {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// InfoHash represents an infohash.
|
// InfoHash represents an infohash.
|
||||||
type InfoHash [20]byte
|
type InfoHash []byte
|
||||||
|
|
||||||
|
const(
|
||||||
|
InfoHashV1Len = 20
|
||||||
|
InfoHashV2Len = 32
|
||||||
|
)
|
||||||
|
|
||||||
|
var invalidHashSize = errors.New("InfoHash must be either 20 (for torrent V1) or 32 (V2) bytes")
|
||||||
|
var isNotV1Hash = errors.New("InfoHash is not V1 (SHA1)")
|
||||||
|
|
||||||
|
// BytesV1 returns 20-bytes length array of the corresponding InfoHash.
|
||||||
|
// If InfoHash is not 20-bytes long (is torrent V2 hash) zeroed array and error returned
|
||||||
|
func (i InfoHash) BytesV1() ([InfoHashV1Len]byte, error){
|
||||||
|
var bb [InfoHashV1Len]byte
|
||||||
|
if len(i) != InfoHashV1Len {
|
||||||
|
return bb, isNotV1Hash
|
||||||
|
}
|
||||||
|
copy(bb[:], i)
|
||||||
|
return bb, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateInfoHash validates input bytes size and returns it
|
||||||
|
// if size one of InfoHashV1Len or InfoHashV2Len.
|
||||||
|
// In other case 0 and non-nil error returned
|
||||||
|
func ValidateInfoHash(b []byte) (int, error) {
|
||||||
|
l := len(b)
|
||||||
|
if l != InfoHashV1Len && l != InfoHashV2Len {
|
||||||
|
return 0, invalidHashSize
|
||||||
|
}
|
||||||
|
return l, nil
|
||||||
|
}
|
||||||
|
|
||||||
// InfoHashFromBytes creates an InfoHash from a byte slice.
|
// InfoHashFromBytes creates an InfoHash from a byte slice.
|
||||||
//
|
func InfoHashFromBytes(b []byte) (InfoHash, error) {
|
||||||
// It panics if b is not 20 bytes long.
|
if l, err := ValidateInfoHash(b); err != nil{
|
||||||
func InfoHashFromBytes(b []byte) InfoHash {
|
return nil, err
|
||||||
if len(b) != 20 {
|
} else {
|
||||||
panic("infohash must be 20 bytes")
|
buf := make([]byte, l)
|
||||||
|
copy(buf[:], b)
|
||||||
|
return buf, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var buf [20]byte
|
|
||||||
copy(buf[:], b)
|
|
||||||
return buf
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// InfoHashFromString creates an InfoHash from a string.
|
// InfoHashFromString creates an InfoHash from a string.
|
||||||
//
|
func InfoHashFromString(s string) (InfoHash, error) {
|
||||||
// It panics if s is not 20 bytes long.
|
return InfoHashFromBytes([]byte(s))
|
||||||
func InfoHashFromString(s string) InfoHash {
|
|
||||||
if len(s) != 20 {
|
|
||||||
panic("infohash must be 20 bytes")
|
|
||||||
}
|
|
||||||
|
|
||||||
var buf [20]byte
|
|
||||||
copy(buf[:], s)
|
|
||||||
return buf
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// String implements fmt.Stringer, returning the base16 encoded InfoHash.
|
// String implements fmt.Stringer, returning the base16 encoded InfoHash.
|
||||||
@@ -84,9 +106,9 @@ func (i InfoHash) String() string {
|
|||||||
return fmt.Sprintf("%x", i[:])
|
return fmt.Sprintf("%x", i[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
// RawString returns a 20-byte string of the raw bytes of the InfoHash.
|
// RawString returns a string of the raw bytes of the InfoHash.
|
||||||
func (i InfoHash) RawString() string {
|
func (i InfoHash) RawString() string {
|
||||||
return string(i[:])
|
return string(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AnnounceRequest represents the parsed parameters from an announce request.
|
// AnnounceRequest represents the parsed parameters from an announce request.
|
||||||
|
|||||||
@@ -41,8 +41,9 @@ func TestPeerID_String(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestInfoHash_String(t *testing.T) {
|
func TestInfoHash_String(t *testing.T) {
|
||||||
s := InfoHashFromBytes(b).String()
|
ih, err := InfoHashFromBytes(b)
|
||||||
require.Equal(t, expected, s)
|
require.Nil(t, err)
|
||||||
|
require.Equal(t, expected, ih.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPeer_String(t *testing.T) {
|
func TestPeer_String(t *testing.T) {
|
||||||
|
|||||||
@@ -168,10 +168,11 @@ func parseQuery(query string) (q *QueryParams, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if key == "info_hash" {
|
if key == "info_hash" {
|
||||||
if len(value) != 20 {
|
if ih, err := InfoHashFromString(value); err == nil{
|
||||||
return nil, ErrInvalidInfohash
|
q.infoHashes = append(q.infoHashes, ih)
|
||||||
|
} else {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
q.infoHashes = append(q.infoHashes, InfoHashFromString(value))
|
|
||||||
} else {
|
} else {
|
||||||
q.params[strings.ToLower(key)] = value
|
q.params[strings.ToLower(key)] = value
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
yaml "gopkg.in/yaml.v2"
|
yaml "gopkg.in/yaml.v2"
|
||||||
@@ -73,19 +72,10 @@ func ParseConfigFile(path string) (*ConfigFile, error) {
|
|||||||
f, err := os.Open(os.ExpandEnv(path))
|
f, err := os.Open(os.ExpandEnv(path))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
} else {
|
||||||
|
defer f.Close()
|
||||||
|
cfgFile := new(ConfigFile)
|
||||||
|
err = yaml.NewDecoder(f).Decode(cfgFile)
|
||||||
|
return cfgFile, err
|
||||||
}
|
}
|
||||||
defer f.Close()
|
|
||||||
|
|
||||||
contents, err := ioutil.ReadAll(f)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var cfgFile ConfigFile
|
|
||||||
err = yaml.Unmarshal(contents, &cfgFile)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &cfgFile, nil
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/rand"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math/rand"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/anacrolix/torrent/tracker"
|
"github.com/anacrolix/torrent/tracker"
|
||||||
@@ -54,28 +54,22 @@ func EndToEndRunCmdFunc(cmd *cobra.Command, args []string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateInfohash() [20]byte {
|
func generateInfohash() bittorrent.InfoHash {
|
||||||
b := make([]byte, 20)
|
b := make([]byte, 20)
|
||||||
|
rand.Read(b)
|
||||||
n, err := rand.Read(b)
|
ih, _ := bittorrent.InfoHashFromBytes(b)
|
||||||
if err != nil {
|
return ih
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
if n != 20 {
|
|
||||||
panic(fmt.Errorf("not enough randomness? Got %d bytes", n))
|
|
||||||
}
|
|
||||||
|
|
||||||
return bittorrent.InfoHashFromBytes(b)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func test(addr string, delay time.Duration) error {
|
func test(addr string, delay time.Duration) error {
|
||||||
ih := generateInfohash()
|
ih, _ := generateInfohash().BytesV1()
|
||||||
return testWithInfohash(ih, addr, delay)
|
return testWithInfohash(ih, addr, delay)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testWithInfohash(infoHash [20]byte, url string, delay time.Duration) error {
|
func testWithInfohash(infoHash [20]byte, url string, delay time.Duration) error {
|
||||||
|
var ih [20]byte
|
||||||
req := tracker.AnnounceRequest{
|
req := tracker.AnnounceRequest{
|
||||||
InfoHash: infoHash,
|
InfoHash: ih,
|
||||||
PeerId: [20]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20},
|
PeerId: [20]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20},
|
||||||
Downloaded: 50,
|
Downloaded: 50,
|
||||||
Left: 100,
|
Left: 100,
|
||||||
|
|||||||
@@ -172,34 +172,21 @@ func NewFrontend(logic frontend.TrackerLogic, provided Config) (*Frontend, error
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.HTTPSAddr != "" && f.tlsCfg == nil {
|
if cfg.HTTPSAddr == "" || f.tlsCfg == nil {
|
||||||
return nil, errors.New("must specify tls_cert_path and tls_key_path when using https_addr")
|
return nil, errors.New("must specify both https_addr, tls_cert_path and tls_key_path")
|
||||||
}
|
|
||||||
if cfg.HTTPSAddr == "" && f.tlsCfg != nil {
|
|
||||||
return nil, errors.New("must specify https_addr when using tls_cert_path and tls_key_path")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var listenerHTTP, listenerHTTPS net.Listener
|
router := httprouter.New()
|
||||||
var err error
|
for _, route := range f.AnnounceRoutes {
|
||||||
if cfg.Addr != "" {
|
router.GET(route, f.announceRoute)
|
||||||
listenerHTTP, err = net.Listen("tcp", f.Addr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if cfg.HTTPSAddr != "" {
|
for _, route := range f.ScrapeRoutes {
|
||||||
listenerHTTPS, err = net.Listen("tcp", f.HTTPSAddr)
|
router.GET(route, f.scrapeRoute)
|
||||||
if err != nil {
|
|
||||||
if listenerHTTP != nil {
|
|
||||||
listenerHTTP.Close()
|
|
||||||
}
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.Addr != "" {
|
if cfg.Addr != "" {
|
||||||
go func() {
|
go func() {
|
||||||
if err := f.serveHTTP(listenerHTTP); err != nil {
|
if err := f.serveHTTP(router,false); err != nil {
|
||||||
log.Fatal("failed while serving http", log.Err(err))
|
log.Fatal("failed while serving http", log.Err(err))
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
@@ -207,7 +194,7 @@ func NewFrontend(logic frontend.TrackerLogic, provided Config) (*Frontend, error
|
|||||||
|
|
||||||
if cfg.HTTPSAddr != "" {
|
if cfg.HTTPSAddr != "" {
|
||||||
go func() {
|
go func() {
|
||||||
if err := f.serveHTTPS(listenerHTTPS); err != nil {
|
if err := f.serveHTTP(router,true); err != nil {
|
||||||
log.Fatal("failed while serving https", log.Err(err))
|
log.Fatal("failed while serving https", log.Err(err))
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
@@ -240,52 +227,31 @@ func (f *Frontend) makeStopFunc(stopSrv *http.Server) stop.Func {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Frontend) handler() http.Handler {
|
|
||||||
router := httprouter.New()
|
|
||||||
for _, route := range f.AnnounceRoutes {
|
|
||||||
router.GET(route, f.announceRoute)
|
|
||||||
}
|
|
||||||
for _, route := range f.ScrapeRoutes {
|
|
||||||
router.GET(route, f.scrapeRoute)
|
|
||||||
}
|
|
||||||
return router
|
|
||||||
}
|
|
||||||
|
|
||||||
// serveHTTP blocks while listening and serving non-TLS HTTP BitTorrent
|
// serveHTTP blocks while listening and serving non-TLS HTTP BitTorrent
|
||||||
// requests until Stop() is called or an error is returned.
|
// requests until Stop() is called or an error is returned.
|
||||||
func (f *Frontend) serveHTTP(l net.Listener) error {
|
func (f *Frontend) serveHTTP(handler http.Handler, tls bool) error {
|
||||||
f.srv = &http.Server{
|
srv := &http.Server{
|
||||||
Addr: f.Addr,
|
Handler: handler,
|
||||||
Handler: f.handler(),
|
|
||||||
ReadTimeout: f.ReadTimeout,
|
ReadTimeout: f.ReadTimeout,
|
||||||
WriteTimeout: f.WriteTimeout,
|
WriteTimeout: f.WriteTimeout,
|
||||||
IdleTimeout: f.IdleTimeout,
|
IdleTimeout: f.IdleTimeout,
|
||||||
}
|
}
|
||||||
|
|
||||||
f.srv.SetKeepAlivesEnabled(f.EnableKeepAlive)
|
srv.SetKeepAlivesEnabled(f.EnableKeepAlive)
|
||||||
|
|
||||||
// Start the HTTP server.
|
var err error
|
||||||
if err := f.srv.Serve(l); err != http.ErrServerClosed {
|
if tls {
|
||||||
return err
|
srv.Addr = f.HTTPSAddr
|
||||||
|
srv.TLSConfig = f.tlsCfg
|
||||||
|
f.tlsSrv = srv
|
||||||
|
err = srv.ListenAndServe()
|
||||||
|
} else{
|
||||||
|
srv.Addr = f.Addr
|
||||||
|
f.srv = srv
|
||||||
|
err = f.tlsSrv.ListenAndServeTLS("", "")
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// serveHTTPS blocks while listening and serving TLS HTTP BitTorrent
|
|
||||||
// requests until Stop() is called or an error is returned.
|
|
||||||
func (f *Frontend) serveHTTPS(l net.Listener) error {
|
|
||||||
f.tlsSrv = &http.Server{
|
|
||||||
Addr: f.HTTPSAddr,
|
|
||||||
TLSConfig: f.tlsCfg,
|
|
||||||
Handler: f.handler(),
|
|
||||||
ReadTimeout: f.ReadTimeout,
|
|
||||||
WriteTimeout: f.WriteTimeout,
|
|
||||||
}
|
|
||||||
|
|
||||||
f.tlsSrv.SetKeepAlivesEnabled(f.EnableKeepAlive)
|
|
||||||
|
|
||||||
// Start the HTTP server.
|
// Start the HTTP server.
|
||||||
if err := f.tlsSrv.ServeTLS(l, "", ""); err != http.ErrServerClosed {
|
if err != http.ErrServerClosed {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import (
|
|||||||
type strMap map[string]interface{}
|
type strMap map[string]interface{}
|
||||||
|
|
||||||
// WriteError communicates an error to a BitTorrent client over HTTP.
|
// WriteError communicates an error to a BitTorrent client over HTTP.
|
||||||
func WriteError(w http.ResponseWriter, err error) error {
|
func WriteError(w http.ResponseWriter, err error) {
|
||||||
message := "internal server error"
|
message := "internal server error"
|
||||||
if _, clientErr := err.(bittorrent.ClientError); clientErr {
|
if _, clientErr := err.(bittorrent.ClientError); clientErr {
|
||||||
message = err.Error()
|
message = err.Error()
|
||||||
@@ -21,9 +21,11 @@ func WriteError(w http.ResponseWriter, err error) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
return bencode.NewEncoder(w).Encode(map[string]interface{}{
|
if err = bencode.NewEncoder(w).Encode(map[string]interface{}{
|
||||||
"failure reason": message,
|
"failure reason": message,
|
||||||
})
|
}); err != nil{
|
||||||
|
log.Error("unable to encode string", log.Err(err))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteAnnounceResponse communicates the results of an Announce to a
|
// WriteAnnounceResponse communicates the results of an Announce to a
|
||||||
@@ -64,19 +66,18 @@ func WriteAnnounceResponse(w http.ResponseWriter, resp *bittorrent.AnnounceRespo
|
|||||||
bdict["peers6"] = IPv6CompactDict
|
bdict["peers6"] = IPv6CompactDict
|
||||||
}
|
}
|
||||||
|
|
||||||
return bencode.NewEncoder(w).Encode(bdict)
|
} else {
|
||||||
|
// Add the peers to the dictionary.
|
||||||
|
var peers []strMap
|
||||||
|
for _, peer := range resp.IPv4Peers {
|
||||||
|
peers = append(peers, dict(peer))
|
||||||
|
}
|
||||||
|
for _, peer := range resp.IPv6Peers {
|
||||||
|
peers = append(peers, dict(peer))
|
||||||
|
}
|
||||||
|
bdict["peers"] = peers
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the peers to the dictionary.
|
|
||||||
var peers []strMap
|
|
||||||
for _, peer := range resp.IPv4Peers {
|
|
||||||
peers = append(peers, dict(peer))
|
|
||||||
}
|
|
||||||
for _, peer := range resp.IPv6Peers {
|
|
||||||
peers = append(peers, dict(peer))
|
|
||||||
}
|
|
||||||
bdict["peers"] = peers
|
|
||||||
|
|
||||||
return bencode.NewEncoder(w).Encode(bdict)
|
return bencode.NewEncoder(w).Encode(bdict)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,7 +101,7 @@ func compact4(peer bittorrent.Peer) (buf []byte) {
|
|||||||
if ip := peer.IP.To4(); ip == nil {
|
if ip := peer.IP.To4(); ip == nil {
|
||||||
panic("non-IPv4 IP for Peer in IPv4Peers")
|
panic("non-IPv4 IP for Peer in IPv4Peers")
|
||||||
} else {
|
} else {
|
||||||
buf = []byte(ip)
|
buf = ip
|
||||||
}
|
}
|
||||||
buf = append(buf, byte(peer.Port>>8))
|
buf = append(buf, byte(peer.Port>>8))
|
||||||
buf = append(buf, byte(peer.Port&0xff))
|
buf = append(buf, byte(peer.Port&0xff))
|
||||||
@@ -111,7 +112,7 @@ func compact6(peer bittorrent.Peer) (buf []byte) {
|
|||||||
if ip := peer.IP.To16(); ip == nil {
|
if ip := peer.IP.To16(); ip == nil {
|
||||||
panic("non-IPv6 IP for Peer in IPv6Peers")
|
panic("non-IPv6 IP for Peer in IPv6Peers")
|
||||||
} else {
|
} else {
|
||||||
buf = []byte(ip)
|
buf = ip
|
||||||
}
|
}
|
||||||
buf = append(buf, byte(peer.Port>>8))
|
buf = append(buf, byte(peer.Port>>8))
|
||||||
buf = append(buf, byte(peer.Port&0xff))
|
buf = append(buf, byte(peer.Port&0xff))
|
||||||
|
|||||||
@@ -112,10 +112,15 @@ func ParseAnnounce(r Request, v6Action bool, opts ParseOptions) (*bittorrent.Ann
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ih, err := bittorrent.InfoHashFromBytes(infohash)
|
||||||
|
if err != nil{
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
request := &bittorrent.AnnounceRequest{
|
request := &bittorrent.AnnounceRequest{
|
||||||
Event: eventIDs[eventID],
|
Event: eventIDs[eventID],
|
||||||
InfoHash: bittorrent.InfoHashFromBytes(infohash),
|
InfoHash: ih,
|
||||||
NumWant: uint32(numWant),
|
NumWant: numWant,
|
||||||
Left: left,
|
Left: left,
|
||||||
Downloaded: downloaded,
|
Downloaded: downloaded,
|
||||||
Uploaded: uploaded,
|
Uploaded: uploaded,
|
||||||
@@ -208,15 +213,26 @@ func ParseScrape(r Request, opts ParseOptions) (*bittorrent.ScrapeRequest, error
|
|||||||
// Skip past the initial headers and check that the bytes left equal the
|
// Skip past the initial headers and check that the bytes left equal the
|
||||||
// length of a valid list of infohashes.
|
// length of a valid list of infohashes.
|
||||||
r.Packet = r.Packet[16:]
|
r.Packet = r.Packet[16:]
|
||||||
if len(r.Packet)%20 != 0 {
|
l := len(r.Packet)
|
||||||
|
isV1, isV2 := l%bittorrent.InfoHashV1Len == 0, l%bittorrent.InfoHashV2Len == 0
|
||||||
|
|
||||||
|
if !(isV1 || isV2) {
|
||||||
return nil, errMalformedPacket
|
return nil, errMalformedPacket
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocate a list of infohashes and append it to the list until we're out.
|
// Allocate a list of infohashes and append it to the list until we're out.
|
||||||
var infohashes []bittorrent.InfoHash
|
var infohashes []bittorrent.InfoHash
|
||||||
for len(r.Packet) >= 20 {
|
pageSize := bittorrent.InfoHashV1Len
|
||||||
infohashes = append(infohashes, bittorrent.InfoHashFromBytes(r.Packet[:20]))
|
if isV2 {
|
||||||
r.Packet = r.Packet[20:]
|
pageSize = bittorrent.InfoHashV2Len
|
||||||
|
}
|
||||||
|
for len(r.Packet) >= pageSize {
|
||||||
|
if ih, err := bittorrent.InfoHashFromBytes(r.Packet[:pageSize]); err != nil{
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
infohashes = append(infohashes, ih)
|
||||||
|
r.Packet = r.Packet[pageSize:]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sanitize the request.
|
// Sanitize the request.
|
||||||
|
|||||||
@@ -17,16 +17,18 @@ var PeerEqualityFunc = func(p1, p2 bittorrent.Peer) bool { return p1.Equal(p2) }
|
|||||||
|
|
||||||
// TestPeerStore tests a PeerStore implementation against the interface.
|
// TestPeerStore tests a PeerStore implementation against the interface.
|
||||||
func TestPeerStore(t *testing.T, p PeerStore) {
|
func TestPeerStore(t *testing.T, p PeerStore) {
|
||||||
|
ih0, _ := bittorrent.InfoHashFromString("00000000000000000001")
|
||||||
|
ih1, _ := bittorrent.InfoHashFromString("00000000000000000002")
|
||||||
testData := []struct {
|
testData := []struct {
|
||||||
ih bittorrent.InfoHash
|
ih bittorrent.InfoHash
|
||||||
peer bittorrent.Peer
|
peer bittorrent.Peer
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
bittorrent.InfoHashFromString("00000000000000000001"),
|
ih0,
|
||||||
bittorrent.Peer{ID: bittorrent.PeerIDFromString("00000000000000000001"), Port: 1, IP: bittorrent.IP{IP: net.ParseIP("1.1.1.1").To4(), AddressFamily: bittorrent.IPv4}},
|
bittorrent.Peer{ID: bittorrent.PeerIDFromString("00000000000000000001"), Port: 1, IP: bittorrent.IP{IP: net.ParseIP("1.1.1.1").To4(), AddressFamily: bittorrent.IPv4}},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
bittorrent.InfoHashFromString("00000000000000000002"),
|
ih1,
|
||||||
bittorrent.Peer{ID: bittorrent.PeerIDFromString("00000000000000000002"), Port: 2, IP: bittorrent.IP{IP: net.ParseIP("abab::0001"), AddressFamily: bittorrent.IPv6}},
|
bittorrent.Peer{ID: bittorrent.PeerIDFromString("00000000000000000002"), Port: 2, IP: bittorrent.IP{IP: net.ParseIP("abab::0001"), AddressFamily: bittorrent.IPv6}},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user