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

135 lines
2.9 KiB
Go
Raw Normal View History

2019-12-26 17:04:32 -05:00
package p2p
import (
2019-12-26 21:53:11 -05:00
"bufio"
"encoding/binary"
2019-12-26 17:04:32 -05:00
"fmt"
"net"
"strconv"
"time"
"github.com/veggiedefender/torrent-client/message"
"github.com/veggiedefender/torrent-client/handshake"
)
type client struct {
2019-12-26 21:53:11 -05:00
peer Peer
infoHash [20]byte
peerID [20]byte
2019-12-26 17:04:32 -05:00
conn net.Conn
2019-12-26 21:53:11 -05:00
reader *bufio.Reader
2019-12-26 17:04:32 -05:00
bitfield message.Bitfield
2019-12-26 21:53:11 -05:00
choked bool
engaged bool
2019-12-26 17:04:32 -05:00
}
2019-12-26 21:53:11 -05:00
func completeHandshake(conn net.Conn, r *bufio.Reader, infohash, peerID [20]byte) (*handshake.Handshake, error) {
2019-12-26 17:04:32 -05:00
conn.SetDeadline(time.Now().Local().Add(3 * time.Second))
defer conn.SetDeadline(time.Time{}) // Disable the deadline
req := handshake.New(infohash, peerID)
_, err := conn.Write(req.Serialize())
if err != nil {
return nil, err
}
2019-12-26 21:53:11 -05:00
res, err := handshake.Read(r)
2019-12-26 17:04:32 -05:00
if err != nil {
return nil, err
}
return res, nil
}
2019-12-26 21:53:11 -05:00
func recvBitfield(conn net.Conn, r *bufio.Reader) (message.Bitfield, error) {
2019-12-26 17:04:32 -05:00
conn.SetDeadline(time.Now().Local().Add(5 * time.Second))
defer conn.SetDeadline(time.Time{}) // Disable the deadline
2019-12-26 21:53:11 -05:00
msg, err := message.Read(r)
2019-12-26 17:04:32 -05:00
if err != nil {
return nil, err
}
if msg.ID != message.MsgBitfield {
err := fmt.Errorf("Expected bitfield but got ID %d", msg.ID)
return nil, err
}
return msg.Payload, nil
}
func newClient(peer 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 {
return nil, err
}
2019-12-26 21:53:11 -05:00
reader := bufio.NewReader(conn)
_, err = completeHandshake(conn, reader, infoHash, peerID)
2019-12-26 17:04:32 -05:00
if err != nil {
return nil, err
}
2019-12-26 21:53:11 -05:00
bf, err := recvBitfield(conn, reader)
2019-12-26 17:04:32 -05:00
if err != nil {
return nil, err
}
2019-12-26 21:53:11 -05:00
2019-12-26 17:04:32 -05:00
return &client{
2019-12-26 21:53:11 -05:00
peer: peer,
infoHash: infoHash,
peerID: peerID,
2019-12-26 17:04:32 -05:00
conn: conn,
2019-12-26 21:53:11 -05:00
reader: reader,
2019-12-26 17:04:32 -05:00
bitfield: bf,
2019-12-26 21:53:11 -05:00
choked: true,
engaged: false,
2019-12-26 17:04:32 -05:00
}, nil
}
func (c *client) hasPiece(index int) bool {
return c.bitfield.HasPiece(index)
}
2019-12-26 21:53:11 -05:00
func (c *client) hasNext() bool {
fmt.Println(c.reader.Buffered() > 0)
return c.reader.Buffered() > 0
}
func (c *client) read() (*message.Message, error) {
msg, err := message.Read(c.reader)
return msg, err
}
func (c *client) request(index, begin, length int) error {
req := message.FormatRequest(index, begin, length)
_, err := c.conn.Write(req.Serialize())
return err
}
func (c *client) interested() error {
msg := message.Message{ID: message.MsgInterested}
_, err := c.conn.Write(msg.Serialize())
return err
}
func (c *client) notInterested() error {
msg := message.Message{ID: message.MsgNotInterested}
_, err := c.conn.Write(msg.Serialize())
return err
}
func (c *client) unchoke() error {
msg := message.Message{ID: message.MsgUnchoke}
_, err := c.conn.Write(msg.Serialize())
return err
}
func (c *client) have(index int) error {
pl := make([]byte, 4)
binary.BigEndian.PutUint32(pl, uint32(index))
msg := message.Message{ID: message.MsgHave, Payload: pl}
_, err := c.conn.Write(msg.Serialize())
return err
}