Logging in: from the launcher to character select

Architecture walkthrough, part 1 of 5

Walkthrough contents Part 1 of 5
  1. Overview
  2. Logging in: from the launcher to character select
  3. The wire: from bytes to packets to actions
  4. Into the world: zones, entities and movement
  5. Fighting: spells, creatures, loot and quests
  6. Behind the scenes: data, database, events and the website

When a player starts WildStar and types their email and password, the client talks to three servers, one after the other. Each one checks what the previous one handed out and passes the player on. This page follows that path up to the moment the player picks a character.

From launch to the world: who says what A sequence diagram with four columns: the client, the login server (port 6600), the realm server (port 23115) and the world server (port 24000). With the login server: the client sends LoginStart with its email; the server answers with a salt and its SRP6 value B; the client sends KeyData with its value A and proof M1; the server answers with proof M2 and from then on the conversation is encrypted with RC4; the client sends LoginFinish and RequestGameToken and receives a single-use game token. With the realm server: the client sends ClientHelloAuth with its email and the game token; the server answers with ServerRealmInfo carrying the world server's address and a new session key. With the world server: the client sends ClientHelloRealm with the session key, asks for its character list and receives it, selects a character, receives ServerChangeWorld telling it which map to load, and finally sends ClientEnteredWorld. WildStar client Login (STS) port 6600 Realm server port 23115 World server port 24000 LoginStart: email salt and B (SRP6) KeyData: A and proof M1 proof M2; RC4 from here on LoginFinish, RequestGameToken game token (single use) ClientHelloAuth: email, game token ServerRealmInfo: world address, session key ClientHelloRealm: session key ClientCharacterList ServerCharacterList ClientCharacterSelect ServerChangeWorld: load this map ClientEnteredWorld

1. The login server (STS)

The first server the client calls is the login server, bezgelor_auth, on port 6600. WildStar's login protocol is called STS. It doesn't look like the rest of the game's protocol: its messages read like web requests, a line such as POST /Auth/LoginStart STS/1.0, a few headers and an XML body. BezgelorAuth.Sts.Packet (apps/bezgelor_auth/lib/bezgelor_auth/sts/packet.ex) reads and writes them.

Each login gets its own process, BezgelorAuth.Sts.Connection, started by Ranch (the library that accepts network connections) for every client that connects. BezgelorAuth.Sts.Handler routes each message by its path:

  1. /Auth/LoginStart: the client sends the email. AuthHandler looks the account up (BezgelorDb.Accounts.get_by_email), checks it isn't suspended, and answers with the values the client needs for the key exchange.
  2. /Auth/KeyData: the client proves it knows the password without ever sending it. This is SRP6, in BezgelorCrypto.SRP6: both sides compute the same secret key from the password's verifier and random numbers they exchange, and each proves to the other that it has it. From here on the conversation is encrypted with RC4 (BezgelorCrypto.RC4), keyed with that secret.
  3. /Auth/LoginFinish: if the account has two-step verification on, BezgelorAuth.Sts.TwoStep asks the client to show its code keypad and checks the code (BezgelorDb.TwoFactor).
  4. /Auth/RequestGameToken: the server makes a random game token, stores it with the account (Accounts.update_game_token) and sends it to the client.

BezgelorAuth.Sts.Session keeps track of how far a login has got (connected, login started, keys exchanged, authenticated), so a message that arrives out of order is refused. The client leaves the login server with one thing: the game token.

2. The realm server

Next the client connects to the realm server, bezgelor_realm, on port 23115. From here on the client speaks WildStar's binary protocol, which The wire explains. The realm app itself is tiny: apps/bezgelor_realm/lib/bezgelor_realm/application.ex starts a listener, and everything else is shared code in bezgelor_protocol, the same code the world server uses.

The client sends ClientHelloAuth with its email and the game token. BezgelorProtocol.Handler.RealmAuthHandler (apps/bezgelor_protocol/lib/bezgelor_protocol/handler/realm_auth_handler.ex):

  1. checks that the client is the build we support (16042, the final live client);
  2. redeems the game token (Accounts.consume_game_token): it works once, and only for a couple of minutes;
  3. checks the account isn't suspended;
  4. makes a new random session key and stores it with the account;
  5. answers with ServerAuthAccepted, any login notices (ServerRealmMessages), and ServerRealmInfo, which carries the world server's address and port and the session key.

ServerRealmInfo is the hand-off: the client disconnects from the realm server and connects to the address it was given.

3. The world server, before the world

The world server, bezgelor_world, listens on port 24000. Its first job is the character screens, before any zone is involved. These handlers also live in apps/bezgelor_protocol/lib/bezgelor_protocol/handler/:

The client sends Handler What happens
ClientHelloRealm (with the session key) WorldAuthHandler Checks the key against the account (Accounts.validate_session_key_with_account) and switches the connection's encryption to a key made from it. Nothing is sent back.
ClientCharacterList CharacterListHandler Sends the account's currencies, unlocks and entitlements, then ServerCharacterList.
ClientCharacterCreate CharacterCreateHandler Looks up the chosen template (race, class, sex, faction) in the client's own CharacterCreation table, checks the name and the slot limit, and creates the character (BezgelorDb.Characters).
ClientCharacterDelete CharacterDeleteHandler Deletes a character.
ClientRealmList, ClientRealmSelect RealmListHandler, RealmSelectHandler The "change realm" screen.
ClientCharacterSelect CharacterSelectHandler Checks the character belongs to the account and starts entering the world.

Selecting a character sends ServerChangeWorld, which tells the client which map to load, together with everything the client needs to draw the player: the player's own entity, stats, spells and more. That burst is built by BezgelorProtocol.MapEntry (map_entry.ex), which is also used for every teleport. While the map loads, the client shows its loading screen; when it is done it sends ClientEnteredWorld, and the player is in a zone. Into the world picks up from there.

Where the accounts live

Accounts, game tokens, session keys and suspensions are rows in PostgreSQL, behind the BezgelorDb.Accounts context (apps/bezgelor_db/lib/bezgelor_db/accounts.ex). Players create accounts on the website, which stores an SRP6 verifier made by BezgelorCrypto.Password, never the password itself.

Where to look

  • apps/bezgelor_auth/lib/bezgelor_auth/sts/: the login server (connection.ex, handler.ex, session.ex, two_step.ex).
  • apps/bezgelor_crypto/lib/bezgelor_crypto/: srp6.ex, rc4.ex, packet_crypt.ex, password.ex, totp.ex.
  • apps/bezgelor_protocol/lib/bezgelor_protocol/handler/realm_auth_handler.ex and world_auth_handler.ex: the two hand-offs.
  • apps/bezgelor_protocol/lib/bezgelor_protocol/packets/realm/: the realm server's packets.
  • config/config.exs: the ports and the address the realm server sends to clients.

Next: The wire.