Gateway connections - NexusTomorrow/server GitHub Wiki
The login and world connections: the read loop and writer they share, how their keys switch, and what each connection takes and answers. Sign-on is on Gateway sign-on, the checks every message passes on Gateway gate, and how the gateway fits together on Gateway.
A game connection
The login and world connections share one base: a read loop and a single writer.
In
- The read loop takes one frame at a time: a 32-bit length that counts itself, a 16-bit opcode, then the body. A frame shorter than its own header or longer than
MaxClientFrameBytesends the connection, judged before the body arrives. - A transport ping, opcode 0 with a one-byte body, is answered with opcode 1 carrying the same byte.
- Every other frame goes through the gate, then the rate limit, then the connection's handler. The next frame isn't decoded until the handler returns.
Out
- An owner or the connection sends a message; one below
Fieldscan't be sent at all. - It joins the session's bounded outbound queue without waiting. A full queue ends the connection.
- The one writer drains the queue in order, wraps each message in its envelope under the session's current key, and flushes every 64 messages and when the queue empties.
Keys
Keys switch between messages. A key change takes effect on the receive side at once, and on the send side exactly between the messages queued before and after it. Both connections start under the key the build fixes. The world connection switches to the session key as soon as it reads WorldHello (0x058F), so the client's next message, even in the same read, is decoded under the new key.
The two connections
| Connection | Takes | Answers |
|---|---|---|
| Login | A bare ServerHello (0x0003) greeting from the server, then one LoginRequest (0x0592), whose game token it redeems with the account owner |
On a grant, LoginAccepted (0x0591) and RealmHandoff (0x03DB): the world's address and port, an echo value, the realm's details and the session key. A wrong build, a database that's unreachable or too many attempts get LoginDenied (0x063D) with the general result. A second LoginRequest ends the connection |
| World | A greeting inside the world envelope, then WorldHello before anything else, whose session key it switches to and redeems |
Character select's requests, handed to the realm owner. Closing the connection takes the account offline |
Known edges
- A logged-in connection has no idle limit yet.
- The world connection takes pregame rows only; messages the client sends tagged wait for in-world routing (Gateway design).
Where the code lives
| Piece | Path |
|---|---|
| Frames, envelopes and the packet cipher | Source/NexusTomorrow.Transport/ |
| The connection base, its outbound queue, and the login and world connections | Source/NexusTomorrow.Gateway/Connections/ |
| The listeners that hand each connection to its class | Source/NexusTomorrow.Gateway/Kestrel/ |
| Tests | Tests/NexusTomorrow.Transport.Tests/, Tests/NexusTomorrow.Gateway.Tests/ |