This page is deprecated and kept for historical reasons. kdbus was implemented as https://github.com/systemd/kdbus, but ultimately was not merged into the kernel and development was abandoned.

D-Bus Version 2 Serialisation

This is how to serialise a "version 2" D-Bus message.

This is heavily based on the specification for D-Bus version 1: http://dbus.freedesktop.org/doc/dbus-specification.html

All messages on kdbus are sent using version 2.

Introduction

D-Bus protocol version 2 assumes a reliable transport mechanism capable of carrying arbitrarily-sized packet data.

kdbus is an example of such a transport.

An arbitrary stream-oriented transport can be turned into a suitable packet transport using the method described in Streaming GVariant.

Packet format

The canonical type of a D-Bus version two message is (yyyyuta{tv}v).

Note that this type is exactly equivalent to some other types, which may make building or decomposing D-Bus messages easier:

  • ((yyyyut)a{tv}v)

  • ((yyyyuta{tv})v)

  • (((yyyyut)a{tv})v)

  • etc.

The first four bytes are exactly the same as the first four bytes in the original D-Bus 1 wire format:

  • endianness indicator
  • message type
  • message flags
  • version field

In version 2 of the protocol, the version field is set to 2.

The uint32 is reserved (possibly for future expansion of the flags field). Currently it must always be set to zero by senders and its value must be ignored by receivers.

The uint64 is the serial number of the message (which has been upgraded from a uint32 in D-Bus 1).

The dictionary mapping uint64 to variants are the extended header fields from version 1 of the protocol, with a couple of modifications:

  • a uint64 is used as a key instead of a byte
  • the reply-to field carries a uint64 instead of a uint32 (corresponding to the increased size of serial numbers)
  • the signature and num-fd fields never appear in version 2 messages

The body of the message is inside of the variant at the end. The body must be a tuple.

Note that it is possible to determine the endianness of the message through inspection of the leading byte, regardless of which endianness the message was loaded with in the first place.

kdbus notes

When transmitting over kdbus, the entire content of the header (all parts up to and including the extended header dictionary) must be transmitted inside of the first payload item (either vector or memfd). The content may be merged with the body (or part of the body) into the same item, but the entire header must appear entirely within the first item.

Messages transmitted over kdbus must always be in the native endianness of the machine.

There are rules regarding how data may be split into multiple vectors. It is not permitted to split the data of a simple-typed value between multiple vectors. It is similarly not permitted to split the offsets of a single container between multiple vectors or any contiguous region of padding at the level of a single container.

Stated another way: for every byte in the serialised data, there is a value (either leaf or container) that is "responsible" for that byte being there. Call this value the owner of that byte. It is not permitted to split up contiguous regions of bytes that are owned by the same value.

As an example, consider the message [(4, "a"), (2, "b")].

With ## to denote padding, the serialised form of this message is:

  \4 \0 \0 \0 'a \0 ## ## \2 \0 \0 \0 'b \0 \6 \e

The message could be maximally split into 6 parts, thus:

  \4 \0 \0 \0 'a \0 ## ## \2 \0 \0 \0 'b \0 \6 \e
  ~~~~~~~~~~~ ~~~~~ ~~~~~ ~~~~~~~~~~~ ~~~~~ ~~~~~

Noting that the basic types (the ints and strings) may not be split, nor may be split the padding bytes between the two items or the offsets at the end (since each of those are contiguous sequences of bytes owned by the array).

The serialised form of any value that is not entirely contained within a given vector must be in normal form.

Insofar as fields in the D-Bus header are copied into the kernel (eg: destination, sender, etc.) the fields must match exactly. Receivers should verify this.

Violation of any of the above rules will result in the packet being rejected.

Stream notes

The alignment requirement of the packet format is 8 which means that a uint64 will be used for the size field when speaking on a stream.

It is not expected that implementations will be able to dequeue messages larger than 263 - 1 bytes in length and therefore it can safely be assumed that the size of messages will therefore always come as a single unsigned 64bit integer.

D-Bus 1 compatibility notes

It is theoretically possible to mix D-Bus protocol version 1 and 2 messages in a single packet-based transport.

If doing this is desired on a socket then the D-Bus version 1 messages should be framed with the size information in exactly the same way is done for version 2.

Once the full packet is received, it is possible to determine the version of the packet by inspecting the header.

Projects/GLib/GDBus/Version2 (last edited 2023-07-29 12:40:50 by PhilipWithnall)