How Bitchat Android Handles Message Routing and TTL in Its Mesh Network
Bitchat Android uses a centralized PacketRelayManager to enforce hop-by-hop TTL limits, decrementing packet counters on every relay while supporting optional source-route hints for deterministic path selection.
The permissionlesstech/bitchat-android repository implements a robust mesh networking layer designed to balance message propagation reach with device resource constraints. Understanding how this system manages message routing and TTL (time-to-live) is essential for developers building decentralized communication protocols that prevent network flooding while ensuring reliable multi-hop delivery across Android devices.
TTL Enforcement in PacketRelayManager
The core routing logic resides in app/src/main/java/com/bitchat/android/mesh/PacketRelayManager.kt, where incoming packets undergo strict TTL validation before forwarding.
Dropping Expired Packets
When handlePacketRelay() receives a packet not addressed to the local peer, it immediately checks the ttl field. If the value equals 0, the manager discards the packet with a TTL expired status, preventing infinite circulation of stale messages. This check occurs at lines 58-63 of the relay manager implementation.
Hop Count Decrement Logic
For packets with remaining TTL, the manager creates a copy with ttl - 1 before forwarding. This decrement operation ensures the mesh network tracks hop distance accurately, limiting propagation to a finite number of relay steps as implemented at lines 64-66.
Source-Route Processing and Loop Prevention
Beyond basic flooding, Bitchat Android supports explicit source routing for deterministic message delivery through the mesh.
Explicit Route List Handling
When a packet contains a route list, the manager searches for the local peer identifier within that sequence. If found, it forwards the packet directly to the next hop or final recipient, as detailed in lines 68-88. This allows senders to specify exact paths through the mesh rather than relying solely on broadcast flooding.
Duplicate Hop Detection
To prevent routing loops, the implementation rejects packets containing duplicate entries in the route list. This validation occurs at lines 71-75, ensuring that packets cannot cycle through the same node multiple times via explicit routes.
Adaptive Relay Decision Making
After TTL decrement, PacketRelayManager applies an intelligent forwarding strategy to optimize network resources. The system uses a configurable probability that scales with current network size, where high-TTL packets receive unconditional relay privileges. This probabilistic approach, implemented in lines 34-62, reduces bandwidth consumption while maintaining connectivity in sparse network topologies.
TTL Configuration Constants
The mesh layer distinguishes between user message traffic and protocol synchronization through distinct TTL constants defined in app/src/main/java/com/bitchat/android/util/AppConstants.kt.
Standard Message TTL
All application-generated packets, including delivery acknowledgments and Noise handshake responses, initialize with MESSAGE_TTL_HOPS set to 7 hops. This default, stored in AppConstants.kt at lines 10-11, provides sufficient budget for multi-hop propagation while preventing excessive network load.
Sync Packet Isolation
Synchronization traffic uses SYNC_TTL_HOPS set to 0, ensuring that GossipSyncManager requests propagate only to immediate neighbors. This isolation prevents sync storms from saturating the network, as these packets are never relayed beyond the direct connection, as defined at lines 11-12.
Implementation Examples
The following patterns demonstrate practical usage of the TTL system within the Bitchat Android codebase.
Relaying Incoming Packets
When processing received mesh traffic, the relay manager handles TTL enforcement automatically:
suspend fun demoRelay(manager: PacketRelayManager, routed: RoutedPacket) {
// manager automatically drops TTL-0 packets,
// decrements TTL, attempts source-routing, then broadcasts if allowed.
manager.handlePacketRelay(routed)
}
The handlePacketRelay() method encapsulates the TTL check, decrement, and routing logic described above.
Creating Messages with Default TTL
Outbound messages in MessageHandler.kt utilize the constant TTL for reliable delivery:
val ack = BitchatPacket(
version = 1u,
type = MessageType.NOISE_ENCRYPTED.value,
senderID = hexStringToByteArray(myPeerID),
recipientID = hexStringToByteArray(senderPeerID),
timestamp = System.currentTimeMillis().toULong(),
payload = encryptedAckPayload,
signature = null,
ttl = AppConstants.MESSAGE_TTL_HOPS // 7 hops
)
delegate.sendPacket(ack)
This pattern mirrors the ACK generation at lines 46-48 of MessageHandler.kt.
Handshake Responses with Hop Limits
Noise protocol handshake responses follow the same TTL semantics:
val response = BitchatPacket(
version = 1u,
type = MessageType.NOISE_HANDSHAKE.value,
senderID = hexStringToByteArray(myPeerID),
recipientID = hexStringToByteArray(peerID),
timestamp = System.currentTimeMillis().toULong(),
payload = handshakeReply,
signature = null,
ttl = AppConstants.MESSAGE_TTL_HOPS // 7 hops
)
delegate.sendPacket(response)
As implemented at lines 79-80 of MessageHandler.kt, this ensures cryptographic handshakes propagate with the same reliability guarantees as standard messages.
Summary
- TTL Enforcement:
PacketRelayManagerdrops packets withttl == 0and decrements valid packets before forwarding at lines 58-66. - Source Routing: Explicit route lists enable deterministic path selection, with duplicate detection preventing loops at lines 71-75.
- Adaptive Flooding: Configurable broadcast probability scales with network size to optimize resource usage at lines 34-62.
- Configuration Constants:
MESSAGE_TTL_HOPS(7) controls message propagation whileSYNC_TTL_HOPS(0) isolates synchronization traffic to direct neighbors. - Protocol Separation: TTL values are excluded from cryptographic signatures in
BinaryProtocol.kt, allowing hop count modification during relay without invalidating message authenticity.
Frequently Asked Questions
How does Bitchat Android prevent infinite message flooding in the mesh?
The system uses a hop-count TTL mechanism where every packet starts with a limited number of hops (default 7). Each relay node decrements the counter and drops packets when TTL reaches zero, physically limiting the propagation radius regardless of network topology.
What is the difference between standard messages and sync packets in terms of TTL?
Standard messages use MESSAGE_TTL_HOPS set to 7, allowing multi-hop propagation across the mesh, while sync packets use SYNC_TTL_HOPS set to 0, restricting them to immediate neighbors only. This isolation prevents synchronization storms from overwhelming the network.
Can packets follow specific paths rather than broadcasting to all neighbors?
Yes. When a route list is present in the packet, PacketRelayManager processes it as a source-routed packet, forwarding only to the specified next hop. This enables deterministic routing when the sender knows the topology, while duplicate detection prevents routing loops.
Why is the TTL excluded from the signed payload in BinaryProtocol.kt?
Excluding TTL from the cryptographic signature allows relay nodes to modify the hop count without invalidating the message signature. This design enables decentralized TTL enforcement while maintaining end-to-end authenticity for the actual message content.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →