PeerMessage

sealed class PeerMessage

One message of the BitTorrent peer wire protocol. This is the pure-Kotlin port of the write_* senders and on_* parsers in bt_peer_connection.cpp, plus the message id enum bt_peer_connection::message_type (include/libtorrent/bt_peer_connection.hpp).

Every non-keepalive message on the wire is length-prefixed:

<4-byte big-endian length N><1-byte message id><N-1 bytes payload>

A keep-alive is the degenerate case N == 0: just four zero bytes, no id, no body (write_keepalive() sends {0,0,0,0}).

The message set spans three specs:

  • BEP-3: choke, unchoke, interested, not-interested, have, bitfield, request, piece, cancel.

  • BEP-5: the DHT port message.

  • BEP-6 Fast extension: suggest, have-all, have-none, reject-request, allowed-fast.

  • BEP-10: the extension-protocol extended carrier message.

encode returns the full frame including the 4-byte length prefix, ready to write to a socket. Decoding is split: PeerMessage.decode parses ONE already-deframed body (id byte + payload, the length prefix already stripped), while PeerMessage.tryReadMessage does length-prefixed stream framing.

Inheritors

Types

Link copied to clipboard
data class AllowedFast(val piece: Int) : PeerMessage

allowed_fast (id 17, BEP-6): the receiver may request piece even while choked.

Link copied to clipboard
data class Bitfield(val bitfield: Bitfield) : PeerMessage

bitfield (id 5): the complete set of pieces the sender has. The payload is the bitfield's raw bytes (MSB-first, exactly Bitfield.data()).

Link copied to clipboard
data class Cancel(val piece: Int, val begin: Int, val length: Int) : PeerMessage

cancel (id 8): cancel a previously sent Request. Same body as request.

Link copied to clipboard

choke (id 0): sender will not honour the receiver's requests.

Link copied to clipboard
object Companion
Link copied to clipboard
data class Extended(val extId: Int, val payload: ByteArray) : PeerMessage

extended (id 20, BEP-10): the extension-protocol carrier. extId is the single-byte extended message id (0 = the extension handshake), followed by an opaque (usually bencoded) payload. On the wire: [len][20][uint8 extId][payload], len = payload.size + 2.

Link copied to clipboard
data class Hashes(val piecesRoot: ByteArray, val baseLayer: Int, val index: Int, val length: Int, val proofLayers: Int, val hashes: List<ByteArray>) : PeerMessage

hashes (id 22, BEP-52): the response to a HashRequest, carrying the requested range of 32-byte SHA-256 Merkle hashes. The payload is the same 48-byte header as HashRequest followed by N concatenated 32-byte hashes. On the wire: [len=49+32*N][22][header][hash...]. Mirrors write_hashes / on_hashes.

Link copied to clipboard
data class HashReject(val piecesRoot: ByteArray, val baseLayer: Int, val index: Int, val length: Int, val proofLayers: Int) : PeerMessage

hash_reject (id 23, BEP-52): refuse a HashRequest. The payload is the identical 48-byte header as HashRequest, with no trailing hashes. On the wire: [len=49][23][header]. Mirrors write_hash_reject / on_hash_reject.

Link copied to clipboard
data class HashRequest(val piecesRoot: ByteArray, val baseLayer: Int, val index: Int, val length: Int, val proofLayers: Int) : PeerMessage

hash_request (id 21, BEP-52): ask the peer for a range of v2 Merkle-tree hashes. The payload is a fixed 48-byte header: [pieces_root 32 bytes][int32 base][int32 index][int32 length][int32 proof_layers]. On the wire: [len=49][21][header]. Mirrors write_hash_request / on_hash_request in bt_peer_connection.cpp (the C++ hash_request carries file/base/index/count/proof_layers; the file is identified on the wire by its pieces_root, and count is named length here).

Link copied to clipboard
data class Have(val piece: Int) : PeerMessage

have (id 4): the sender now has piece piece.

Link copied to clipboard

have_all (id 14, BEP-6): the sender has every piece (a seed).

Link copied to clipboard

have_none (id 15, BEP-6): the sender has no pieces.

Link copied to clipboard

interested (id 2): sender wants to request pieces.

Link copied to clipboard

Keep-alive: four zero bytes, length 0, no id, no payload.

Link copied to clipboard

not_interested (id 3): sender no longer wants to request pieces.

Link copied to clipboard
data class Piece(val piece: Int, val begin: Int, val block: ByteArray) : PeerMessage

piece (id 7): a block of data, block bytes at begin within piece. On the wire: [len][7][int32 piece][int32 begin][raw block], len = block.size + 9.

Link copied to clipboard
data class Port(val port: Int) : PeerMessage

port (id 9, BEP-5): the sender's DHT UDP port. On the wire the port is a 16-bit big-endian value (write_dht_port emits {0,0,0,3, 9, hi, lo}).

Link copied to clipboard
data class RejectRequest(val piece: Int, val begin: Int, val length: Int) : PeerMessage

reject_request (id 16, BEP-6): refuse a Request. Same body as request.

Link copied to clipboard
data class Request(val piece: Int, val begin: Int, val length: Int) : PeerMessage

request (id 6): ask for length bytes at begin within piece.

Link copied to clipboard
data class Suggest(val piece: Int) : PeerMessage

suggest (id 13, BEP-6): a hint that the receiver may want piece.

Link copied to clipboard

unchoke (id 1): sender will now honour the receiver's requests.

Link copied to clipboard
data class Unknown(val id: Int, val payload: ByteArray) : PeerMessage

A frame whose message id is not one this codec recognises. libtorrent would route this to a peer-plugin or drop the connection; we surface it so the caller can decide. id is the raw id byte, payload is everything after it.

Properties

Link copied to clipboard
abstract val id: Int

The numeric message id, or -1 for KeepAlive (which has no id byte on the wire). Matches bt_peer_connection::message_type.

Functions

Link copied to clipboard
abstract fun encode(): ByteArray

The full on-the-wire frame: 4-byte big-endian length prefix + id + payload.