mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-25 07:05:20 +00:00
- New protocol types ping=0x26 / pong=0x27 (9-byte payload: 8-byte nonce + origin TTL) with per-peer inbound rate limiting (5 per 10s) - /ping @name reports RTT and hop count, 10s timeout - /trace @name prints the estimated path from gossiped directNeighbors - Topology map sheet (circular Canvas layout) reachable from App Info - Ping/pong ride the deterministic directed-relay path like DMs - Tests: payload round-trip, hop-count math, command output, edge normalization, layout Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
58 lines
2.1 KiB
Swift
58 lines
2.1 KiB
Swift
//
|
|
// MeshPingPayload.swift
|
|
// BitFoundation
|
|
//
|
|
// This is free and unencumbered software released into the public domain.
|
|
// For more information, see <https://unlicense.org>
|
|
//
|
|
|
|
import struct Foundation.Data
|
|
|
|
/// Wire payload shared by the `ping` (0x26) and `pong` (0x27) message types.
|
|
///
|
|
/// Layout (9 bytes):
|
|
/// - 8 bytes: random nonce (a pong echoes the nonce of the ping it answers)
|
|
/// - 1 byte: origin TTL — the TTL the packet was launched with, so the
|
|
/// receiver can compute the hop count as `originTTL - receivedTTL`.
|
|
///
|
|
/// Both directions are unencrypted and unsigned: the payload carries no
|
|
/// private data, and the unguessable nonce already binds a pong to a probe
|
|
/// the local device actually sent.
|
|
public struct MeshPingPayload: Equatable {
|
|
public static let nonceLength = 8
|
|
private static let encodedLength = nonceLength + 1
|
|
|
|
public let nonce: Data
|
|
public let originTTL: UInt8
|
|
|
|
public init?(nonce: Data, originTTL: UInt8) {
|
|
guard nonce.count == Self.nonceLength else { return nil }
|
|
self.nonce = nonce
|
|
self.originTTL = originTTL
|
|
}
|
|
|
|
public func encode() -> Data {
|
|
var data = Data(capacity: Self.encodedLength)
|
|
data.append(nonce)
|
|
data.append(originTTL)
|
|
return data
|
|
}
|
|
|
|
/// Accepts payloads with trailing bytes so future revisions can extend
|
|
/// the format without breaking older clients.
|
|
public static func decode(_ data: Data) -> MeshPingPayload? {
|
|
guard data.count >= encodedLength else { return nil }
|
|
let nonce = Data(data.prefix(nonceLength))
|
|
let originTTL = data[data.index(data.startIndex, offsetBy: nonceLength)]
|
|
return MeshPingPayload(nonce: nonce, originTTL: originTTL)
|
|
}
|
|
|
|
/// Number of links a packet crossed, derived from TTL decrements plus the
|
|
/// final delivery link (a directly connected peer is 1 hop away).
|
|
/// Returns nil when the TTLs are inconsistent (received above origin).
|
|
public static func hopCount(originTTL: UInt8, receivedTTL: UInt8) -> Int? {
|
|
guard originTTL >= receivedTTL else { return nil }
|
|
return Int(originTTL - receivedTTL) + 1
|
|
}
|
|
}
|