The SOE protocol is a UDP transport layer for the networking traffic of many games developed by Sony Online Entertainment, newer examples of which include Free Realms, H1Z1, Landmark and PlanetSide 2.
The protocol can be thought of, in essence, as a stripped-back version of TCP. It offers basic sessions, packet verification (CRC32), optional compression (zlib), reliable/ordered transmission of data, and optional encryption (RC4).
This documentation covers version 3 of the SOE protocol, using 2022 versions of PlanetSide 2 as a reference.
Warning
This documentation is reverse engineered. As such, it may be incomplete and/or incorrect, and is not necessarily applicable to other games that use the SOE protocol.
All packets of the SOE protocol use big endian and are prefixed by a two-byte OP code.
Packets have a maximum length, which is dictated by both parties using the SessionRequest
and
SessionResponse
packets. This length is usually 512.
The names and OP codes of the protocol packets are:
SessionRequest = 0x01,
SessionResponse = 0x02,
MultiPacket = 0x03,
Disconnect = 0x05,
Heartbeat = 0x06,
NetStatusRequest = 0x07,
NetStatusResponse = 0x08,
ReliableData = 0x09,
ReliableDataFragment = 0x0D,
Acknowledge = 0x11,
AcknowledgeAll = 0x15,
UnknownSender = 0x1D,
RemapConnection = 0x1E
Note: 'data packets' (ReliableData/ReliableDataFragment/Acknowledge/AcknowledgeAll) are actually duplicated four times each, using consecutive OP codes. This allows data to be sent on multiple 'channels'. However, to the author's knowledge, only the first channel has been observed in any games utilising the SOE protocol thus far.
The SOE protocol utilises two sets of packets. The first are concerned with creating, sustaining and failing sessions. As such, having no context, they are not verified and cannot be compressed.
The second set, used within the context of a session, are largely concerned with the transfer of application data. These packets may be pre/suffixed with additional data to facilitate verification and compression.
Those packets involved with negotiating a session are:
- SessionRequest
- SessionResponse
- NetStatusRequest
- NetStatusResponse
- UnknownSender
- RemapConnection
Those packets requiring a session to be utilised are:
- MultiPacket
- Disconnect
- Heartbeat
- ReliableData
- ReliableDataFragment
- Acknowledge
- AcknowledgeAll
All SOE packets are prefixed with an OP code. However, those packets which are sent within the
context of a session can also include additional data, except for when they are bundled within a MultiPacket
.
For a non-sub-packet, the overall structure is as follows:
struct PacketWrapper
{
ushort OpCode;
bool? IsCompressed;
<packet_fields>;
byte[] Crc;
}
The IsCompressed
field is optional, and will only be included if the server indicates that
compression should be enabled, via SessionResponse#IsCompressionEnabled
. Should this flag
be set, the entirety of the wrapped packet's data (<packet_fields>
) is compressed using ZLIB
before being wrapped. The default level of compression (FLEVEL = 2) is used.
The length of the Crc
field is dictated by the SessionResponse#CrcLength
field. It is calculated
using the entirety of the packet buffer; starting from the OP code and ending immediately before the
CRC bytes. The algorithm is a variant of CRC-32 which performs a more lengthy initialization step.
See Appendix A for more info.
Note: before continuing, please consult the Packet Reference.
-
To begin a session, the client party should send a
SessionRequest
packet to the server.- The
SessionId
must be a randomly generated number. - The
UdpLength
field is typically 512 (bytes). - The
ApplicationProtocol
field describes the application protocol that the client wishes to proxy over this session. Using PlanetSide 2 as an example, this might beLoginUdp_X
orExternalGatewayApi_X
.
- The
-
If the server decides to accept the session, it must respond with a
SessionResponse
packet.- The
SessionId
field must contain the ID generated by the client. - The
CrcSeed
must be a randomly generated number. - The
CrcLength
is typically 2 (bytes). Must be between 0 and 4, inclusive. - The
UdpLength
field is typically 512 (bytes).
- The
-
At this point the session is active, and data transmission may begin.
At any point, either party may send a Disconnect
packet to terminate the session. If the ConnectionRefused
or ConnectingToSelf
reasons are provided, the client should not attempt to reconnect. In other cases, the
client may decide how to proceed.
// TODO
The main purpose of the SOE protocol is to provide reliable and ordered transmission of data from a higher level protocol. This is documented here.