SubSpace Directory Protocols

Introduction

I've gone back and added little notes (like this one) far too often. This page is about as smooth as a car with square wheels. It really needs to be redone, but I'm really not in the mood for it. I'm sure that I'll be motivated someday. Until then you'll have to make do with this page and my profuse apologies.

WARNING: Some of this is flat out wrong. From a functional standpoint it works, but I lied and did start trying to separate the transport layer (is that the correct term? I'm not sure...) that seems to be common in all non-stateless SubSpace communications (client-dierctory, client-server, probably server-biller). Some of the terms I came up with are incorrect, and there's a lot of stuff that needs to be written. Really quickly, packets types MAY be only 1 byte in size, not 2. That's one I'm not totally sure of yet. Packet type 03h (previously called 0300h) is an "extra" header like 0Eh (formerly 0E00h). It signifies a packet which must be ACKed (with a packet of type 04h). Packet 0Eh is a way of piggy-backing two small packets. In our case that's an acknowledgement and a small data packet, which is probably signified by packet 0Ah (listed unknown before). The unknown data listed in packet 0Eh is really the ACK packet. I intend to write more about this later, but until then, be aware that much of the theory on this page is not 100% correct.

In late January, after a brief period of not playing SubSpace, I was looking at some news sites to catch up on what had happened during my break. Some of them still maintained a list of zones they started because of the directory server scare some time ago. That got me thinking about how it would be cool to have access to my own directory, and how if VIE UK did drop support the community could set up its own.

First a quick interjection: I wrote most of this before the most recent downtime for sscentral.vie.co.uk If I sometimes say things like, "and of course the UK directory will always be around", don't write to me explaining how it was just down because I know that and am not going to retype these pages.

The specification here is obviously incomplete, and I haven't updated it for a long time. If you want to continue work on it yourself, find one of the people who are more familiar with the directory server and ask one of them to fill you in on the holes here.

With three distinct servers (game, billing, and directory) used in SubSpace, writing about these protocols can get confusing. Familiarize yourself with my definitions if they aren't already clear. These are set in stone as far as I'm concerned, so please write to me if you find any incorrect references like accidentally calling the directory a server later on.

  • Client - the game
  • Server - game server
  • Biller - billing server
  • Directory - directory server

Directory - Server

One of the directory's two core fuctions is maintaining a list of active zones. To add themselves to a directory, servers send announcements about themselves once at startup and again every minute. The directory collects these announcements for its zone list, updating entries as necessary.

Server announcements carry all the information the directory needs, and the transfer is one way. The directory does not respond with even a confirmation or error message. Servers are unlisted automatically by the directory when it stops receiving announcements. While I don't know the official time before a zone is unlisted, it must be over 60 seconds or servers would be incorrectly removed. Two minutes seems reasonable because such a limit requires that two announcements be dropped in a row before an active zone is deleted.

By default, servers send their announcements in UDP packets to port 4991. While the port is configureable in the file server.ini, changing it is a bad idea. For one thing, it forces sysops to make an unnecessary change to their setup and could cause confusion among new zone creators, being a hassle at best. For another, the client uses port 4990, which seems to be a base port for the directory, and is not changeable as far as I can tell.

Besides collecting server information, the directory runs a small echo service. If I remember correctly, the server only uses it once at startup for verification. The reply is the only time the directory sends anything to the server. Pings come as a single packet containing exactly 4 arbitrary bytes. The directory's pong response is exactly 8 bytes. The first 4 are always 01 00 00 00, which is 1 when read as a 32 bit integer on little-endian machines like x86's and compatibles. The next 4 are a copy of the server's packet.

Sample ping - pong sequence:

  • Ping (server to directory): 24 15 07 34
  • Pong (directory to server): 01 00 00 00 24 15 07 34

The announcements carry the server's base port, the number of players in the zone, whether or not the server is connected to a biller (i.e. whether or not it's keeping track of scores), the server version, the zone title, the password for being listed in the directory, and the zone description. Note that the server's IP address isn't included because it gets taken from the packet's sender field. The default password is "cane", and, as with the port, I would reccomend that this be left alone for simplicity's sake. There is nothing, though, that precludes the use of multiple passwords. General zones could use the public one while more trusted zones use a private one. These trusted zones could have access to registered prefixes to prevent unauthorized listings starting with VIE, etc.

Server announcement format:

  • 4 bytes zero
    perhaps this separates announcements and pings
  • 2 byes - Port
    least significant byte first (LSB)
  • 2 bytes - Number of players
    LSB
  • 2 bytes - Scorekeeping
    LSB
    0 = not keeping score; 1 = keeping scores
  • 4 bytes - Server version
    LSB
    ex: 86 00 00 00 (134 decimal) represents 1.34
  • 32 bytes - Title
    NULL terminated string
  • 48 bytes - Password
    NULL terminated string
  • variable length - Description
    NULL terminated string

Sample announcement:
Zero 00 00 00 00 zero filled
Port 70 71 server's base port is 6000
Number of Players 53 00 83 players
Scorekeeping 01 00 This server is keeping scores
Server version 86 00 00 00 version 1.34
Title 41 62 43 20 50 72 69 6D 6F 72 64 69 61 6C 20 53 6F 75 70 00 00 00 00 00 00 00 00 00 00 00 00 00 AbC Primordial Soup
Password 63 61 6E 65 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 cane
Description 49 74 27 73 20 66 69 73 68 2D 65 61 74 2D 66 69 73 68 20 69 6E 20 74 68 69 73 20 65 78 63 69 74 69 6E 67 20 6E 65 77 20 7A 6F 6E 52 21 20 4F 72 69 67 69 6E 61 6C 20 73 65 74 74 69 6E 67 73 20 26 20 6D 61 70 2E 00 It's fish-eat-fish in this exciting new zone! Original settings & map.

Directory - Client

The directory - client protocol specifies how the client should retrieve the zone list. Server packet dumps suggest that Jeff Petersen used similar code for the directory - client connection and the server - client connection. Rather than trying to separate what may be two protocol layers, however, I'm going to present this as it applies to the directory.

Clients communicate with the directory on port 4990 with UDP packets, and there doesn't seem to be any way to change that. The zone list is broken into variable sized records that come one after another forming a single chunk. That chunk is then split into packets with no more than 480 data bytes.

The dialog between the directory and the client has a general structure:

  • Ping - verify that the directory exists
  • Request for zone list
  • Data transfer loop
    • data packet
    • acknowledge
  • Close connection
Furthermore, every packet has a general format:
  • 2 bytes packet type
  • header (only on data packets)
  • variable size packet data

 

Ping Sequence

The client begins by sending a packet of type 0100h. It includes a random 4 bytes of data. The directory responds with a packet of type 0200h and the same 4 bytes.

Sample ping - pong sequence:

  • Ping (client to directory): 00 01 24 15 07 34
  • Pong (directory to client): 00 02 24 15 07 34

 

Request for List

The client requests the transfer with packet type 0300h. It includes 9 bytes of data.
  • 2 bytes packet type
  • 5 bytes unknown - always 00 00 00 00 01
  • 4 bytes minimum number of players
Sample request:
Packet Type 00 03 Packet type 0300h
Unknown 00 00 00 00 01 unknown purpose
Min players 09 00 00 00 List only zones with at lest 9 players

This packet can be repeated during the trasfer. One explanation is that the client times out waiting for a packet and prods the directory to repeat the last one in case it got lost.

 

Transfer Loop

The data is sent in packet type 0300h, then the client acknowledges it with a packet of type 0400h. Data packets have the form:
  • 2 bytes packet type - 00 03
  • 4 bytes packet ID
  • 2 bytes unknown - always 00 0A
  • 4 bytes total data size (size of big chunk before split, does not include these 12 byte headers)
  • variable size data - no more than 480 bytes
Acknowledge packets:
  • 2 bytes packet type - 00 04
  • 4 bytes packet ID
The packet ID starts at 0 and increments for each data packet.

The big data chunk contains the zone list as a series of variable length structures with the following format:

  • 14 byte header
    • 4 bytes zone IP address
    • 2 bytes zone base port
    • 2 bytes number of players
    • 2 bytes scorekeeping
    • 4 bytes server version
  • 64 byte title
    NULL terminated
  • varliable length description
    NULL-terminated
Rules for interpreting fields in the header are the same as for zone announcements. The IP address is in network order. That is, 7F 00 00 01 (interpreted as 0100007Fh on x86's) represents 127.0.0.1.

There will always be a single byte 01 in front of the first (and only the first) zone record. This byte is considered to be part of the data chunk and is included in the total information size.

For small data packets (only the last one can possibly qualify for this), the directory adds an extra 10 bytes to the front of the packet. I don't know the exact rules for using this extra header, and my directory sticks it onto all data packets with less than 244 bytes of zone information. The 10 bytes have the structure:

  • 2 bytes packet type - 00 0E
  • 7 bytes unknown - always 06 00 04 00 00 00 00
  • 1 byte packet size - size of small data packet with standard 12 byte header but without this 10 byte header
Sample 0E00h packet:
Packet Type 00 0E This is a data packet with the 10 byte prefix
Unknown 06 00 04 00 00 00 00 unknown purpose
Packet Size 0D size of packet with 12 byte header
Packet Type 00 03 Packet type 0300h (data packet)
Packet ID 00 00 00 00 This is the first (and in this case last) data packet
Unknown 00 0A unknown purpose
Total data size 01 00 00 00 There is 1 byte of data
Data 01 Zone information - a series of zone information records as described above

In the sample 0E00h packet, there was exactly 1 byte of data total. That packet is what the directory should send the client if there are no zones at or above the requested minimum number of players. It follows all the normal packet creation rules; there simply isn't any data to send besides the one byte that's always added to the zone list.

 

Closing the Connection

After the last data packet has been acknowledged, the directory sometimes sends a packet of type 0400h with 4 bytes zero. The rule seems to be that if the last packet did not have the 0E00h extra header, the directory must send the closing 0400h packet or else the client will continue prodding the server with data requests, and there user will see the transfer pause until the client times out and drops the connection. My directory uses both, and that doesn't seem to cause any trouble.

The connection is officially closed when the client sends packet type 0700h. It takes no other information, and the directory makes no response.

Sample closing sequence, total of 11 data packets in this case:

  • Ack last packet (client to directory): 00 04 0A 00 00 00
  • Indicate no more data (directory to client): 00 04 00 00 00 00
  • Close connection (client to directory): 00 07

 

Unknown Sequence

At any time during the transfer, the client may send a packet of type 0500h with 12 bytes of information. I haven't studied these much, and they appear to be nonessential in that they don't affect the data transfer. The 12 bytes of data appear to be split into 3 groups of 4 bytes, each being a 32-bit integer that increases before the next 0500h packet gets sent. The directory's reply is a packet of type 0600h with 8 bytes of information. The first 4 bytes are the same as the first 4 bytes of information in the 0500h packet to which the 0600h packet is a reply. The next 4 make another 32-bit integer that also increases. I don't know what these values are supposed to represent. My directory just uses the current count, which increases at the constant rate of 10 per second.

I'm guessing this has something to do with measuring packetloss.


Copyright © 1999 by Ravi Iyengar