Jump to content

SimTX API/Framing: Difference between revisions

From SimTX Wiki
Clanker (talk | contribs)
Protocol v25 reference
 
Clanker (talk | contribs)
Remove development history and server internals
 
Line 10: Line 10:
</syntaxhighlight>
</syntaxhighlight>


The server sends no preface. The preface is the only part of the protocol outside protobuf, and the only place the protocol version appears. A server that does not speak the requested version answers with a [[SimTX API/Packets/ServerHello|ServerHello]] whose status is <code>HELLO_STATUS_VERSION_UNSUPPORTED</code>; see [[SimTX API/Connection and handshake#Version 24 clients|Version 24 clients]] for the v24 case.
The server sends no preface. The preface is the only part of the protocol outside protobuf, and the only place the protocol version appears. A server that does not speak the requested version answers with a [[SimTX API/Packets/ServerHello|ServerHello]] whose status is <code>HELLO_STATUS_VERSION_UNSUPPORTED</code>.


== Frames ==
== Frames ==
Line 20: Line 20:
</syntaxhighlight>
</syntaxhighlight>


This is protobuf's standard ''length-delimited'' encoding of a message, as written by <code>writeDelimitedTo</code> and read by <code>parseDelimitedFrom</code> in the Java library, and by the equivalent helpers of other protobuf libraries. The varint is the usual base-128 encoding, least significant group first.
This is protobuf's standard ''length-delimited'' encoding of a message, as written by <code>writeDelimitedTo</code> and read by <code>parseDelimitedFrom</code>, or the equivalent helpers of other protobuf libraries. The varint is the usual base-128 encoding, least significant group first.


<code>ClientFrame</code> and <code>ServerFrame</code> each consist of one <code>oneof msg</code>. Exactly one member is set in every frame. The member number says what the frame is, and the member's value is the message:
<code>ClientFrame</code> and <code>ServerFrame</code> each consist of one <code>oneof msg</code>. Exactly one member is set in every frame. The member number says what the frame is, and the member's value is the message:
Line 55: Line 55:
|}
|}


Numbers 1 to 15 encode the tag in one byte. Numbers that were used before release are reserved and never reused.
Numbers 1 to 15 encode the tag in one byte. <code>ServerFrame</code> numbers 15, 16 and 62 are reserved; do not use them.


== Size and shape limits ==
== Size and shape limits ==
Line 74: Line 74:
|}
|}


The element budget exists because a frame's size in bytes says little about the memory it needs once parsed: an empty repeated message costs 2 bytes on the wire but far more as an object. Receivers check a frame's shape before parsing it. A client frame over a limit is a protocol violation; the server answers [[SimTX API/Packets/Error|Error]] <code>INVALID_REQUEST</code> where it can and closes the connection. Clients should apply the same limits to server frames.
A client frame over a limit is a protocol violation; the server answers [[SimTX API/Packets/Error|Error]] <code>INVALID_REQUEST</code> where it can and closes the connection. Clients should apply the same limits to server frames.


A reader should not allocate the announced length blindly: check it against 16 MiB first, and for large frames let the buffer grow as bytes arrive.
A reader should not allocate the announced length blindly: check it against 16 MiB first, and for large frames let the buffer grow as bytes arrive.


== Unknown frames and fields ==
== Unknown frames and fields ==
The protocol grows within version 25 by adding messages, <code>oneof</code> members, fields and enum values. A reader must therefore:
A reader must:
* '''Skip unknown frames.''' A frame whose member number it does not know parses as a frame with no member set. Ignore it and read the next frame. Never treat it as fatal. An empty frame is skipped the same way.
* '''Skip unknown frames.''' A frame whose member number it does not know parses as a frame with no member set. Ignore it and read the next frame. Never treat it as fatal. An empty frame is skipped the same way.
* '''Skip unknown fields''' of every wire type: varint (0), 64-bit (1), length-delimited (2) and 32-bit (5). Generated protobuf code does this already; hand-written decoders must do it explicitly.
* '''Skip unknown fields''' of every wire type: varint (0), 64-bit (1), length-delimited (2) and 32-bit (5). Generated protobuf code does this already; hand-written decoders must do it explicitly.

Latest revision as of 17:14, 24 October 2026

This page describes how messages of the SimTX API game protocol, version 25, are laid out on the TLS byte stream: the preface, the length-delimited frames, the limits a frame must respect, and how a reader skips what it does not understand.

Preface[edit | edit source]

The client opens the stream with exactly 8 bytes:

53 49 4D 54     magic      0x53494D54, "SIMT", big-endian int32
00 00 00 19     version    25, big-endian int32

The server sends no preface. The preface is the only part of the protocol outside protobuf, and the only place the protocol version appears. A server that does not speak the requested version answers with a ServerHello whose status is HELLO_STATUS_VERSION_UNSUPPORTED.

Frames[edit | edit source]

After the preface, each direction is a sequence of frames:

varint      length       number of bytes that follow
bytes       message      one ClientFrame (client to server) or ServerFrame (server to client)

This is protobuf's standard length-delimited encoding of a message, as written by writeDelimitedTo and read by parseDelimitedFrom, or the equivalent helpers of other protobuf libraries. The varint is the usual base-128 encoding, least significant group first.

ClientFrame and ServerFrame each consist of one oneof msg. Exactly one member is set in every frame. The member number says what the frame is, and the member's value is the message:

message ClientFrame {
  oneof msg {
    ClientHello hello = 1;
    Ping ping = 2;
    ...
    ReceiverStart receiver_start = 10;
    ...
  }
}

So a frame body always starts with the tag of its member (field number × 8 + 2), then the member's length, then the member's message. The complete lists are on SimTX API/Packet list.

Member numbers[edit | edit source]

Member numbers are allocated in blocks, the same in both directions:

Numbers Area
1 to 9 Connection: hello, ping, errors, banners
10 to 29 Receiver and transmitter sessions
30 to 59 Control sessions
60 to 79 Moderation sessions
80 to 99 Reserved for the next area

Numbers 1 to 15 encode the tag in one byte. ServerFrame numbers 15, 16 and 62 are reserved; do not use them.

Size and shape limits[edit | edit source]

Limit Value
Frame length At most 16 MiB (16,777,216 bytes), both directions
Hello frame At most 64 KiB
Frames before the hello At most 16 unknown or empty frames
Elements per frame At most 16,384 in client frames and 2,097,152 in server frames, counting nested messages, elements of repeated string, bytes and message fields, and unknown fields
Nesting depth At most 32 levels of nested messages
Group encoding Not allowed (wire types 3 and 4)

A client frame over a limit is a protocol violation; the server answers Error INVALID_REQUEST where it can and closes the connection. Clients should apply the same limits to server frames.

A reader should not allocate the announced length blindly: check it against 16 MiB first, and for large frames let the buffer grow as bytes arrive.

Unknown frames and fields[edit | edit source]

A reader must:

  • Skip unknown frames. A frame whose member number it does not know parses as a frame with no member set. Ignore it and read the next frame. Never treat it as fatal. An empty frame is skipped the same way.
  • Skip unknown fields of every wire type: varint (0), 64-bit (1), length-delimited (2) and 32-bit (5). Generated protobuf code does this already; hand-written decoders must do it explicitly.
  • Keep unknown enum values. Treat them as "unknown" in the user interface rather than failing. Each enum documents how its 0 value and unknown values are read; see Enumerations.

Within a session, frames that are known but not allowed (for example a TxUpdate on a receiver connection) are a protocol violation.

Order[edit | edit source]

Frames are processed in order on each connection. Responses to control requests arrive in the order of the requests, but other frames can arrive between any two of them: Pong, Banner, MonitorBlock, SessionStatus updates and Error. Read each connection with a loop that dispatches on the member number, rather than expecting a particular frame next.

Reading loop[edit | edit source]

send preface, then the hello frame
loop:
    length = read varint                      (at most 5 bytes for a valid length)
    if length > 16 MiB: protocol error, close
    body = read exactly length bytes
    frame = parse ServerFrame from body       (unknown fields skipped)
    switch on the member that is set:
        known member  -> handle it
        nothing set   -> ignore (newer message or empty frame)

Example[edit | edit source]

A ping and its pong:

ping (client to server, 12 bytes):

0B                      frame length 11
12 09                   ping (Ping), 9 bytes
  08 63                 nonce = 99
  10 80 94 83 B9 97 34  client_time_ms = 1793000000000

pong (server to client, 19 bytes):

12                      frame length 18
12 10                   pong (Pong), 16 bytes
  08 63                 nonce = 99
  10 80 94 83 B9 97 34  client_time_ms = 1793000000000
  18 8C 94 83 B9 97 34  server_time_ms = 1793000000012
SimTX API reference (protocol v25)
Start OverviewQuick startFramingData typesPacket listSchemaLimits and errorsCompatibility and versioning
Account service OverviewDevice loginServer directoryStation endpointsGame ticketsPermissionsPublic endpoints
Game protocol Connection and handshakeSession statusReceiver sessionTransmitter sessionControl sessionCatalogModeration
Stations StationsSatellitesTracking and pointing
Connection ClientHelloPingServerHelloPongErrorBanner
Session AntennaPointingUpdateSessionStatus
Receiver ForwardedClientAddressReceiverStartReceiverRetuneIqStreamDescriptorIqBlock
Transmitter TransmitterStartSampleBlockTxUpdateTxModeInfoTxQueueTxAcceptTxTelemetryTxUpdateAck
Control ListStationsStartMonitorStopMonitorWeatherMapRequestServerHealthRequestCoverageMapRequestEphemerisRequestPassPredictionRequestStationListMonitorBlockMonitorEndWeatherMapResponseServerHealthReportCoverageMapResponseEphemerisResponsePassPredictionResponseMonitorAck
Catalog CatalogListRequestCatalogFetchCatalogUploadCatalogDeleteCatalogListCatalogEntryCatalogUploadResultCatalogDeleteResult
Moderation KickRequestIpModerationRequestBroadcastBannerKickResultIpModerationResultStationImpactList
Archive Protocol v24 reference