# How Bitchat Android Handles Message Routing and TTL in Its Mesh Network

> Explore how Bitchat Android manages message routing and TTL in its mesh network. Discover hop-by-hop TTL enforcement and source-route hints for efficient packet delivery.

- Repository: [permissionlesstech/bitchat-android](https://github.com/permissionlesstech/bitchat-android)
- Tags: internals
- Published: 2026-07-28

---

**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`](https://github.com/permissionlesstech/bitchat-android/blob/main/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`](https://github.com/permissionlesstech/bitchat-android/blob/main/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`](https://github.com/permissionlesstech/bitchat-android/blob/main/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:

```kotlin
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`](https://github.com/permissionlesstech/bitchat-android/blob/main/MessageHandler.kt) utilize the constant TTL for reliable delivery:

```kotlin
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`](https://github.com/permissionlesstech/bitchat-android/blob/main/MessageHandler.kt).

### Handshake Responses with Hop Limits

Noise protocol handshake responses follow the same TTL semantics:

```kotlin
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`](https://github.com/permissionlesstech/bitchat-android/blob/main/MessageHandler.kt), this ensures cryptographic handshakes propagate with the same reliability guarantees as standard messages.

## Summary

- **TTL Enforcement**: `PacketRelayManager` drops packets with `ttl == 0` and 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 while `SYNC_TTL_HOPS` (0) isolates synchronization traffic to direct neighbors.
- **Protocol Separation**: TTL values are excluded from cryptographic signatures in [`BinaryProtocol.kt`](https://github.com/permissionlesstech/bitchat-android/blob/main/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.