1
0
mirror of https://github.com/veggiedefender/torrent-client.git synced 2025-11-06 09:29:16 +02:00

Break p2p.Peer and parsePeers into its own package

This commit is contained in:
Jesse Li
2020-01-02 10:39:35 -05:00
parent 25810161eb
commit 73a9a5216b
6 changed files with 79 additions and 66 deletions

View File

@@ -8,6 +8,7 @@ import (
"time"
"github.com/veggiedefender/torrent-client/bitfield"
"github.com/veggiedefender/torrent-client/peers"
"github.com/veggiedefender/torrent-client/message"
@@ -15,7 +16,7 @@ import (
)
type client struct {
peer Peer
peer peers.Peer
infoHash [20]byte
peerID [20]byte
conn net.Conn
@@ -57,7 +58,7 @@ func recvBitfield(conn net.Conn, r *bufio.Reader) (bitfield.Bitfield, error) {
return msg.Payload, nil
}
func newClient(peer Peer, peerID, infoHash [20]byte) (*client, error) {
func newClient(peer peers.Peer, peerID, infoHash [20]byte) (*client, error) {
hostPort := net.JoinHostPort(peer.IP.String(), strconv.Itoa(int(peer.Port)))
conn, err := net.DialTimeout("tcp", hostPort, 3*time.Second)
if err != nil {

View File

@@ -5,11 +5,11 @@ import (
"crypto/sha1"
"fmt"
"log"
"net"
"runtime"
"time"
"github.com/veggiedefender/torrent-client/message"
"github.com/veggiedefender/torrent-client/peers"
)
// MaxBlockSize is the largest number of bytes a request can ask for
@@ -18,15 +18,9 @@ const MaxBlockSize = 16384
// MaxBacklog is the number of unfulfilled requests a client can have in its pipeline
const MaxBacklog = 5
// Peer encodes connection information for a peer
type Peer struct {
IP net.IP
Port uint16
}
// Torrent holds data required to download a torrent from a list of peers
type Torrent struct {
Peers []Peer
Peers []peers.Peer
PeerID [20]byte
InfoHash [20]byte
PieceHashes [][20]byte
@@ -146,7 +140,7 @@ func checkIntegrity(pw *pieceWork, buf []byte) error {
return nil
}
func (t *Torrent) startDownloadWorker(peer Peer, workQueue chan *pieceWork, results chan *pieceResult) {
func (t *Torrent) startDownloadWorker(peer peers.Peer, workQueue chan *pieceWork, results chan *pieceResult) {
c, err := newClient(peer, t.PeerID, t.InfoHash)
if err != nil {
log.Printf("Could not handshake with %s. Disconnecting\n", peer.IP)

30
peers/peers.go Normal file
View File

@@ -0,0 +1,30 @@
package peers
import (
"encoding/binary"
"fmt"
"net"
)
// Peer encodes connection information for a peer
type Peer struct {
IP net.IP
Port uint16
}
// Unmarshal parses peer IP addresses and ports from a buffer
func Unmarshal(peersBin []byte) ([]Peer, error) {
const peerSize = 6 // 4 for IP, 2 for port
numPeers := len(peersBin) / peerSize
if len(peersBin)%peerSize != 0 {
err := fmt.Errorf("Received malformed peers")
return nil, err
}
peers := make([]Peer, numPeers)
for i := 0; i < numPeers; i++ {
offset := i * peerSize
peers[i].IP = net.IP(peersBin[offset : offset+4])
peers[i].Port = binary.BigEndian.Uint16([]byte(peersBin[offset+4 : offset+6]))
}
return peers, nil
}

39
peers/peers_test.go Normal file
View File

@@ -0,0 +1,39 @@
package peers
import (
"net"
"testing"
"github.com/stretchr/testify/assert"
)
func TestUnmarshal(t *testing.T) {
tests := map[string]struct {
input string
output []Peer
fails bool
}{
"correctly parses peers": {
input: string([]byte{127, 0, 0, 1, 0x00, 0x50, 1, 1, 1, 1, 0x01, 0xbb}),
output: []Peer{
{IP: net.IP{127, 0, 0, 1}, Port: 80},
{IP: net.IP{1, 1, 1, 1}, Port: 443},
},
},
"not enough bytes in peers": {
input: string([]byte{127, 0, 0, 1, 0x00}),
output: nil,
fails: true,
},
}
for _, test := range tests {
peers, err := Unmarshal([]byte(test.input))
if test.fails {
assert.NotNil(t, err)
} else {
assert.Nil(t, err)
}
assert.Equal(t, test.output, peers)
}
}

View File

@@ -1,16 +1,14 @@
package torrentfile
import (
"encoding/binary"
"fmt"
"net"
"net/http"
"net/url"
"strconv"
"time"
"github.com/veggiedefender/torrent-client/peers"
"github.com/jackpal/bencode-go"
"github.com/veggiedefender/torrent-client/p2p"
)
type bencodeTrackerResp struct {
@@ -18,22 +16,6 @@ type bencodeTrackerResp struct {
Peers string `bencode:"port"`
}
func parsePeers(peersBin string) ([]p2p.Peer, error) {
const peerSize = 6 // 4 for IP, 2 for port
numPeers := len(peersBin) / peerSize
if len(peersBin)%peerSize != 0 {
err := fmt.Errorf("Received malformed peers")
return nil, err
}
peers := make([]p2p.Peer, numPeers)
for i := 0; i < numPeers; i++ {
offset := i * peerSize
peers[i].IP = net.IP(peersBin[offset : offset+4])
peers[i].Port = binary.BigEndian.Uint16([]byte(peersBin[offset+4 : offset+6]))
}
return peers, nil
}
func (t *TorrentFile) buildTrackerURL(peerID [20]byte, port uint16) (string, error) {
base, err := url.Parse(t.Announce)
if err != nil {
@@ -52,7 +34,7 @@ func (t *TorrentFile) buildTrackerURL(peerID [20]byte, port uint16) (string, err
return base.String(), nil
}
func (t *TorrentFile) requestPeers(peerID [20]byte, port uint16) ([]p2p.Peer, error) {
func (t *TorrentFile) requestPeers(peerID [20]byte, port uint16) ([]peers.Peer, error) {
url, err := t.buildTrackerURL(peerID, port)
if err != nil {
return nil, err
@@ -71,7 +53,7 @@ func (t *TorrentFile) requestPeers(peerID [20]byte, port uint16) ([]p2p.Peer, er
return nil, err
}
peers, err := parsePeers(trackerResp.Peers)
peers, err := peers.Unmarshal([]byte(trackerResp.Peers))
if err != nil {
return nil, err
}

View File

@@ -1,11 +1,9 @@
package torrentfile
import (
"net"
"testing"
"github.com/stretchr/testify/assert"
"github.com/veggiedefender/torrent-client/p2p"
)
func TestBuildTrackerURL(t *testing.T) {
@@ -27,34 +25,3 @@ func TestBuildTrackerURL(t *testing.T) {
assert.Nil(t, err)
assert.Equal(t, url, expected)
}
func TestParsePeers(t *testing.T) {
tests := map[string]struct {
input string
output []p2p.Peer
fails bool
}{
"correctly parses peers": {
input: string([]byte{127, 0, 0, 1, 0x00, 0x50, 1, 1, 1, 1, 0x01, 0xbb}),
output: []p2p.Peer{
{IP: net.IP{127, 0, 0, 1}, Port: 80},
{IP: net.IP{1, 1, 1, 1}, Port: 443},
},
},
"not enough bytes in peers": {
input: string([]byte{127, 0, 0, 1, 0x00}),
output: nil,
fails: true,
},
}
for _, test := range tests {
peers, err := parsePeers(test.input)
if test.fails {
assert.NotNil(t, err)
} else {
assert.Nil(t, err)
}
assert.Equal(t, test.output, peers)
}
}