Documentation
¶
Overview ¶
Package protocol defines constants for uTP (Micro Transport Protocol) per BEP 29
Package protocol implements uTP (Micro Transport Protocol) per BEP 29 This is a complete implementation of uTP with full congestion control, packet loss handling, selective ACKs, and retransmission logic.
Package protocol implements uTP connection state management per BEP 29 ¶
Package protocol implements uTP (Micro Transport Protocol) per BEP 29.
Index ¶
- Constants
- func AllowedFastSet(k int, numPieces uint32, infoHash [20]byte, ip net.IP) []uint32
- func ClearPiece(bitfield []byte, pieceIndex int)
- func CountPieces(bitfield []byte) int
- func DefaultPeerID() (dht.Key, error)
- func DialContext(ctx context.Context, network, addr string) (net.Conn, error)
- func FetchMetadata(peer net.Addr, infoHash, peerID dht.Key, timeout time.Duration, ...) (*torrent.MetaInfo, error)
- func GeneratePeerID(clientID string, version string) (dht.Key, error)
- func HasPiece(bitfield []byte, pieceIndex int) bool
- func NewBitfield(numPieces int) []byte
- func ParseExtendedMessage(msg *Message) (extID uint8, payload []byte, err error)
- func SetPiece(bitfield []byte, pieceIndex int)
- func WriteMessage(w io.Writer, msg *Message) error
- type AllowedFastMessage
- type BitfieldMessage
- type CancelMessage
- type Conn
- func (c *Conn) Close() error
- func (c *Conn) LocalAddr() net.Addr
- func (c *Conn) Read(b []byte) (int, error)
- func (c *Conn) RemoteAddr() net.Addr
- func (c *Conn) SetDeadline(t time.Time) error
- func (c *Conn) SetReadDeadline(t time.Time) error
- func (c *Conn) SetWriteDeadline(t time.Time) error
- func (c *Conn) Write(b []byte) (n int, err error)
- type Extension
- type ExtensionHandshake
- type Handshake
- type HaveMessage
- type Header
- type Listener
- type Message
- func NewAllowedFastMessage(pieceIndex uint32) *Message
- func NewBitfieldMessage(bitfield []byte) *Message
- func NewCancelMessage(index, begin, length uint32) *Message
- func NewChokeMessage() *Message
- func NewExtendedMessage(extID uint8, payload []byte) *Message
- func NewHaveAllMessage() *Message
- func NewHaveMessage(pieceIndex uint32) *Message
- func NewHaveNoneMessage() *Message
- func NewInterestedMessage() *Message
- func NewNotInterestedMessage() *Message
- func NewPieceMessage(index, begin uint32, block []byte) *Message
- func NewRejectMessage(index, begin, length uint32) *Message
- func NewRequestMessage(index, begin, length uint32) *Message
- func NewSuggestMessage(pieceIndex uint32) *Message
- func NewUnchokeMessage() *Message
- func ReadMessage(r io.Reader, timeout time.Duration) (*Message, error)
- type MetadataExchanger
- type MetadataMessage
- type PieceMessage
- type RejectMessage
- type RequestMessage
- type SelectiveAck
- type State
- func (s *State) AddOutstandingPacket(seqNr uint16, data []byte)
- func (s *State) AdjustWindow(ourDelay uint32)
- func (s *State) CanSend(packetSize uint32) bool
- func (s *State) CheckTimeout() []uint16
- func (s *State) DetectPacketLossViaSeqGap(ackNr uint16, selectiveAcks []byte) []uint16
- func (s *State) GetConnectionIDs() (recvID, sendID uint16)
- func (s *State) GetOutstandingPacket(seqNr uint16) *outstandingPacket
- func (s *State) GetRTTInfo() (rtt, rttVar int64, timeout time.Duration)
- func (s *State) GetState() int
- func (s *State) GetWindowInfo() (maxWindow, curWindow, wndSize uint32)
- func (s *State) IncrementSeqNr() uint16
- func (s *State) MarkPacketResent(seqNr uint16)
- func (s *State) OnPacketLoss()
- func (s *State) ProcessAck(ackNr uint16) []uint16
- func (s *State) ProcessSelectiveAck(selectiveAcks []byte)
- func (s *State) RemoveOutstandingPacket(seqNr uint16)
- func (s *State) ResetTimeout()
- func (s *State) SetConnectionIDs(recvID, sendID uint16)
- func (s *State) SetState(state int)
- func (s *State) UpdateBaseDelay(delay uint32)
- func (s *State) UpdateDelayTracking(timestamp uint32)
- func (s *State) UpdateRTT(packetRTT int64)
- type SuggestMessage
Constants ¶
const ( ST_DATA = 0 // Regular data packet ST_FIN = 1 // Finalize connection ST_STATE = 2 // State packet (ACK only) ST_RESET = 3 // Reset connection ST_SYN = 4 // Connect SYN )
Packet types per BEP 29
const ( EXT_NO_EXTENSION = 0 // No extensions EXT_SELECTIVE_ACK = 1 // Selective ACK extension )
Extension types per BEP 29
const ( CS_IDLE = iota // Connection idle CS_SYN_SENT // SYN sent, waiting for SYN-ACK CS_SYN_RECV // SYN received, sent SYN-ACK CS_CONNECTED // Connected CS_FIN_SENT // FIN sent, waiting for FIN-ACK CS_CLOSED // Connection closed )
Connection states per BEP 29
const ( // Congestion control targets CCONTROL_TARGET = 100 * time.Millisecond // Target delay MAX_CWND_INCREASE_PACKETS_PER_RTT = 3000 // Max window increase per RTT // Packet sizes MIN_WINDOW_SIZE = 150 // Minimum packet size MAX_PACKET_SIZE = 1400 // Maximum data per packet // Timeouts INIT_TIMEOUT = 1000 * time.Millisecond // Initial timeout MIN_TIMEOUT = 500 * time.Millisecond // Minimum timeout // Protocol version UTP_VERSION = 1 )
Constants per BEP 29
const ( MetadataRequest uint8 = 0 MetadataData uint8 = 1 MetadataReject uint8 = 2 )
Metadata message types (BEP 9)
const ( MsgChoke uint8 = 0 // BEP 3: choke — peer will not serve requests MsgUnchoke uint8 = 1 // BEP 3: unchoke — peer will serve requests MsgInterested uint8 = 2 // BEP 3: interested — wants pieces the peer has MsgNotInterested uint8 = 3 // BEP 3: not interested — no longer wants pieces MsgHave uint8 = 4 // BEP 3: have <piece index> — completed & verified a piece MsgBitfield uint8 = 5 // BEP 3: bitfield — sent as first message after handshake MsgRequest uint8 = 6 // BEP 3: request <index><begin><length> — ask for a block MsgPiece uint8 = 7 // BEP 3: piece <index><begin><block> — deliver a block MsgCancel uint8 = 8 // BEP 3: cancel <index><begin><length> — cancel a pending request MsgPort uint8 = 9 // BEP 5: port — advertise DHT listener port MsgSuggest uint8 = 13 // BEP 6: suggest piece MsgHaveAll uint8 = 14 // BEP 6: have all pieces MsgHaveNone uint8 = 15 // BEP 6: have no pieces MsgReject uint8 = 16 // BEP 6: reject request MsgAllowedFast uint8 = 17 // BEP 6: allowed fast piece MsgExtended uint8 = 20 // BEP 10: extension protocol message )
BEP 3 §Peer Messages — message IDs for the peer wire protocol. https://www.bittorrent.org/beps/bep_0003.html
const ( ProtocolString = "BitTorrent protocol" // BEP 3: pstr = "BitTorrent protocol" HandshakeLen = 68 // BEP 3: 1 (pstrlen) + 19 (pstr) + 8 (reserved) + 20 (info_hash) + 20 (peer_id) )
BEP 3 §Handshake — protocol constants.
const (
ExtHandshake uint8 = 0 // BEP 10: extension handshake (ext_id=0, always)
)
BEP 10 §Extension Messages — extension message sub-IDs.
const (
ExtensionBit = 0x100000 // BEP 10: bit 20 from right → reserved[5] & 0x10
)
BEP 10 — extension bits in the 8-byte handshake reserved field.
const MetadataBlockSize = 16384
MetadataBlockSize is the standard block size for metadata exchange (16KB)
const OurMetadataExtID uint8 = 1
OurMetadataExtID is the extension ID we announce for ut_metadata Peers send responses TO US using this ID
Variables ¶
This section is empty.
Functions ¶
func AllowedFastSet ¶
AllowedFastSet computes the canonical allowed fast set per BEP 6.
Algorithm:
x = (ip & 0xFFFFFF00) ++ infohash (24 bytes)
while |a| < k:
x = SHA1(x)
for i in 0..4 and |a| < k:
index = BigEndian(x[i*4 : i*4+4]) % numPieces
if index not in a: add to a
func ClearPiece ¶
ClearPiece clears a piece from the bitfield (BEP 3).
func CountPieces ¶
CountPieces counts the number of pieces set in the bitfield
func DefaultPeerID ¶
DefaultPeerID generates a peer ID with default client identification
func DialContext ¶
DialContext attempts to establish a uTP connection (BEP 29 handshake)
func FetchMetadata ¶
func FetchMetadata(peer net.Addr, infoHash, peerID dht.Key, timeout time.Duration, logger *slog.Logger) (*torrent.MetaInfo, error)
FetchMetadata connects to a peer and fetches metadata for a torrent
func GeneratePeerID ¶
GeneratePeerID creates a unique peer ID following Azureus-style convention Format: -XX0000-<12 random chars>
func NewBitfield ¶
NewBitfield creates a bitfield for the given number of pieces (BEP 3).
func ParseExtendedMessage ¶
ParseExtendedMessage parses an extended message
Types ¶
type AllowedFastMessage ¶
type AllowedFastMessage struct {
PieceIndex uint32
}
AllowedFastMessage declares a piece the choked peer may still request (BEP 6).
func ParseAllowedFastMessage ¶
func ParseAllowedFastMessage(msg *Message) (*AllowedFastMessage, error)
ParseAllowedFastMessage parses a BEP 6 Allowed Fast message.
type BitfieldMessage ¶
type BitfieldMessage struct {
Bitfield []byte // Length must be (num_pieces + 7) / 8 bytes
}
BitfieldMessage represents which pieces the peer has. BEP 3: sent as the very first message after handshake (if peer has any pieces). Each bit represents a piece index (1 = have, 0 = don't have). Bit ordering: high bit of first byte = piece 0, next bit = piece 1, etc.
func ParseBitfieldMessage ¶
func ParseBitfieldMessage(msg *Message) (*BitfieldMessage, error)
ParseBitfieldMessage parses a bitfield message
type CancelMessage ¶
type CancelMessage struct {
Index uint32 // BEP 3: piece index (matches original request)
Begin uint32 // BEP 3: byte offset (matches original request)
Length uint32 // BEP 3: block size (matches original request)
}
CancelMessage cancels a pending request. BEP 3: cancel <index><begin><length> — identical payload format to request. Used during endgame mode when a block arrives from another peer.
func ParseCancelMessage ¶
func ParseCancelMessage(msg *Message) (*CancelMessage, error)
ParseCancelMessage parses a cancel message
type Conn ¶
type Conn struct {
// contains filtered or unexported fields
}
Conn represents a uTP connection. It operates in two modes:
- dialer mode: owns its own UDP socket (recvChan == nil)
- acceptor mode: shares the Listener's socket (recvChan != nil)
func (*Conn) SetDeadline ¶
SetDeadline implements net.Conn
func (*Conn) SetReadDeadline ¶
SetReadDeadline implements net.Conn
func (*Conn) SetWriteDeadline ¶
SetWriteDeadline implements net.Conn
type ExtensionHandshake ¶
type ExtensionHandshake struct {
M map[string]int `bencode:"m"` // BEP 10: dict of extension name → local message ID
P int `bencode:"p,omitempty"` // BEP 10: local TCP listen port
V string `bencode:"v,omitempty"` // BEP 10: client name and version
YourIP string `bencode:"yourip,omitempty"` // BEP 10: compact IP of the remote peer
IPv6 string `bencode:"ipv6,omitempty"` // BEP 10: compact IPv6 address
IPv4 string `bencode:"ipv4,omitempty"` // BEP 10: compact IPv4 address
Reqq int `bencode:"reqq,omitempty"` // BEP 10: max outstanding request hint
MetadataSize int `bencode:"metadata_size,omitempty"` // BEP 9: total size of info dict in bytes
UploadOnly int `bencode:"upload_only,omitempty"` // BEP 21: 1 = partial seed (not downloading)
}
ExtensionHandshake represents the BEP 10 extension handshake. Sent as extended message with ext_id=0 immediately after the BEP 3 handshake.
func NewExtensionHandshake ¶
func NewExtensionHandshake(port int) *ExtensionHandshake
NewExtensionHandshake creates a minimal extension handshake with metadata support. BEP 10: the "m" dict declares the extension IDs THIS peer will use when SENDING. BEP 9: "ut_metadata" enables metadata exchange for magnet link resolution.
func ParseExtensionHandshake ¶
func ParseExtensionHandshake(data []byte) (*ExtensionHandshake, error)
ParseExtensionHandshake parses an extension handshake from bencode
func (*ExtensionHandshake) GetMetadataExtID ¶
func (e *ExtensionHandshake) GetMetadataExtID() (int, bool)
GetMetadataExtID returns the peer's declared extension ID for ut_metadata (BEP 9). This is the ID the PEER will use when sending ut_metadata messages to us.
func (*ExtensionHandshake) HasMetadataSupport ¶
func (e *ExtensionHandshake) HasMetadataSupport() bool
HasMetadataSupport checks if peer supports metadata exchange (BEP 9).
func (*ExtensionHandshake) Serialize ¶
func (e *ExtensionHandshake) Serialize() ([]byte, error)
Serialize encodes the extension handshake to bencode
type Handshake ¶
Handshake represents the BitTorrent handshake
func NewHandshake ¶
NewHandshake creates a handshake with extension protocol support. BEP 3 §Handshake: pstrlen(1) + pstr(19) + reserved(8) + info_hash(20) + peer_id(20) = 68 bytes.
func ReadHandshake ¶
ReadHandshake reads a handshake from a connection
func (*Handshake) SupportsExtensions ¶
SupportsExtensions checks if the peer supports extension protocol (BEP 10).
func (*Handshake) SupportsFast ¶
SupportsFast checks if the peer supports BEP 6 Fast Extension.
type HaveMessage ¶
type HaveMessage struct {
PieceIndex uint32 // BEP 3: zero-based piece index
}
HaveMessage announces that the peer completed and verified a piece. BEP 3: have <piece index> — payload is a single 4-byte big-endian uint32.
func ParseHaveMessage ¶
func ParseHaveMessage(msg *Message) (*HaveMessage, error)
ParseHaveMessage parses a have message
type Header ¶
type Header struct {
Type uint8 // 4 bits: packet type
Version uint8 // 4 bits: protocol version (must be 1)
Extension uint8 // 8 bits: extension type
ConnectionID uint16 // 16 bits: connection identifier
Timestamp uint32 // 32 bits: timestamp in microseconds
TimestampDiff uint32 // 32 bits: timestamp difference
WndSize uint32 // 32 bits: advertised window size
SeqNr uint16 // 16 bits: sequence number
AckNr uint16 // 16 bits: acknowledgment number
Extensions []Extension // Linked list of extensions
}
Header represents uTP packet header per BEP 29 (20 bytes + extensions)
func (*Header) AddSelectiveAck ¶
AddSelectiveAck adds selective ACK extension to header
func (*Header) ParseSelectiveAck ¶
func (h *Header) ParseSelectiveAck() (*SelectiveAck, error)
ParseSelectiveAck parses selective ACK from extensions
type Listener ¶
type Listener struct {
// contains filtered or unexported fields
}
Listener accepts incoming uTP connections on a shared UDP port.
type Message ¶
Message represents a BitTorrent protocol message
func NewAllowedFastMessage ¶
NewAllowedFastMessage creates an Allowed Fast message (BEP 6: msg ID 17, 4-byte index).
func NewBitfieldMessage ¶
NewBitfieldMessage creates a bitfield message
func NewCancelMessage ¶
NewCancelMessage creates a cancel message
func NewExtendedMessage ¶
NewExtendedMessage creates an extended protocol message
func NewHaveAllMessage ¶
func NewHaveAllMessage() *Message
NewHaveAllMessage creates a HaveAll message (BEP 6: msg ID 14, no payload).
func NewHaveMessage ¶
NewHaveMessage creates a have message
func NewHaveNoneMessage ¶
func NewHaveNoneMessage() *Message
NewHaveNoneMessage creates a HaveNone message (BEP 6: msg ID 15, no payload).
func NewInterestedMessage ¶
func NewInterestedMessage() *Message
NewInterestedMessage creates an interested message
func NewNotInterestedMessage ¶
func NewNotInterestedMessage() *Message
NewNotInterestedMessage creates a not interested message
func NewPieceMessage ¶
NewPieceMessage creates a piece message
func NewRejectMessage ¶
NewRejectMessage creates a Reject Request message (BEP 6: msg ID 16, 12-byte payload).
func NewRequestMessage ¶
NewRequestMessage creates a request message
func NewSuggestMessage ¶
NewSuggestMessage creates a Suggest Piece message (BEP 6: msg ID 13, 4-byte index).
func NewUnchokeMessage ¶
func NewUnchokeMessage() *Message
NewUnchokeMessage creates an unchoke message
type MetadataExchanger ¶
type MetadataExchanger struct {
// contains filtered or unexported fields
}
MetadataExchanger handles metadata exchange with a peer
func NewMetadataExchanger ¶
func NewMetadataExchanger(conn net.Conn, infoHash, peerID dht.Key, logger *slog.Logger) *MetadataExchanger
NewMetadataExchanger creates a new metadata exchanger
func (*MetadataExchanger) PerformHandshake ¶
func (m *MetadataExchanger) PerformHandshake(port int) error
PerformHandshake performs the BitTorrent and extension handshakes
func (*MetadataExchanger) RequestMetadata ¶
RequestMetadata requests all metadata blocks from the peer
type MetadataMessage ¶
type MetadataMessage struct {
MsgType uint8 `bencode:"msg_type"`
Piece int `bencode:"piece"`
TotalSize int `bencode:"total_size,omitempty"`
}
MetadataMessage represents a ut_metadata message
type PieceMessage ¶
type PieceMessage struct {
Index uint32 // BEP 3: zero-based piece index
Begin uint32 // BEP 3: byte offset within the piece
Block []byte // BEP 3: raw piece data for this block
}
PieceMessage delivers a block of a piece. BEP 3: piece <index><begin><block> — index and begin are 4-byte big-endian uint32.
func ParsePieceMessage ¶
func ParsePieceMessage(msg *Message) (*PieceMessage, error)
ParsePieceMessage parses a piece message
type RejectMessage ¶
RejectMessage rejects a previously received request (BEP 6).
func ParseRejectMessage ¶
func ParseRejectMessage(msg *Message) (*RejectMessage, error)
ParseRejectMessage parses a BEP 6 Reject Request message.
type RequestMessage ¶
type RequestMessage struct {
Index uint32 // BEP 3: zero-based piece index
Begin uint32 // BEP 3: byte offset within the piece
Length uint32 // BEP 3: block size (typically 16384 bytes)
}
RequestMessage requests a block of a piece. BEP 3: request <index><begin><length> — all fields are 4-byte big-endian uint32. Length is typically 2^14 (16384 = 16 KiB) except for the last block in a piece.
func ParseRequestMessage ¶
func ParseRequestMessage(msg *Message) (*RequestMessage, error)
ParseRequestMessage parses a request message
type SelectiveAck ¶
type SelectiveAck struct {
Bitmask []byte // Bitmask of received packets
}
SelectiveAck represents selective ACK extension
type State ¶
type State struct {
// contains filtered or unexported fields
}
State tracks connection state and all per-connection data
func (*State) AddOutstandingPacket ¶
AddOutstandingPacket tracks a sent packet
func (*State) AdjustWindow ¶
AdjustWindow performs delay-based congestion control per BEP 29
func (*State) CheckTimeout ¶
CheckTimeout checks if any outstanding packets have timed out (BEP 29) Returns list of packets to retransmit
func (*State) DetectPacketLossViaSeqGap ¶
DetectPacketLossViaSeqGap detects packet loss via sequence number gaps (BEP 29) If 3+ packets are ACKed past the oldest unacked packet, it's assumed lost
func (*State) GetConnectionIDs ¶
GetConnectionIDs returns the connection IDs for this connection
func (*State) GetOutstandingPacket ¶
GetOutstandingPacket retrieves a packet for retransmission
func (*State) GetRTTInfo ¶
GetRTTInfo returns RTT information for debugging
func (*State) GetWindowInfo ¶
GetWindowInfo returns current window information for debugging
func (*State) IncrementSeqNr ¶
IncrementSeqNr increments and returns next sequence number
func (*State) MarkPacketResent ¶
MarkPacketResent updates the sent time for a retransmitted packet
func (*State) OnPacketLoss ¶
func (s *State) OnPacketLoss()
OnPacketLoss handles packet loss per BEP 29: multiply max_window by 0.5
func (*State) ProcessAck ¶
ProcessAck processes received ACK and detects duplicate ACKs (BEP 29: packet loss section) Returns list of packets to retransmit if packet loss detected
func (*State) ProcessSelectiveAck ¶
ProcessSelectiveAck processes selective ACK extension
func (*State) RemoveOutstandingPacket ¶
RemoveOutstandingPacket removes an ACKed packet
func (*State) ResetTimeout ¶
func (s *State) ResetTimeout()
ResetTimeout resets timeout counter (BEP 29)
func (*State) SetConnectionIDs ¶
SetConnectionIDs sets the connection IDs during handshake
func (*State) UpdateBaseDelay ¶
UpdateBaseDelay updates sliding minimum delay (BEP 29: base_delay)
func (*State) UpdateDelayTracking ¶
UpdateDelayTracking updates delay measurements for congestion control
type SuggestMessage ¶
type SuggestMessage struct {
PieceIndex uint32
}
SuggestMessage suggests a piece for the peer to download (BEP 6).
func ParseSuggestMessage ¶
func ParseSuggestMessage(msg *Message) (*SuggestMessage, error)
ParseSuggestMessage parses a BEP 6 Suggest Piece message.