summaryrefslogtreecommitdiff
path: root/src/libsystemd/libsystemd-internal/sd-bus/GVARIANT-SERIALIZATION
blob: 6aeb11364a415f832e14275b8da10bd75f0a2141 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
How we use GVariant for serializing D-Bus messages
--------------------------------------------------

We stay close to the original dbus1 framing as possible, but make
certain changes to adapt for GVariant. dbus1 has the following
framing:

    1. A fixed header of "yyyyuu"
    2. Additional header fields of "a(yv)"
    3. Padding with NUL bytes to pad up to next 8byte boundary
    4. The body

Note that the body is not padded at the end, the complete message
hence might have a non-aligned size. Reading multiple messages at once
will hence result in possibly unaligned messages in memory.

The header consists of the following:

    y  Endianness, 'l' or 'B'
    y  Message Type
    y  Flags
    y  Protocol version, '1'
    u  Length of the body, i.e. the length of part 4 above
    u  32bit Serial number

    = 12 bytes

This header is then followed by the fields array, whose first value is
a 32bit array size.

When using GVariant we keep the basic structure in place, only
slightly alter the header, and define protocol version '2'. The new
header:

    y  Endianness, 'l' or 'B'
    y  Message Type
    y  Flags
    y  Protocol version, '2'
    u  Reserved, must be 0
    t  64bit Cookie

    = 16 bytes

This is then followed by the GVariant fields array ("a{tv}"), and
finally the actual body as variant (v). Putting this altogether a
packet on dbus2 hence qualifies as a fully compliant GVariant
structure of (yyyyuta{tv}v).

For details on gvariant, see:

https://people.gnome.org/~desrt/gvariant-serialisation.pdf

Regarding the framing of dbus2, also see:

https://wiki.gnome.org/Projects/GLib/GDBus/Version2

The first four bytes of the header are defined the same way for dbus1
and dbus2. The first bytes contain the endianess field and the
protocol version, so that the remainder of the message can be safely
made sense of just by looking at the first 32bit.

Note that the length of the body is no longer included in the header
on dbus2! In fact, the message size must be known in advance, from the
underlying transport in order to parse dbus2 messages, while it is
directly included in dbus1 message headers. This change of semantics
is an effect of GVariant's basic design.

The serial number has been renamed cookie and has been extended from
32bit to 64bit. It is recommended to avoid the higher 32bit of the
cookie field though, to simplify compatibility with dbus1 peers. Note
that not only the cookie/serial field in the fixed header, but also
the reply_cookie/reply_serial additional header field has been
increased from 32bit to 64bit, too!

The header field identifiers have been extended from 8bit to
64bit. This has been done to simplify things (as kdbus otherwise uses
exclusively 64bit types, unless there is a strong reason not to), and
has no effect on the serialization size, as due to alignment for each
8bit header field identifier 56 bits of padding had to be added.

Note that the header size changed, due to these changes. However,
consider that on dbus1 the beginning of the fields array contains the
32bit array size (since that is how arrays are encoded on dbus1),
thus, if one considers that size part of the header, instead of the
array, the size of the header on dbus1 and dbus2 stays identical, at
16 bytes.

              0               4               8               12              16
      Common: | E | T | F | V | ...

       dbus1: |  (as above)   | Body Length   | Serial        | Fields Length | Fields array ...

    gvariant: |  (as above)   | Reserved      | Cookie                        | Fields array ...

And that's already it.

Note: to simplify parsing, valid kdbus/dbus2 messages must include the
entire fixed header and additional header fields in a single non-memfd
message part. Also, the signature string of the body variant all the
way to the end of the message must be in a single non-memfd part
too. The parts for this extended header and footer can be the same
one, and can also continue any amount of additional body bytes.

Note: on kdbus only native endian messages marshalled in gvariant may
      be sent. If a client receives a message in non-native endianness
      or in dbus1 marshalling it shall ignore the message.

Note: The GVariant "MAYBE" type is not supported, so that messages can
      be fully converted forth and back between dbus1 and gvariant
      representations.