blob: 97e330dd6ff20a48aac61a20bc95bcf5533be658 [file] [log] [blame] [view]
# [FTP](../ Transactional Message Header v3
Field | Value
Status | Accepted
Authors |
Submitted | 2019-03-07
Reviewed | 2019-03-14
## Summary
This proposal **modifies the wire format** as follows.
The **reserved bytes of the transaction header** are allocated to:
* A one byte **magic number** to identify the wire format used;
* And three bytes for **flags** meant to be temporarily used for soft migrations.
Additionally, rather than shoehorning epitaphs values in the header, an
**epitaph payload is a `struct{int32}`**.
## Motivation and design
Having a magic number in headers:
* Provides a mechanism to readers whether a message received is compatible (or
note), and symmetrically provide a mechanisn for writers to indicate the
format of messages sent.
* Ordering of magic numbers is a non-goal, magic numbers should simply checked,
and if not compatible (i.e. the same), rejected. Specifically, we shy away
from the term "version" since we want pairwise compatibility checks, and not
range based compatibility as in "supports v5 through v8".
Having flags in headers:
* Provides a mechanism to help with soft transition, especially the requirement
that bindings MUST NOT reject messages if they do not know about the use of
certain flags, and instead just ignore them. For instance, this was used to
migrate [away from static unions](
* We prefer allocating more bytes to flags (3 bytes) than to magic numbers (1
byte) as we expect a lot more features to be temporarily needed, than wire
format flavors.
On epitaph:
* Epitaphs were [shoehorned]( into the `reserved` bytes,
which are now used for the magic number and the flags;
* Having epitaphs be a plain vanilla payload `struct{int32}` removes one special
snowflake from the [wire format][wire-format], which typically simplifies
bindings and reduces the likelihood of bugs or incompatibilities.
Lastly, we want to keep the header as small as possible, and it is an explicit
goal to keep it at 16 bytes all the while supporting the additional requirements
described above.
### Evolution of Transactional Message Header
FIDL2 (“v2”):
* Transaction ID (`uint32`)
* Reserved (`uint32`)
* Flags (`uint32`)
* Ordinal (`uint32`)
* Transaction ID (`uint32`)
* Reserved (`uint32`) OR [Epitaph value
* Flags (`uint32`)
* Ordinal (`uint32`)
* Transaction ID (`uint32`)
* Reserved (`uint32`) OR [Epitaph value
* Ordinal (`uint64`)
Initially, the reserved (`uint32`) field covering bytes 4 through 7 was meant to
align with requirements from [zx_channel_call][zx_channel_call]. However, the
syscall has stabilized, and this requirement is no longer needed.
<!-- xrefs -->
[zx_channel_call]: /docs/reference/syscalls/
### Version 3
We stabilize the transactional message header (“v3”) to be:
* Transaction ID (`uint32`)
* Flags (`array<uint8>:3`, i.e. 3 bytes)
* Magic Number (`uint8`)
* Ordinal (`uint64`)
Bindings MUST NOT check flags, except for specific flags these bindings are
using or know about, i.e. it is valid to set a bit which is unknown to recipient
As a [wire format diagram][wire-format] we have:
### When should a new magic number be assigned
The initial magic number will be `0x01`. We reserve funnier numbers for later.
A magic number MUST be assigned to a new wire format when the wire format it is
evolving or replacing cannot be reasonably phased out by the FIDL team.
## Performance
Having epitaphs be `struct{int32}` payloads, rather than embedded in the
transaction header, increases the minimal amount of bytes read from 16 bytes to
24 bytes Performant bindings stack allocate a small buffer, and an increase of 8
bytes has minimal impact.
<!-- xrefs -->
[wire-format]: /docs/reference/fidl/language/wire-format