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

96 lines
1.8 KiB
Go
Raw Normal View History

2019-12-22 17:43:39 -05:00
package p2p
import (
"net"
"strconv"
2019-12-24 13:23:46 -05:00
"time"
2019-12-22 23:51:31 -05:00
2019-12-24 10:39:22 -05:00
"github.com/veggiedefender/torrent-client/handshake"
2019-12-22 17:43:39 -05:00
)
2019-12-22 22:25:57 -05:00
// Peer encodes connection information for a peer
2019-12-22 17:43:39 -05:00
type Peer struct {
IP net.IP
Port uint16
}
2019-12-24 13:23:46 -05:00
// Download holds data required to download a torrent from a list of peers
type Download struct {
2019-12-22 23:51:31 -05:00
Peers []Peer
PeerID [20]byte
InfoHash [20]byte
PieceHashes [][20]byte
Length int
2019-12-22 22:25:57 -05:00
}
2019-12-22 17:43:39 -05:00
2019-12-24 13:23:46 -05:00
type peerState struct {
peer *Peer
conn net.Conn
}
2019-12-22 23:51:31 -05:00
2019-12-24 13:23:46 -05:00
type swarm struct {
peerStates []*peerState
2019-12-22 22:25:57 -05:00
}
2019-12-22 17:43:39 -05:00
2019-12-22 23:51:31 -05:00
func (p *Peer) connect(peerID [20]byte, infoHash [20]byte) (net.Conn, error) {
2019-12-22 22:25:57 -05:00
hostPort := net.JoinHostPort(p.IP.String(), strconv.Itoa(int(p.Port)))
2019-12-24 13:23:46 -05:00
conn, err := net.DialTimeout("tcp", hostPort, 3*time.Second)
2019-12-22 17:43:39 -05:00
if err != nil {
2019-12-22 22:25:57 -05:00
return nil, err
2019-12-22 17:43:39 -05:00
}
2019-12-22 22:25:57 -05:00
return conn, nil
2019-12-22 17:43:39 -05:00
}
2019-12-22 23:51:31 -05:00
2019-12-24 13:23:46 -05:00
func (d *Download) handshake(conn net.Conn) (*handshake.Handshake, error) {
conn.SetDeadline(time.Now().Local().Add(3 * time.Second))
2019-12-24 11:05:22 -05:00
req := handshake.New(d.InfoHash, d.PeerID)
2019-12-22 23:51:31 -05:00
_, err := conn.Write(req.Serialize())
if err != nil {
return nil, err
}
2019-12-24 10:39:22 -05:00
res, err := handshake.Read(conn)
2019-12-22 23:51:31 -05:00
if err != nil {
return nil, err
}
2019-12-24 13:23:46 -05:00
conn.SetDeadline(time.Time{}) // Disable the deadline
2019-12-22 23:51:31 -05:00
return res, nil
}
2019-12-24 13:23:46 -05:00
func (d *Download) initPeer(p *Peer, c chan *peerState) {
conn, err := p.connect(d.PeerID, d.InfoHash)
if err != nil {
c <- nil
return
}
_, err = d.handshake(conn)
if err != nil {
c <- nil
return
}
c <- &peerState{p, conn}
}
func (d *Download) startSwarm() *swarm {
c := make(chan *peerState)
for i := range d.Peers {
go d.initPeer(&d.Peers[i], c)
}
peerStates := make([]*peerState, 0)
for range d.Peers {
ps := <-c
if ps != nil {
peerStates = append(peerStates, ps)
}
}
return &swarm{peerStates}
}
// Download downloads a torrent
func (d *Download) Download() error {
d.startSwarm()
return nil
}