Skip to content

The Cockpit Library Architecture

wowus edited this page Sep 14, 2010 · 4 revisions

Introduction

Think of Cockpit as the Apache of Gunz Servers. We don’t write your “webpages” for you, but rather provide a framework for you to write your own. In this case, the server implementation we’re writing is GoGo; but Cockpit has no dependency on GoGo, so can be ripped out and used for other implementations easily.

Properties

Cockpit must be…

  • Scalable. The design goal right now is 1000 clients per gigabyte of RAM.
  • Memory-leak-proof. Leaky memory is just as bad as mov esp, 0 for a server.
  • Highly reliable. The server must never throw an exception out into application code, terminate gracefully if something unrecoverable happens, and have appropriate logging for when something inevitably does go wrong. Minor mistakes will be compensated for, corrupt packets will be dropped, and running out of memory will lead to graceful shutdown.
  • Fast.

Public API

Cockpit consists of five public APIs:

  1. MatchServer
  2. Transmitter
  3. Logger
  4. ClientHandler
  5. ClientHandlerFactory

MatchServer

The MatchServer is where the bulk of the action takes place. It is constructed with a port to run on, a logger to log to, a factory to make ClientHandler’s, and an io_service to asynchronously run on. On construction, it just sits and waits. To start MatchServer listening on the provided port, just call the start() method. It returns immediately. If you wish to wait for the server to die (which is just a synonym for “wait forever”), call the wait() method.

Transmitter

The transmitter does not need to be implemented by the application, rather, it is provided to the ClientHandler so it may send packets. All the transmitter does it provide a nice API for sending Gunz packets.

Logger

A logger subclass MUST be implemented by the application. It has four logging levels, each for a different purpose. Read through the comments in include/cockpit/Logger.h for more details. A valid logger must be passed into MatchServer.

ClientHandler

A ClientHandler subclass must be implemented by the application. This is where the bulk of the game code will reside. A ClientHandler registers itself with a packet registry, and then responds to incoming packets with packets sent with the Transmitter it has been initialized with. Incidentally, it also handles MAIETs handshake for getting the crypto keys. This is just a by-product of my design not being able to nicely compensate for that odd quirk in abstraction.

ClientHandlerFactory

A ClientHandlerFactory subclass’ instance must be passed into MatchServer in order to create valid ClientHandlers on the fly. This class is provided to allow for features such as Channels, Stages, and any other client-to-client shared state without the use of singletons. The state can just be passed to the ClientHandler when it is created by the factory.

Networking Pipeline

Any junction with an o in it means that both paths are followed.
If the junction is just lines, it means that only one path is ever followed.

...............................................
.                                              .
.   /--->  [A] accept new connection           .
.   |                 |                        . <-- Handled by the "MatchServer" class.
.   \-----------------o                        .
.                     |                        .
......................|.........................
.                     |                        .
.                    \ /                       .
.    [B] perform handshake; get crypto keys    .
.                     |                        .
.                    \ /                       .
.        [C] populate packet registry          .
.                     |                        .
.                    \ /                       .
.     /-----> [D] receive packet               . <-- Handled by the "Client" class.
.     |               |                        .
.     |               |                        .
.     |               |----------------\       .
.     |               |                |       .
.     |              \ /               |       .
.     |     [E] decrypt the packet     |       .
.     |               |                |       .
.     |               |                |       .
.     |              \ /               |       .
.     |    [F] dispatch the packet <---/       .
.     |               |                        .
.     |               |                        .
.     \---------------/                        .
................................................

Random side notes:

[B] and © are actually done inside the initialize() method of the created ClientHandler, however, it’s being called by the Client class. In all reality, it’s only inside the client module because I’m lazy.