DhtNode

class DhtNode(socket: DatagramTransport, nodeId: Sha1Hash, scope: CoroutineScope, val routingTable: RoutingTable = RoutingTable(nodeId, K_BUCKET), val storage: DhtStorage = DhtStorage(), tokens: DhtTokens = DhtTokens(), clock: () -> Long = { 0L }, enforceNodeId: Boolean = false, readOnly: Boolean = false, random: Random = Random.Default)

A live Kademlia DHT node (BEP-5). This is the networked half of the DHT. It wires the pure RoutingTable, DhtMessage, DhtStorage and DhtItem types to a UDP socket via DhtRpc and TraversalState. Port of dht::node, dht_tracker and the find_data and get_peers traversal algorithms.

Drives the two things a client actually needs from the DHT: trackerless peer discovery (getPeers) and re-announcing ourselves (announce); plus it answers inbound queries so we are a good citizen of the network.

Parameters

clock

supplies epoch-seconds for storage expiry and token rotation. The core is clockless, so the platform passes one in ({ System.currentTimeMillis()/1000 }).

Constructors

Link copied to clipboard
constructor(socket: DatagramTransport, nodeId: Sha1Hash, scope: CoroutineScope, routingTable: RoutingTable = RoutingTable(nodeId, K_BUCKET), storage: DhtStorage = DhtStorage(), tokens: DhtTokens = DhtTokens(), clock: () -> Long = { 0L }, enforceNodeId: Boolean = false, readOnly: Boolean = false, random: Random = Random.Default)

Types

Link copied to clipboard
object Companion
Link copied to clipboard
class GetItemResult(val item: DhtItem?, val closestWithTokens: List<Pair<CompactNode, ByteArray>>, val observedSeq: Long?)

Result of getItem: the best item found (or null), the closest token-bearing nodes, and observedSeq, the highest mutable sequence number seen across responders. Use that as the cas value for a following mutable putItem. It is null if nothing was found.

Link copied to clipboard
class GetPeersResult(val peers: List<DhtEndpoint>, val closestWithTokens: List<Pair<CompactNode, ByteArray>>)

Peers found for an info-hash, plus the closest responders + their write tokens (for announce).

Link copied to clipboard
class SampleResult(val infohashes: List<Sha1Hash>, val nodes: List<CompactNode>, val num: Int, val interval: Int)

Result of a BEP-51 sample_infohashes query.

Properties

Link copied to clipboard

Our own node id (m_id). Mutable so enableSecureId can re-derive it from our IP.

Link copied to clipboard
Link copied to clipboard

Functions

Link copied to clipboard
suspend fun announce(infoHash: Sha1Hash, port: Int)

Announce that we are a peer for infoHash on port to the closest nodes that gave us a token.

Link copied to clipboard
suspend fun bootstrap(routers: List<Pair<String, Int>>)

Ping the router nodes, pull their neighbours, then self-lookup to fill the table.

Link copied to clipboard
fun enableSecureId(externalIp: String, enforce: Boolean = true)

Re-derive our node id from our observed external IP per BEP-42 and (optionally) turn on the enforceNodeId admission gate. The engine calls this once it learns our external address (e.g. from a router's ip reply or the platform). The routing table is rebuilt around the new id (RoutingTable.updateNodeId).

Link copied to clipboard
suspend fun getItem(target: Sha1Hash, mutableSeq: Long? = null, maxRounds: Int = 12): DhtNode.GetItemResult

Fetch a BEP-44 item from the DHT. This is the client port of node::get_item and its traversal. Runs a get traversal toward target, merging closer nodes from each reply, and returns the best item found (the highest-seq verified mutable item, or the immutable item) together with the closest responders and their write tokens (so a follow-up putItem can re-publish without a second lookup).

Link copied to clipboard
suspend fun getPeers(infoHash: Sha1Hash, maxRounds: Int = 12): DhtNode.GetPeersResult

Iterative get_peers traversal toward infoHash; returns the swarm peers it found.

Link copied to clipboard
suspend fun maintain()

Periodic upkeep: the session-layer port of node::tick and dht_tracker's timers. Call on a steady cadence (libtorrent ticks the refresh timer every 5 s and the storage/token timers on slower multiples; ~30 s is a sensible single cadence here):

Link copied to clipboard
suspend fun putItem(item: DhtItem): Int

Store a BEP-44 item in the DHT. This is the client port of node::put_item. It runs a get→(optional cas)→put: a getItem traversal locates the closest nodes and their write tokens, then a put is fired to each. For a mutable item, the discovered highest stored sequence number is supplied as cas so a concurrent writer can't be silently clobbered (libtorrent's compare-and-swap). Returns the number of nodes the put was accepted by (a non-error reply).

Link copied to clipboard
suspend fun reannounce(infoHashes: Iterable<Sha1Hash>, port: Int)

Re-announce ourselves as a peer for every info-hash in infoHashes on port. A session calls this on its DHT announce interval, roughly every 15 minutes. It loops over announce. Each announce is independent, so one failure does not stop the others.

Link copied to clipboard

Restore known nodes from a serialize blob, re-seeding the routing table (they're added un-pinged via RoutingTable.heardAbout; the next lookup confirms them). The node id is not changed here. The constructor and enableSecureId own id continuity. The saved id is returned, so a caller can reconstruct with it.

Link copied to clipboard
suspend fun sampleInfohashes(host: String, port: Int, target: Sha1Hash = generateRandomId(random)): DhtNode.SampleResult?

BEP-51 client: ask host:port for a sample of the info-hashes it tracks. Returns the decoded sample (20-byte info-hashes) plus the closest nodes it pointed us at, or null on timeout/parse failure. This is the querier half; most callers only need it for DHT-wide content indexing.

Link copied to clipboard

Serialize the node id and the live routing-table nodes into a bencoded blob the platform can persist and pass back to restore on the next start. This is the KiteTorrent analogue of libtorrent's dht_state save (save_state, dht_settings). Only the id and (host, port) of every live node is kept; ids are re-confirmed on the next bootstrap, so a stale node simply fails to answer and is dropped.

Link copied to clipboard
fun setReadOnly(enabled: Boolean)

Turn BEP-43 read-only mode on/off at runtime (dht_read_only).

Link copied to clipboard
fun start(): Job

Start the inbound receive loop. Responses are routed to RPC waiters; queries are answered.

Link copied to clipboard
suspend fun tick()

Alias for maintain, named to match DhtStorage.tick and DhtTokens.