Skip to content

3. Session

A session is a player's stay on the server. It starts with a login over TCP, which gives the client a session token; the client then binds its UDP endpoint to the session with that token, and the game runs over UDP. This section specifies the TCP messages and the binding. The framing of TCP messages is in section 1.3, the UDP header in section 2.

3.1 Overview

sequenceDiagram
    participant C as Client
    participant S as Server
    C->>S: TCP connect
    C->>S: LoginRequest (version, name)
    alt accepted
        S->>C: LoginAccepted (token, player, UDP port)
        loop every 250 ms until Accept
            C->>S: UDP Connect (session = token)
        end
        S->>C: UDP Accept
        Note over C,S: game over UDP, TCP stays open and silent
        C->>S: Logout (or TCP close)
    else rejected
        S->>C: LoginRejected (reason)
        S--xC: TCP close
    end

3.2 TCP messages

Every TCP message, inside its length prefix, starts with its kind on one u8; the fields of that kind follow. Fields are encoded as in section 1.4.

Kind Name Direction Fields
1 LoginRequest client → server version (u8), name (string)
2 LoginAccepted server → client session (u32), player (u8), udp_port (u16)
3 LoginRejected server → client reason (u8)
4 Logout both reason (u8)

Kinds 0 and 5 to 255 are reserved.

LoginRequest

The first and only message a client sends to log in.

  • version is the protocol version, the same as in the UDP header: 1.
  • name is the player's name: 1 to 16 bytes of UTF-8, without control characters (code points below 0x20, and 0x7F). It is shown to the other players.

LoginAccepted

The login succeeded: the session exists.

  • session is the session token. The server MUST NOT issue 0, MUST NOT give the same token to two sessions at once, and SHOULD draw it at random, so that a third party cannot guess the token of another player's session.
  • player is the player's number in the game, 0 to 3: it picks the player's ship and color.
  • udp_port is the UDP port of the server, to which the client sends its datagrams.

LoginRejected

The login failed. The server MUST close the connection right after sending it.

reason Name Meaning
1 ServerFull The game already has 4 players
2 BadVersion The server does not speak this version
3 BadName The name is empty, too long, not UTF-8 or has control characters
4 NameTaken Another player of the game has this name
5 GameStarted The game is running and does not take new players

A client MUST treat an unknown reason like any other rejection.

Logout

The sender ends the session; it MUST close the connection right after sending it.

reason Name Sent by Meaning
0 Left client The player quit
1 Shutdown server The server is stopping
2 TimedOut server No valid datagram for too long (section 5.5)
3 ProtocolError server The client sent something invalid over UDP

A receiver MUST treat an unknown reason as Left coming from a client, and as Shutdown coming from the server.

3.3 Rules of the TCP connection

  • The client MUST send LoginRequest as its first message. The server MUST close a connection that sends anything else first, or nothing within 5 seconds of being accepted.
  • After the login, the client MUST NOT send anything but Logout; the server MUST NOT send anything but Logout. A peer MUST close the connection on a second LoginRequest, on a message of an unknown or unexpected kind, or on a malformed message: a field past its end, bytes left after the last field, or an invalid value. A TCP stream cannot be trusted after a bad message, so there is no rejection message in that case.
  • The session ends when either side sends Logout, when the connection closes, or when UDP times out (section 5.5). In every case the server forgets the token, closes the connection if it is still open, and tells the other players (section 4.4).

3.4 Binding the UDP endpoint

Once logged in, the client tells the server which UDP endpoint (address and port) it plays from:

  1. The client sends a Connect datagram (type 1) to udp_port, its session field set to the token and its payload empty. Its sequence starts the numbering of the client's datagrams (section 2.2).
  2. On a Connect whose token belongs to a session with no endpoint yet, the server binds the datagram's source endpoint to the session and answers with an Accept datagram (type 2, empty payload) to that endpoint. Gameplay traffic may then start in both directions.
  3. The client sends Connect again every 250 ms until an Accept arrives. Without an Accept within 5 seconds of LoginAccepted, it gives up: it sends Logout and reports that the server cannot be reached over UDP (a firewall, usually).

The server MUST:

  • drop a Connect whose token is not the one of a current session;
  • answer a Connect again with an Accept when it comes from the endpoint already bound to the session (the first Accept was lost);
  • drop a Connect for a session already bound to another endpoint, so a third party who learned a token cannot take over the session;
  • drop every other datagram whose source endpoint is not bound, or whose token is not the one of the session bound to its endpoint (section 2.2).

The client MUST drop every datagram that does not come from the server's udp_port, or whose token is not its own, and every datagram but Accept before the first Accept.

3.5 Example

A client logs in as R9 and gets session 0xDEADBEEF, player 2, UDP port 4242 (0x1092). Each message is shown with its length prefix:

06 00  01  01  02 00 52 39          LoginRequest
len    kind ver name: len "R9"

08 00  02  EF BE AD DE  02  92 10   LoginAccepted
len    kind session     pl  udp_port

Its first UDP datagram is then a Connect in that session, with sequence 0 and nothing acknowledged yet (section 5.1):

52 54 59 50  01  01  00 00  FF FF  00 00 00 00  EF BE AD DE
magic        ver typ seq    ack    ack_bits     session