UtMetadata

object UtMetadata

BEP-9 "Extension for Peers to Send Metadata Files" (ut_metadata). This is the pure message codec, ported from libtorrent's ut_metadata.cpp (src/ut_metadata.cpp, ut_metadata_peer_plugin::write_metadata_packet and on_extended).

The metadata that this protocol exchanges is the bencoded info dictionary of a torrent (the same bytes whose SHA-1 is the v1 info-hash). It is sliced into 16 KiB pieces and pulled from peers a piece at a time.

Wire format

An ut_metadata message is the payload of a BEP-10 extended message (id 20) carried under the extension id the remote peer advertised for ut_metadata in its extension handshake. That payload is:

<bencode dict>[<raw 16 KiB metadata piece>]

The bencode dict always has:

  • msg_type: 0 = request, 1 = data, 2 = reject

  • piece: the 0-based 16 KiB piece index

and, for a data message, also:

  • total_size: the total length in bytes of the whole metadata (info) blob.

For a data message the raw bytes of that one piece are appended after the bencode dict (this is why a plain bdecode of the buffer stops at the end of the dict, because the trailing bytes are the payload). libtorrent recovers them with body.subspan(msg.data_section().size()), i.e. everything past the bencoded dict; parse does the same using BdecodeNode.dataSection.

This class is the codec only. The request scheduling and rate limiting that the C++ peer plugin adds lives elsewhere. MetadataTransfer is the small reassembly + verification helper.

Types

Link copied to clipboard
data class Message(val type: UtMetadata.Type, val piece: Int, val totalSize: Long = 0, val data: ByteArray = EMPTY)

A decoded ut_metadata message.

Link copied to clipboard

The msg_type field, the port of the anonymous enum class msg_t : uint8_t in ut_metadata.cpp. The integer values are part of the wire format.

Properties

Link copied to clipboard
const val PIECE_SIZE: Int

Size of one metadata piece, 16 KiB, written as 16 * 1024 in libtorrent.

Functions

Link copied to clipboard
fun encode(type: UtMetadata.Type, piece: Int, totalSize: Long = 0, pieceData: ByteArray = ByteArray(0), includeTotalSize: Boolean = (type == Type.DATA)): ByteArray

General encoder. Builds the {msg_type, piece [, total_size]} dict and, for Type.DATA, appends pieceData after it.

Link copied to clipboard
fun encodeData(piece: Int, totalSize: Long, pieceData: ByteArray): ByteArray

Encode a data message: the bencode dict d8:msg_typei1e5:piecei<n>e10:total_sizei<s>ee, followed by the raw pieceData bytes appended verbatim.

Link copied to clipboard

Encode a reject (dont_have) message: d8:msg_typei2e5:piecei<n>ee.

Link copied to clipboard

Encode a request message: d8:msg_typei0e5:piecei<n>ee.

Link copied to clipboard

Parse a ut_metadata message payload (the body of the extended message, not including the 4-byte length / id-20 / extended-id wire framing).

Link copied to clipboard
fun pieceCount(totalSize: Int): Int

Number of 16 KiB pieces needed to carry a metadata blob of totalSize bytes.

Link copied to clipboard
fun pieceLength(piece: Int, totalSize: Int): Int

The length of metadata piece piece for a blob of totalSize bytes.