1
0
mirror of https://github.com/veggiedefender/torrent-client.git synced 2025-11-06 09:29:16 +02:00
Files
torrent-client/handshake/handshake.go
2019-12-26 21:53:11 -05:00

71 lines
1.4 KiB
Go

package handshake
import (
"bufio"
"errors"
"io"
)
// A Handshake is a sequence of bytes a peer uses to identify itself
type Handshake struct {
Pstr string
InfoHash [20]byte
PeerID [20]byte
}
// New creates a new handshake with the standard pstr
func New(infoHash, peerID [20]byte) *Handshake {
return &Handshake{
Pstr: "BitTorrent protocol",
InfoHash: infoHash,
PeerID: peerID,
}
}
// Serialize serializes the handshake to a buffer
func (h *Handshake) Serialize() []byte {
pstrlen := len(h.Pstr)
bufLen := 49 + pstrlen
buf := make([]byte, bufLen)
buf[0] = byte(pstrlen)
copy(buf[1:], h.Pstr)
// Leave 8 reserved bytes
copy(buf[1+pstrlen+8:], h.InfoHash[:])
copy(buf[1+pstrlen+8+20:], h.PeerID[:])
return buf
}
// Read parses a message from a stream. Returns `nil` on keep-alive message
func Read(r *bufio.Reader) (*Handshake, error) {
lengthBuf := make([]byte, 1)
_, err := io.ReadFull(r, lengthBuf)
if err != nil {
return nil, err
}
pstrlen := int(lengthBuf[0])
if pstrlen == 0 {
err := errors.New("pstrlen cannot be 0")
return nil, err
}
handshakeBuf := make([]byte, 48+pstrlen)
_, err = io.ReadFull(r, handshakeBuf)
if err != nil {
return nil, err
}
var infoHash, peerID [20]byte
copy(infoHash[:], handshakeBuf[pstrlen+8:pstrlen+8+20])
copy(peerID[:], handshakeBuf[pstrlen+8+20:])
h := Handshake{
Pstr: string(handshakeBuf[0:pstrlen]),
InfoHash: infoHash,
PeerID: peerID,
}
return &h, nil
}