Bancho Binary Protocol Implementation
Relevant source files
The following files were used as context for generating this wiki page:
The Bancho Binary Protocol implementation in Athena provides a compatibility layer for stable osu! clients. It handles the parsing, building, and routing of binary packets over HTTP, enabling features such as authentication, chat, and real-time presence updates. The implementation relies on the caterpillar-py library for declarative binary structure modeling and follows a little-endian byte order for all multi-byte fields.
Sources: README.md:5-13, AGENTS.md:144-150, src/osu_server/transports/stable/bancho/protocol/types.py:12-25
Architecture and Data Flow
The Bancho transport is structured as a hexagonal adapter within the modular monolith. It consists of three primary layers: the HTTP boundary (Endpoint), the Workflow layer (Login/Polling), and the Protocol layer (Binary modeling).
Workflow Execution Flow
When a stable client interacts with the server, the BanchoEndpoint determines the appropriate workflow based on the presence of an osu-token header.
The endpoint acts as the primary entry point for stable client binary communication.
Sources: src/osu_server/transports/stable/bancho/endpoint.py:46-73, README.md:73-77
Protocol Type System
Athena utilizes a specialized type system to handle the osu! proprietary binary formats. These types are implemented using the caterpillar library to ensure memory safety and strictly defined serialization boundaries.
Core Wire Types
| Type | Description | Structure |
|---|---|---|
| BanchoString | Proprietary string encoding | 0x00 (empty) or 0x0B + ULEB128 Length + UTF-8 Data |
| IntList | Length-prefixed integer array | uint16 count + int32[] values |
| Message | Chat message structure | sender, content, target (Strings) + sender_id (int32) |
| Channel | Chat channel metadata | name, topic (Strings) + user_count (int16) |
| StatusUpdate | Player status metadata | status, mods, play_mode, beatmap_id, etc. |
Sources: src/osu_server/transports/stable/bancho/protocol/types.py:101-149, tests/unit/transports/bancho/protocol/test_types.py:15-20
Variable Length Encoding (ULEB128)
For strings longer than 127 bytes, the protocol uses ULEB128 encoding for the length field. This allows the length to occupy multiple bytes where the most significant bit of each byte indicates if another byte follows.
def _write_uleb128(stream: BytesIO, value: int) -> None:
"""Encode *value* as ULEB128 and write to *stream*."""
while value > _ULEB128_VALUE_MASK:
_ = stream.write(bytes([value & _ULEB128_VALUE_MASK | 0x80]))
value >>= 7
_ = stream.write(bytes([value]))
Sources: src/osu_server/transports/stable/bancho/protocol/types.py:82-87, tests/unit/transports/bancho/protocol/test_types.py:48-52
Endpoint Handling
The BanchoEndpoint class manages the lifecycle of a Bancho session. It is responsible for injecting specific response headers required by the client, such as cho-token and cho-protocol.
Request/Response Specifications
- HTTP Method:
POST - Target:
/(configured via Starlette routes) - Headers:
osu-token: Used to identify active sessions.cho-token: Returned during login to be used in subsequentosu-tokenheaders.cho-protocol: Indicates the protocol version (currently 19).
Sources: src/osu_server/transports/stable/bancho/endpoint.py:65-73, tests/unit/transports/bancho/test_endpoint.py:86-105
Configuration and Constraints
The protocol implementation is governed by several application-level constraints defined in AppConfig to prevent resource exhaustion and ensure stability.
| Configuration Field | Type | Default | Description |
|---|---|---|---|
packet_queue_max_size | int | 4096 | Max packets held in Valkey queue per session |
max_request_body_size | int | 1,048,576 | Max size for binary POST bodies |
session_ttl | int | 300 | Seconds before a volatile session expires |
bancho_bot_username | str | "BanchoBot" | Name used in system messages |
Sources: src/osu_server/config.py:44-55, AGENTS.md:156-158
Implementation Rules for Developers
Developers extending the protocol must follow these strict guidelines:
- No Manual Slicing: Packet handlers must not use
struct.unpackor manual byte slicing; all definitions must usecaterpillarstructs. - Separate Enums:
ClientPacketIDandServerPacketIDmust be maintained in separate enums despite sharing some numeric values. - Transport Isolation: The
transports/stable/banchopackage must not import details fromlazeror other transport families. - Registration: New packets require a definition in the protocol package and registration via a decorator in the handler layer.
Sources: AGENTS.md:148-154, src/osu_server/transports/stable/bancho/protocol/types.py:93-99, pyproject.toml:193-197
Summary
The Bancho Binary Protocol implementation provides the necessary infrastructure for Athena to support legacy osu!stable clients. By leveraging the caterpillar library for type-safe binary modeling and strictly separating transport-specific mapping from core domain logic, the system maintains high compatibility while allowing the internal architecture to evolve independently. All volatile states, including packet queues and session metadata, are stored in Valkey to support horizontal scalability.
Sources: README.md:43-52, AGENTS.md:156-158