All numbers are transmitted in network byte order (big-endian).
|byte 0||byte 1||byte 2||byte 3||Comments|
|0||O||S||M||E||I||Observed Seq.||Sequence Number||The first bit of an Airhook packet is always 0|
|Observed session ID||Only present if O bit is set in flags|
|Session ID||Only present if S bit is set in flags|
|Interval||Only present if I bit is set in flags|
|Next Msg. #||Only present if E bit is set in flags|
|# Missed - 1||Missed #0||Missed #1||...||Only present if M bit is set in flags|
|# Bytes - 1||Byte #0||Byte #1||...||Repeated for each message in packet (may be none)|
Note: an Airhook packet is distinct from an Airhook message (or "micropacket"). A packet corresponds to a physical, link-level datagram. A message corresponds to a logical datagram. The Airhook protocol's job is to implement reliable message transport over an unreliable packet transport.
The first octet of an Airhook packet is a set of flags. The high-order bit (bit 7) is always 0; Airhook users may take advantage of this to mark non-Airhook, "out of band" messages by setting the high bit of the first byte. Bits 4, 3, 2, 1, and 0 (symbolically, O, S, M, E, and I) are used to indicate the presence (1) or absence (0) of optional packet components.
Airhook packets are strictly ordered; packets which arrive out of order are discarded by the receiver. (This isn't as bad as it sounds. Packet reordering is rare in practice, and Airhook recovers very quickly from missed packets.) Ordering is guaranteed by the 16-bit Sequence Number present in every packet.
The Sequence Number starts at zero for the first packet sent and increments by one (modulo 65536) for each packet sent thereafter. The receiver ignores any packet whose sequence number is not between 1 and 255 greater (modulo 65536) than the last successful packet's sequence number. The transmitter must therefore never increment the sequence number until it receives confirmation that the opposing receiver has successfully received a packet with a sequence number no more than 255 less (modulo 65536) than the current sequence number.
Put more simply, the transmitter is not allowed to get more than 255 sequence numbers "ahead" of what has been confirmed by the receiver. If the transmitter runs out of confirmed sequence numbers, it must continue retransmitting with the last sequence number (and no new data) until it receives additional confirmation.
Confirmation is established with the Observed Sequence Number field, which records the low-order octet of the latest Sequence Number seen so far by the transmitter of the packet. (Because of the constraint described above, the high-order octet may be inferred by the receiver.) Not every packet must be individually confirmed, but regular confirmations are necessary to keep data flowing. Note that there is no special "ACK" packet; confirmation occurs as a side effect of normal transmission.
There is one exception to the "every new packet should have an incremented sequence number" rule. ... FIXME ...
Each endpoint assigns itself a four-byte session ID designed to distinguish it from past and future instances of the same endpoint which might have access to the same physical transport. (It is common to set the session ID from the real-time clock, but this is not required.) These session ID values are used to synchronize Airhook connections and to detect when an endpoint has been replaced with a new instance.
If the S flag bit is set, the Session ID field is set to the transmitter's session ID (otherwise, it is absent). If the O flag bit is set, the Observed Session ID field is set to the last known session ID seen by the transmitter. (The Observed Session ID field will never be present without the Session ID field.)
At startup, the Session ID field is always present. Confirmations are ignored until a packet is received that has Session ID set and Observed Session ID set to the receiver's own session ID. When a new Session ID value is seen, the endpoint transmits both Session ID and Observed Session ID fields until any such packet is successfully confirmed. (After that, Session ID and Observed Session ID are skipped to save space.)
The Interval field is only present when the I flag bit is set. This field is reserved for use by rate-based congestion control algorithms; currently it is never utilized. The receiver ignores it if it is present.
Messages, like packets, are assigned sequence numbers. They use their own 8-bit sequence number space. As with packet sequence numbers, the transmitter is not allowed to be more than 255 messages ahead of the receiver; if it outstrips the receiver, it must wait for confirmation of an earlier packet.
The Next Message Number field contains the first message number which has not been used. This does not include any messages contained in this packet itself, only messages previously transmitted. That is, the first message in this packet, if it exists, will have the message number in this field. (Subsequent messages in the same packet will have incrementally higher message numbers.)
The presence of this field allows the receiver to determine if it has missed any messages. If so, the receiver must list the missed message numbers in the next response which confirms receipt of this packet. Otherwise, confirmation of a packet implies confirmation of every message up to and including the messages physically present in that packet.
If the M flag bit is set, this field contains a list of message numbers which were missed (as described above). The first octet contains the number of message numbers in the list minus one. The sender needs to include the missed message numbers in every subsequent packet until confirmation is received. Message numbers are not reused; if the missed messages are retransmitted, they will be assigned new message numbers, and they will be indistinguishable (at the Airhook level) from new messages. If the sender has chosen to discard the missed messages in the meantime, they will simply not be retransmitted.
Airhook messages are never retransmitted speculatively. Each message is transmitted once; only when the receiver confirms transmission failure (missed message) will it be retransmitted (again, once; the cycle repeats). This ensures that each message arrives exactly once, and minimizes bandwidth waste.
Once everything described above is out of the way, the rest of the packet contents (if any) is a sequence of messages. Each message is preceded by a byte which contains the length of the message minus one. (Zero-length messages are not allowed by the Airhook protocol; the maximum Airhook message length is 256.) Message numbers are implicitly assigned as described above.
Note that in the common case, once the session has been established and while data is flowing smoothly, the entire overhead for an Airhook packet is five bytes plus one byte per message contained in the packet. Combined with UDP overhead, that's a total of 14 header bytes for a single message. Compare that with the 24 bytes required by TCP, and consider also that TCP requires the transmission of additional packets for ACK, etc. (which are already built into normal Airhook packets).