22
vendor/github.com/anacrolix/torrent/peer_protocol/compactip.go
generated
vendored
Normal file
22
vendor/github.com/anacrolix/torrent/peer_protocol/compactip.go
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
package peer_protocol
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/anacrolix/torrent/bencode"
|
||||
)
|
||||
|
||||
// Marshals to the smallest compact byte representation.
|
||||
type CompactIp net.IP
|
||||
|
||||
var _ bencode.Marshaler = CompactIp{}
|
||||
|
||||
func (me CompactIp) MarshalBencode() ([]byte, error) {
|
||||
return bencode.Marshal(func() []byte {
|
||||
if ip4 := net.IP(me).To4(); ip4 != nil {
|
||||
return ip4
|
||||
} else {
|
||||
return me
|
||||
}
|
||||
}())
|
||||
}
|
||||
126
vendor/github.com/anacrolix/torrent/peer_protocol/decoder.go
generated
vendored
Normal file
126
vendor/github.com/anacrolix/torrent/peer_protocol/decoder.go
generated
vendored
Normal file
@@ -0,0 +1,126 @@
|
||||
package peer_protocol
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"sync"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type Decoder struct {
|
||||
R *bufio.Reader
|
||||
Pool *sync.Pool
|
||||
MaxLength Integer // TODO: Should this include the length header or not?
|
||||
}
|
||||
|
||||
// io.EOF is returned if the source terminates cleanly on a message boundary.
|
||||
func (d *Decoder) Decode(msg *Message) (err error) {
|
||||
var length Integer
|
||||
err = length.Read(d.R)
|
||||
if err != nil {
|
||||
return fmt.Errorf("reading message length: %w", err)
|
||||
}
|
||||
if length > d.MaxLength {
|
||||
return errors.New("message too long")
|
||||
}
|
||||
if length == 0 {
|
||||
msg.Keepalive = true
|
||||
return
|
||||
}
|
||||
r := d.R
|
||||
readByte := func() (byte, error) {
|
||||
length--
|
||||
return d.R.ReadByte()
|
||||
}
|
||||
c, err := readByte()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
msg.Type = MessageType(c)
|
||||
switch msg.Type {
|
||||
case Choke, Unchoke, Interested, NotInterested, HaveAll, HaveNone:
|
||||
case Have, AllowedFast, Suggest:
|
||||
length -= 4
|
||||
err = msg.Index.Read(r)
|
||||
case Request, Cancel, Reject:
|
||||
for _, data := range []*Integer{&msg.Index, &msg.Begin, &msg.Length} {
|
||||
err = data.Read(r)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
length -= 12
|
||||
case Bitfield:
|
||||
b := make([]byte, length)
|
||||
_, err = io.ReadFull(r, b)
|
||||
length = 0
|
||||
msg.Bitfield = unmarshalBitfield(b)
|
||||
case Piece:
|
||||
for _, pi := range []*Integer{&msg.Index, &msg.Begin} {
|
||||
err := pi.Read(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
length -= 8
|
||||
dataLen := int64(length)
|
||||
msg.Piece = *d.Pool.Get().(*[]byte)
|
||||
if int64(cap(msg.Piece)) < dataLen {
|
||||
return errors.New("piece data longer than expected")
|
||||
}
|
||||
msg.Piece = msg.Piece[:dataLen]
|
||||
_, err := io.ReadFull(r, msg.Piece)
|
||||
if err != nil {
|
||||
return fmt.Errorf("reading piece data: %w", err)
|
||||
}
|
||||
length = 0
|
||||
case Extended:
|
||||
var b byte
|
||||
b, err = readByte()
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
msg.ExtendedID = ExtensionNumber(b)
|
||||
msg.ExtendedPayload = make([]byte, length)
|
||||
_, err = io.ReadFull(r, msg.ExtendedPayload)
|
||||
if err == io.EOF {
|
||||
err = io.ErrUnexpectedEOF
|
||||
}
|
||||
length = 0
|
||||
case Port:
|
||||
err = binary.Read(r, binary.BigEndian, &msg.Port)
|
||||
length -= 2
|
||||
default:
|
||||
err = fmt.Errorf("unknown message type %#v", c)
|
||||
}
|
||||
if err == nil && length != 0 {
|
||||
err = fmt.Errorf("%v unused bytes in message type %v", length, msg.Type)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func readByte(r io.Reader) (b byte, err error) {
|
||||
var arr [1]byte
|
||||
n, err := r.Read(arr[:])
|
||||
b = arr[0]
|
||||
if n == 1 {
|
||||
err = nil
|
||||
return
|
||||
}
|
||||
if err == nil {
|
||||
panic(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func unmarshalBitfield(b []byte) (bf []bool) {
|
||||
for _, c := range b {
|
||||
for i := 7; i >= 0; i-- {
|
||||
bf = append(bf, (c>>uint(i))&1 == 1)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
38
vendor/github.com/anacrolix/torrent/peer_protocol/extended.go
generated
vendored
Normal file
38
vendor/github.com/anacrolix/torrent/peer_protocol/extended.go
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
package peer_protocol
|
||||
|
||||
import (
|
||||
"net"
|
||||
)
|
||||
|
||||
// http://www.bittorrent.org/beps/bep_0010.html
|
||||
type (
|
||||
ExtendedHandshakeMessage struct {
|
||||
M map[ExtensionName]ExtensionNumber `bencode:"m"`
|
||||
V string `bencode:"v,omitempty"`
|
||||
Reqq int `bencode:"reqq,omitempty"`
|
||||
Encryption bool `bencode:"e,omitempty"`
|
||||
// BEP 9
|
||||
MetadataSize int `bencode:"metadata_size,omitempty"`
|
||||
// The local client port. It would be redundant for the receiving side of
|
||||
// a connection to send this.
|
||||
Port int `bencode:"p,omitempty"`
|
||||
YourIp CompactIp `bencode:"yourip,omitempty"`
|
||||
Ipv4 CompactIp `bencode:"ipv4,omitempty"`
|
||||
Ipv6 net.IP `bencode:"ipv6,omitempty"`
|
||||
}
|
||||
|
||||
ExtensionName string
|
||||
ExtensionNumber int
|
||||
)
|
||||
|
||||
const (
|
||||
// http://www.bittorrent.org/beps/bep_0011.html
|
||||
ExtensionNamePex ExtensionName = "ut_pex"
|
||||
|
||||
ExtensionDeleteNumber ExtensionNumber = 0
|
||||
)
|
||||
|
||||
func (me *ExtensionNumber) UnmarshalBinary(b []byte) error {
|
||||
*me = ExtensionNumber(b[0])
|
||||
return nil
|
||||
}
|
||||
147
vendor/github.com/anacrolix/torrent/peer_protocol/handshake.go
generated
vendored
Normal file
147
vendor/github.com/anacrolix/torrent/peer_protocol/handshake.go
generated
vendored
Normal file
@@ -0,0 +1,147 @@
|
||||
package peer_protocol
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"strconv"
|
||||
|
||||
"github.com/anacrolix/torrent/metainfo"
|
||||
)
|
||||
|
||||
type ExtensionBit uint
|
||||
|
||||
const (
|
||||
ExtensionBitDHT = 0 // http://www.bittorrent.org/beps/bep_0005.html
|
||||
ExtensionBitExtended = 20 // http://www.bittorrent.org/beps/bep_0010.html
|
||||
ExtensionBitFast = 2 // http://www.bittorrent.org/beps/bep_0006.html
|
||||
)
|
||||
|
||||
func handshakeWriter(w io.Writer, bb <-chan []byte, done chan<- error) {
|
||||
var err error
|
||||
for b := range bb {
|
||||
_, err = w.Write(b)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
done <- err
|
||||
}
|
||||
|
||||
type (
|
||||
PeerExtensionBits [8]byte
|
||||
)
|
||||
|
||||
func (pex PeerExtensionBits) String() string {
|
||||
return hex.EncodeToString(pex[:])
|
||||
}
|
||||
|
||||
func NewPeerExtensionBytes(bits ...ExtensionBit) (ret PeerExtensionBits) {
|
||||
for _, b := range bits {
|
||||
ret.SetBit(b, true)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (pex PeerExtensionBits) SupportsExtended() bool {
|
||||
return pex.GetBit(ExtensionBitExtended)
|
||||
}
|
||||
|
||||
func (pex PeerExtensionBits) SupportsDHT() bool {
|
||||
return pex.GetBit(ExtensionBitDHT)
|
||||
}
|
||||
|
||||
func (pex PeerExtensionBits) SupportsFast() bool {
|
||||
return pex.GetBit(ExtensionBitFast)
|
||||
}
|
||||
|
||||
func (pex *PeerExtensionBits) SetBit(bit ExtensionBit, on bool) {
|
||||
if on {
|
||||
pex[7-bit/8] |= 1 << (bit % 8)
|
||||
} else {
|
||||
pex[7-bit/8] &^= 1 << (bit % 8)
|
||||
}
|
||||
}
|
||||
|
||||
func (pex PeerExtensionBits) GetBit(bit ExtensionBit) bool {
|
||||
return pex[7-bit/8]&(1<<(bit%8)) != 0
|
||||
}
|
||||
|
||||
type HandshakeResult struct {
|
||||
PeerExtensionBits
|
||||
PeerID [20]byte
|
||||
metainfo.Hash
|
||||
}
|
||||
|
||||
// ih is nil if we expect the peer to declare the InfoHash, such as when the peer initiated the
|
||||
// connection. Returns ok if the Handshake was successful, and err if there was an unexpected
|
||||
// condition other than the peer simply abandoning the Handshake.
|
||||
func Handshake(
|
||||
sock io.ReadWriter, ih *metainfo.Hash, peerID [20]byte, extensions PeerExtensionBits,
|
||||
) (
|
||||
res HandshakeResult, err error,
|
||||
) {
|
||||
// Bytes to be sent to the peer. Should never block the sender.
|
||||
postCh := make(chan []byte, 4)
|
||||
// A single error value sent when the writer completes.
|
||||
writeDone := make(chan error, 1)
|
||||
// Performs writes to the socket and ensures posts don't block.
|
||||
go handshakeWriter(sock, postCh, writeDone)
|
||||
|
||||
defer func() {
|
||||
close(postCh) // Done writing.
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// Wait until writes complete before returning from handshake.
|
||||
err = <-writeDone
|
||||
if err != nil {
|
||||
err = fmt.Errorf("error writing: %w", err)
|
||||
}
|
||||
}()
|
||||
|
||||
post := func(bb []byte) {
|
||||
select {
|
||||
case postCh <- bb:
|
||||
default:
|
||||
panic("mustn't block while posting")
|
||||
}
|
||||
}
|
||||
|
||||
post([]byte(Protocol))
|
||||
post(extensions[:])
|
||||
if ih != nil { // We already know what we want.
|
||||
post(ih[:])
|
||||
post(peerID[:])
|
||||
}
|
||||
var b [68]byte
|
||||
_, err = io.ReadFull(sock, b[:68])
|
||||
if err != nil {
|
||||
return res, fmt.Errorf("while reading: %w", err)
|
||||
}
|
||||
if string(b[:20]) != Protocol {
|
||||
return res, errors.New("unexpected protocol string")
|
||||
}
|
||||
|
||||
copyExact := func(dst, src []byte) {
|
||||
if dstLen, srcLen := uint64(len(dst)), uint64(len(src)); dstLen != srcLen {
|
||||
panic("dst len " + strconv.FormatUint(dstLen, 10) + " != src len " + strconv.FormatUint(srcLen, 10))
|
||||
}
|
||||
copy(dst, src)
|
||||
}
|
||||
copyExact(res.PeerExtensionBits[:], b[20:28])
|
||||
copyExact(res.Hash[:], b[28:48])
|
||||
copyExact(res.PeerID[:], b[48:68])
|
||||
// peerExtensions.Add(res.PeerExtensionBits.String(), 1)
|
||||
|
||||
// TODO: Maybe we can just drop peers here if we're not interested. This
|
||||
// could prevent them trying to reconnect, falsely believing there was
|
||||
// just a problem.
|
||||
if ih == nil { // We were waiting for the peer to tell us what they wanted.
|
||||
post(res.Hash[:])
|
||||
post(peerID[:])
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
43
vendor/github.com/anacrolix/torrent/peer_protocol/int.go
generated
vendored
Normal file
43
vendor/github.com/anacrolix/torrent/peer_protocol/int.go
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
package peer_protocol
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"io"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type Integer uint32
|
||||
|
||||
func (i *Integer) UnmarshalBinary(b []byte) error {
|
||||
if len(b) != 4 {
|
||||
return errors.New("expected 4 bytes")
|
||||
}
|
||||
*i = Integer(binary.BigEndian.Uint32(b))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *Integer) Read(r io.Reader) error {
|
||||
var b [4]byte
|
||||
n, err := io.ReadFull(r, b[:])
|
||||
if err == nil {
|
||||
if n != 4 {
|
||||
panic(n)
|
||||
}
|
||||
return i.UnmarshalBinary(b[:])
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// It's perfectly fine to cast these to an int. TODO: Or is it?
|
||||
func (i Integer) Int() int {
|
||||
return int(i)
|
||||
}
|
||||
|
||||
func (i Integer) Uint64() uint64 {
|
||||
return uint64(i)
|
||||
}
|
||||
|
||||
func (i Integer) Uint32() uint32 {
|
||||
return uint32(i)
|
||||
}
|
||||
30
vendor/github.com/anacrolix/torrent/peer_protocol/messagetype_string.go
generated
vendored
Normal file
30
vendor/github.com/anacrolix/torrent/peer_protocol/messagetype_string.go
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
// Code generated by "stringer -type=MessageType"; DO NOT EDIT.
|
||||
|
||||
package peer_protocol
|
||||
|
||||
import "strconv"
|
||||
|
||||
const (
|
||||
_MessageType_name_0 = "ChokeUnchokeInterestedNotInterestedHaveBitfieldRequestPieceCancelPort"
|
||||
_MessageType_name_1 = "SuggestHaveAllHaveNoneRejectAllowedFast"
|
||||
_MessageType_name_2 = "Extended"
|
||||
)
|
||||
|
||||
var (
|
||||
_MessageType_index_0 = [...]uint8{0, 5, 12, 22, 35, 39, 47, 54, 59, 65, 69}
|
||||
_MessageType_index_1 = [...]uint8{0, 7, 14, 22, 28, 39}
|
||||
)
|
||||
|
||||
func (i MessageType) String() string {
|
||||
switch {
|
||||
case i <= 9:
|
||||
return _MessageType_name_0[_MessageType_index_0[i]:_MessageType_index_0[i+1]]
|
||||
case 13 <= i && i <= 17:
|
||||
i -= 13
|
||||
return _MessageType_name_1[_MessageType_index_1[i]:_MessageType_index_1[i+1]]
|
||||
case i == 20:
|
||||
return _MessageType_name_2
|
||||
default:
|
||||
return "MessageType(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
}
|
||||
42
vendor/github.com/anacrolix/torrent/peer_protocol/metadata.go
generated
vendored
Normal file
42
vendor/github.com/anacrolix/torrent/peer_protocol/metadata.go
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
package peer_protocol
|
||||
|
||||
import (
|
||||
"github.com/anacrolix/torrent/bencode"
|
||||
)
|
||||
|
||||
const (
|
||||
// http://bittorrent.org/beps/bep_0009.html. Note that there's an
|
||||
// LT_metadata, but I've never implemented it.
|
||||
ExtensionNameMetadata = "ut_metadata"
|
||||
)
|
||||
|
||||
type (
|
||||
ExtendedMetadataRequestMsg struct {
|
||||
Piece int `bencode:"piece"`
|
||||
TotalSize int `bencode:"total_size"`
|
||||
Type ExtendedMetadataRequestMsgType `bencode:"msg_type"`
|
||||
}
|
||||
|
||||
ExtendedMetadataRequestMsgType int
|
||||
)
|
||||
|
||||
func MetadataExtensionRequestMsg(peerMetadataExtensionId ExtensionNumber, piece int) Message {
|
||||
return Message{
|
||||
Type: Extended,
|
||||
ExtendedID: peerMetadataExtensionId,
|
||||
ExtendedPayload: bencode.MustMarshal(ExtendedMetadataRequestMsg{
|
||||
Piece: piece,
|
||||
Type: RequestMetadataExtensionMsgType,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the expected piece size for this request message. This is needed to determine the offset
|
||||
// into an extension message payload that the request metadata piece data starts.
|
||||
func (me ExtendedMetadataRequestMsg) PieceSize() int {
|
||||
ret := me.TotalSize - me.Piece*(1<<14)
|
||||
if ret > 1<<14 {
|
||||
ret = 1 << 14
|
||||
}
|
||||
return ret
|
||||
}
|
||||
139
vendor/github.com/anacrolix/torrent/peer_protocol/msg.go
generated
vendored
Normal file
139
vendor/github.com/anacrolix/torrent/peer_protocol/msg.go
generated
vendored
Normal file
@@ -0,0 +1,139 @@
|
||||
package peer_protocol
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// This is a lazy union representing all the possible fields for messages. Go doesn't have ADTs, and
|
||||
// I didn't choose to use type-assertions.
|
||||
type Message struct {
|
||||
Keepalive bool
|
||||
Type MessageType
|
||||
Index, Begin, Length Integer
|
||||
Piece []byte
|
||||
Bitfield []bool
|
||||
ExtendedID ExtensionNumber
|
||||
ExtendedPayload []byte
|
||||
Port uint16
|
||||
}
|
||||
|
||||
var _ interface {
|
||||
encoding.BinaryUnmarshaler
|
||||
encoding.BinaryMarshaler
|
||||
} = (*Message)(nil)
|
||||
|
||||
func MakeCancelMessage(piece, offset, length Integer) Message {
|
||||
return Message{
|
||||
Type: Cancel,
|
||||
Index: piece,
|
||||
Begin: offset,
|
||||
Length: length,
|
||||
}
|
||||
}
|
||||
|
||||
func (msg Message) RequestSpec() (ret RequestSpec) {
|
||||
return RequestSpec{
|
||||
msg.Index,
|
||||
msg.Begin,
|
||||
func() Integer {
|
||||
if msg.Type == Piece {
|
||||
return Integer(len(msg.Piece))
|
||||
} else {
|
||||
return msg.Length
|
||||
}
|
||||
}(),
|
||||
}
|
||||
}
|
||||
|
||||
func (msg Message) MustMarshalBinary() []byte {
|
||||
b, err := msg.MarshalBinary()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func (msg Message) MarshalBinary() (data []byte, err error) {
|
||||
var buf bytes.Buffer
|
||||
if !msg.Keepalive {
|
||||
err = buf.WriteByte(byte(msg.Type))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
switch msg.Type {
|
||||
case Choke, Unchoke, Interested, NotInterested, HaveAll, HaveNone:
|
||||
case Have:
|
||||
err = binary.Write(&buf, binary.BigEndian, msg.Index)
|
||||
case Request, Cancel, Reject:
|
||||
for _, i := range []Integer{msg.Index, msg.Begin, msg.Length} {
|
||||
err = binary.Write(&buf, binary.BigEndian, i)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
case Bitfield:
|
||||
_, err = buf.Write(marshalBitfield(msg.Bitfield))
|
||||
case Piece:
|
||||
for _, i := range []Integer{msg.Index, msg.Begin} {
|
||||
err = binary.Write(&buf, binary.BigEndian, i)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
n, err := buf.Write(msg.Piece)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
if n != len(msg.Piece) {
|
||||
panic(n)
|
||||
}
|
||||
case Extended:
|
||||
err = buf.WriteByte(byte(msg.ExtendedID))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_, err = buf.Write(msg.ExtendedPayload)
|
||||
case Port:
|
||||
err = binary.Write(&buf, binary.BigEndian, msg.Port)
|
||||
default:
|
||||
err = fmt.Errorf("unknown message type: %v", msg.Type)
|
||||
}
|
||||
}
|
||||
data = make([]byte, 4+buf.Len())
|
||||
binary.BigEndian.PutUint32(data, uint32(buf.Len()))
|
||||
if buf.Len() != copy(data[4:], buf.Bytes()) {
|
||||
panic("bad copy")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func marshalBitfield(bf []bool) (b []byte) {
|
||||
b = make([]byte, (len(bf)+7)/8)
|
||||
for i, have := range bf {
|
||||
if !have {
|
||||
continue
|
||||
}
|
||||
c := b[i/8]
|
||||
c |= 1 << uint(7-i%8)
|
||||
b[i/8] = c
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (me *Message) UnmarshalBinary(b []byte) error {
|
||||
d := Decoder{
|
||||
R: bufio.NewReader(bytes.NewReader(b)),
|
||||
}
|
||||
err := d.Decode(me)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if d.R.Buffered() != 0 {
|
||||
return fmt.Errorf("%d trailing bytes", d.R.Buffered())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
47
vendor/github.com/anacrolix/torrent/peer_protocol/pex.go
generated
vendored
Normal file
47
vendor/github.com/anacrolix/torrent/peer_protocol/pex.go
generated
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
package peer_protocol
|
||||
|
||||
import (
|
||||
"github.com/anacrolix/dht/v2/krpc"
|
||||
"github.com/anacrolix/torrent/bencode"
|
||||
)
|
||||
|
||||
type PexMsg struct {
|
||||
Added krpc.CompactIPv4NodeAddrs `bencode:"added"`
|
||||
AddedFlags []PexPeerFlags `bencode:"added.f"`
|
||||
Added6 krpc.CompactIPv6NodeAddrs `bencode:"added6"`
|
||||
Added6Flags []PexPeerFlags `bencode:"added6.f"`
|
||||
Dropped krpc.CompactIPv4NodeAddrs `bencode:"dropped"`
|
||||
Dropped6 krpc.CompactIPv6NodeAddrs `bencode:"dropped6"`
|
||||
}
|
||||
|
||||
func (m *PexMsg) Len() int {
|
||||
return len(m.Added) + len(m.Added6) + len(m.Dropped) + len(m.Dropped6)
|
||||
}
|
||||
|
||||
func (m *PexMsg) Message(pexExtendedId ExtensionNumber) Message {
|
||||
payload := bencode.MustMarshal(m)
|
||||
return Message{
|
||||
Type: Extended,
|
||||
ExtendedID: pexExtendedId,
|
||||
ExtendedPayload: payload,
|
||||
}
|
||||
}
|
||||
|
||||
func LoadPexMsg(b []byte) (ret PexMsg, err error) {
|
||||
err = bencode.Unmarshal(b, &ret)
|
||||
return
|
||||
}
|
||||
|
||||
type PexPeerFlags byte
|
||||
|
||||
func (me PexPeerFlags) Get(f PexPeerFlags) bool {
|
||||
return me&f == f
|
||||
}
|
||||
|
||||
const (
|
||||
PexPrefersEncryption PexPeerFlags = 1 << iota
|
||||
PexSeedUploadOnly
|
||||
PexSupportsUtp
|
||||
PexHolepunchSupport
|
||||
PexOutgoingConn
|
||||
)
|
||||
52
vendor/github.com/anacrolix/torrent/peer_protocol/protocol.go
generated
vendored
Normal file
52
vendor/github.com/anacrolix/torrent/peer_protocol/protocol.go
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
package peer_protocol
|
||||
|
||||
const (
|
||||
Protocol = "\x13BitTorrent protocol"
|
||||
)
|
||||
|
||||
type MessageType byte
|
||||
|
||||
//go:generate stringer -type=MessageType
|
||||
|
||||
func (mt MessageType) FastExtension() bool {
|
||||
return mt >= Suggest && mt <= AllowedFast
|
||||
}
|
||||
|
||||
func (mt *MessageType) UnmarshalBinary(b []byte) error {
|
||||
*mt = MessageType(b[0])
|
||||
return nil
|
||||
}
|
||||
|
||||
const (
|
||||
// BEP 3
|
||||
Choke MessageType = 0
|
||||
Unchoke MessageType = 1
|
||||
Interested MessageType = 2
|
||||
NotInterested MessageType = 3
|
||||
Have MessageType = 4
|
||||
Bitfield MessageType = 5
|
||||
Request MessageType = 6
|
||||
Piece MessageType = 7
|
||||
Cancel MessageType = 8
|
||||
|
||||
// BEP 5
|
||||
Port MessageType = 9
|
||||
|
||||
// BEP 6 - Fast extension
|
||||
Suggest MessageType = 0x0d // 13
|
||||
HaveAll MessageType = 0x0e // 14
|
||||
HaveNone MessageType = 0x0f // 15
|
||||
Reject MessageType = 0x10 // 16
|
||||
AllowedFast MessageType = 0x11 // 17
|
||||
|
||||
// BEP 10
|
||||
Extended MessageType = 20
|
||||
)
|
||||
|
||||
const (
|
||||
HandshakeExtendedID = 0
|
||||
|
||||
RequestMetadataExtensionMsgType ExtendedMetadataRequestMsgType = 0
|
||||
DataMetadataExtensionMsgType ExtendedMetadataRequestMsgType = 1
|
||||
RejectMetadataExtensionMsgType ExtendedMetadataRequestMsgType = 2
|
||||
)
|
||||
11
vendor/github.com/anacrolix/torrent/peer_protocol/reqspec.go
generated
vendored
Normal file
11
vendor/github.com/anacrolix/torrent/peer_protocol/reqspec.go
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
package peer_protocol
|
||||
|
||||
import "fmt"
|
||||
|
||||
type RequestSpec struct {
|
||||
Index, Begin, Length Integer
|
||||
}
|
||||
|
||||
func (me RequestSpec) String() string {
|
||||
return fmt.Sprintf("{%d %d %d}", me.Index, me.Begin, me.Length)
|
||||
}
|
||||
Reference in New Issue
Block a user