Transport & connections

Connections

Environments

The Scalable Server exists in two separate environments:

  • staging

  • production

The staging environment allows to test a game. Note that the staging environment is sharing the user datastore with the production environment, which means that game history, rankings, etc are common to both environments.

All developers are sharing the same staging environment, but every developer have their own production environment (created by request to the Asmodee.net administrators).

Before a client can connect to a staging or production environment, the developer must have created its game identifier in the Asmodee.net Studio Manager, and contacted the Asmodee.net Administrators to obtain the connection information to the staging environment.

Before the developer’s game enters in beta stage, the developer needs to contact the Asmodee.net Administrators again to obtain a production environment. The developer will then receive the correct hostname and public key pinning parameters.

This procedure will soon be automated through the Asmodee.net Studio Manager.

Connecting to an Environment

The Client connects to the Scalable Server with a TLS (1.0+) TCP connection (preferably TLSv1.2 or better).

The client doesn’t authenticate to the server with a certificate (it is an anonymous client), but the player authenticates herself to the server (see authentication).

The client might choose to keep the connection open as much as possible, in this case it should send Ping requests so that the server can detect connection issues (in return the Client receives Ping responses, which also can help detect connection issues), and compute presence information for the given player.

In the event a player is not connected and the Scalable Server needs to inform her of an important event (like an invitation, or if it’s this player’s turn in a game), the Scalable Server will send a cross-platform push notification to all devices that this player connected with, provided the developer gives the necessary push certificates to the Asmodee.net Administrators.

A connection is valid for a Player and a given Game.

TLS Public Key Pinning

To be noted that the production and staging Scalable Server present a self-signed certificate to the Client. Clients are supposed to validate the server certificate public key with a procedure called Public Key Pinning.

This is a counter-cheating measure that prevents Man in the Middle attacks where the attacker puts a proxy between the client and the server and is able to decrypt/modify the traffic because the client might not check the server is whom it pretends to be.

To prevent this, the client must check that the server offered certificate public key is the correct one. It should also check that the CN part of the certificate DN is the one that it connected to (each developer have a different one).

To check that the public key is correct, the client extracts the public key of the certificate presented by the server, and computes a SHA256 hash of it.

The hash should match one of this checksum (valid for the staging environment, the production one will be given to the developer):

Primary:

25:5c:20:0e:ae:6c:55:e1:a7:a9:f8:eb:7b:93:3c:ad:3b:98:18:7c:75:28:cc:10:5d:42:48:9e:55:ca:a3:cc

Backup:

1d:34:65:b4:70:9d:29:e8:22:53:a8:a2:7c:fc:5a:00:1e:9e:9b:72:3a:a8:02:00:4f:f8:6c:4e:d2:c0:4e:d8

If the presented public key checksum doesn’t match any of those hash, the client must drop the connection and possibly inform the user that something went wrong.

TLS Troubleshooting

The Scalable Server listens on the TCP port 2445. You can check that your own network allows to connect to our staging Scalable Server with the following command:

openssl s_client -host staging-async-games.daysofwonder.com -port 2445

This should print the certificate chain and the various TLS parameters that were used.

If you want to check your client code can connect to a TLS server, you can emulate the Scalable Server with the following command:

openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -nodes -days 3650
openssl s_server -no_ssl3 -accept 2445 -key key.pem -cert cert.pem

Then point your client to this fake server to be able to troubleshoot the TLS connection.

On the wire transport protocol

Both the client to server and server to client communications use the same transport protocol.

The Scalable Server transport protocol is a message based protocol, where client and server exchange messages. Most of the time, the message flow obey a request/response kind of protocol. Sometimes the server might send messages to a client on its own.

The messages are described and serialized/deserialized on the wire with Protocol Buffers (v3) which is an efficient, cross-platform, maintainable system.

Length Delimited Packets

The messages are sent over the TLS connection as size-delimited fragments.

The size of the fragment is serialized in RFC1700 network order also called Big Endian, that is the most significant bits will be serialized first, and the last significant bit will be serialized last.

For example, if the payload size is 498 bytes, the size will be serialized to the following byte string:

00 00 01 f2

After this size, we’ll find the serialized payload.

Protobuf matriochkas

The Protocol defines several Protobuf messages, but those are not sent verbatim on the wire. They are encapsulated in two different more generic protobuf structures.

Message

Each request is encapsulated into a Protobuf oneof field of Message

message Message {
      int32 request_number = 1; /// id of the underlying request
      oneof request {
              PingRequest ping_request = 777; /// 777

              com.daysofwonder.async.AsyncAuthRequest async_auth_request = 400; /// 400
              com.daysofwonder.async.GameCreatedRequest game_created_request = 404; /// 404
      [...]
  }
}

Let’s imagine we’re serializing a Ping request which is defined as this:

message PingRequest {
  int64 timestamp = 1;
}

Then the request_number will be 777. When serializing, we’ll get the following (shown as Protobuf decoded text):

{
   request_number: 777
   ping_request {
     timestamp: 12343344456
   }
}

The complete definition of the syntax is available on the Protobuf proto3 page.

Note

The wire format is compatible between Protobuf 2 and Protobuf 3. Any client serializing/deserializing the protocol with Protobuf 2.x can successfully connect to the server which uses Protobuf 3.

Packet

Before being sent over the wire the Message needs to be encapsulated into a Packet structure:

message Packet {
  int64 id = 1;
  com.daysofwonder.mm.Message payload = 3;
}

The id field is filled by the Client with any arbitrary value. If this request allows a response from the server, the Scalable Server will do its best to put the same id in the response to allow the client to match a response to a sent request. Requests sent by the server without any prior request, or requests sent to another client in response of an incoming request will the id field set at 0 or unset.