DBUS ---- Type System

前言

       最近在看BlueZ源码,有关DBUS的知识点,在此记录下来。

原文

Type System

D-Bus has a type system, in which values of various types can be serialized into a sequence of bytes referred to as the wire format in a standard way. Converting a value from some other representation into the wire format is called marshaling and converting it back from the wire format is unmarshaling.

The D-Bus protocol does not include type tags in the marshaled data; a block of marshaled values must have a known type signature. The type signature is made up of zero or more single complete types, each made up of one or more type codes.

A type code is an ASCII character representing the type of a value. Because ASCII characters are used, the type signature will always form a valid ASCII string. A simple string compare determines whether two type signatures are equivalent.

A single complete type is a sequence of type codes that fully describes one type: either a basic type, or a single fully-described container type. A single complete type is a basic type code, a variant type code, an array with its element type, or a struct with its fields (all of which are defined below). So the following signatures are not single complete types:

        "aa"
     
        "(ii"
      
        "ii)"
      

And the following signatures contain multiple complete types:

        "ii"
      
        "aiai"
      
        "(ii)(ii)"
      

Note however that a single complete type may contain multiple other single complete types, by containing a struct or dict entry.

Basic types

The simplest type codes are the basic types, which are the types whose structure is entirely defined by their 1-character type code. Basic types consist of fixed types and string-like types.

The fixed types are basic types whose values have a fixed length, namely BYTE, BOOLEAN, DOUBLE, UNIX_FD, and signed or unsigned integers of length 16, 32 or 64 bits.

As a simple example, the type code for 32-bit integer (INT32) is the ASCII character 'i'. So the signature for a block of values containing a single INT32 would be:

          "i"
        

A block of values containing two INT32 would have this signature:

          "ii"
        

The characteristics of the fixed types are listed in this table.

Conventional nameASCII type-codeEncoding
BYTEy (121)Unsigned 8-bit integer
BOOLEANb (98)Boolean value: 0 is false, 1 is true, any other value allowed by the marshalling format is invalid
INT16n (110)Signed (two's complement) 16-bit integer
UINT16q (113)Unsigned 16-bit integer
INT32i (105)Signed (two's complement) 32-bit integer
UINT32u (117)Unsigned 32-bit integer
INT64x (120)Signed (two's complement) 64-bit integer (mnemonic: x and t are the first characters in "sixty" not already used for something more common)
UINT64t (116)Unsigned 64-bit integer
DOUBLEd (100)IEEE 754 double-precision floating point
UNIX_FDh (104)Unsigned 32-bit integer representing an index into an out-of-band array of file descriptors, transferred via some platform-specific mechanism (mnemonic: h for handle)

 

The string-like types are basic types with a variable length. The value of any string-like type is conceptually 0 or more Unicode codepoints encoded in UTF-8, none of which may be U+0000. The UTF-8 text must be validated strictly: in particular, it must not contain overlong sequences or codepoints above U+10FFFF.

Since D-Bus Specification version 0.21, in accordance with Unicode Corrigendum #9, the "noncharacters" U+FDD0..U+FDEF, U+nFFFE and U+nFFFF are allowed in UTF-8 strings (but note that older versions of D-Bus rejected these noncharacters).

The marshalling formats for the string-like types all end with a single zero (NUL) byte, but that byte is not considered to be part of the text.

The characteristics of the string-like types are listed in this table.

Conventional nameASCII type-codeValidity constraints
STRINGs (115)No extra constraints
OBJECT_PATHo (111)Must be a syntactically valid object path
SIGNATUREg (103)Zero or more single complete types

 

Valid Object Paths

An object path is a name used to refer to an object instance. Conceptually, each participant in a D-Bus message exchange may have any number of object instances (think of C++ or Java objects) and each such instance will have a path. Like a filesystem, the object instances in an application form a hierarchical tree.

Object paths are often namespaced by starting with a reversed domain name and containing an interface version number, in the same way as interface names and well-known bus names. This makes it possible to implement more than one service, or more than one version of a service, in the same process, even if the services share a connection but cannot otherwise co-operate (for instance, if they are implemented by different plugins).

Using an object path of / is allowed, but recommended against, as it makes versioning of interfaces hard. Any signals emitted from a D-Bus object have the service’s unique bus name associated with them, rather than its well-known name. This means that receipients of the signals must rely entirely on the signal name and object path to work out which interface the signal originated from.

For instance, if the owner of example.com is developing a D-Bus API for a music player, they might use the hierarchy of object paths that start with /com/example/MusicPlayer1 for its objects.

The following rules define a valid object path. Implementations must not send or accept messages with invalid object paths.

  • The path may be of any length.

  • The path must begin with an ASCII '/' (integer 47) character, and must consist of elements separated by slash characters.

  • Each element must only contain the ASCII characters "[A-Z][a-z][0-9]_"

  • No element may be the empty string.

  • Multiple '/' characters cannot occur in sequence.

  • A trailing '/' character is not allowed unless the path is the root path (a single '/' character).

 

Valid Signatures

An implementation must not send or accept invalid signatures. Valid signatures will conform to the following rules:

  • The signature is a list of single complete types. Arrays must have element types, and structs must have both open and close parentheses.

  • Only type codes, open and close parentheses, and open and close curly brackets are allowed in the signature. The STRUCT type code is not allowed in signatures, because parentheses are used instead. Similarly, the DICT_ENTRY type code is not allowed in signatures, because curly brackets are used instead.

  • The maximum depth of container type nesting is 32 array type codes and 32 open parentheses. This implies that the maximum total depth of recursion is 64, for an "array of array of array of ... struct of struct of struct of ..." where there are 32 array and 32 struct.

  • The maximum length of a signature is 255.

 

When signatures appear in messages, the marshalling format guarantees that they will be followed by a nul byte (which can be interpreted as either C-style string termination or the INVALID type-code), but this is not conceptually part of the signature.

Container types

In addition to basic types, there are four container types: STRUCTARRAYVARIANT, and DICT_ENTRY.

STRUCT has a type code, ASCII character 'r', but this type code does not appear in signatures. Instead, ASCII characters '(' and ')' are used to mark the beginning and end of the struct. So for example, a struct containing two integers would have this signature:

          "(ii)"
        

Structs can be nested, so for example a struct containing an integer and another struct:

          "(i(ii))"
        

The value block storing that struct would contain three integers; the type signature allows you to distinguish "(i(ii))" from "((ii)i)" or "(iii)" or "iii".

The STRUCT type code 'r' is not currently used in the D-Bus protocol, but is useful in code that implements the protocol. This type code is specified to allow such code to interoperate in non-protocol contexts.

Empty structures are not allowed; there must be at least one type code between the parentheses.

ARRAY has ASCII character 'a' as type code. The array type code must be followed by a single complete type. The single complete type following the array is the type of each array element. So the simple example is:

          "ai"
        

which is an array of 32-bit integers. But an array can be of any type, such as this array-of-struct-with-two-int32-fields:

          "a(ii)"
        

Or this array of array of integer:

          "aai"
        

VARIANT has ASCII character 'v' as its type code. A marshaled value of type VARIANT will have the signature of a single complete type as part of the value. This signature will be followed by a marshaled value of that type.

Unlike a message signature, the variant signature can contain only a single complete type. So "i", "ai" or "(ii)" is OK, but "ii" is not. Use of variants may not cause a total message depth to be larger than 64, including other container types such as structures.

DICT_ENTRY works exactly like a struct, but rather than parentheses it uses curly braces, and it has more restrictions. The restrictions are: it occurs only as an array element type; it has exactly two single complete types inside the curly braces; the first single complete type (the "key") must be a basic type rather than a container type. Implementations must not accept dict entries outside of arrays, must not accept dict entries with zero, one, or more than two fields, and must not accept dict entries with non-basic-typed keys. A dict entry is always a key-value pair.

The first field in the DICT_ENTRY is always the key. A message is considered corrupt if the same key occurs twice in the same array of DICT_ENTRY. However, for performance reasons implementations are not required to reject dicts with duplicate keys.

In most languages, an array of dict entry would be represented as a map, hash table, or dict object.

Summary of types

The following table summarizes the D-Bus types.

CategoryConventional NameCodeDescription
reservedINVALID0 (ASCII NUL)Not a valid type code, used to terminate signatures
fixed, basicBYTE121 (ASCII 'y')8-bit unsigned integer
fixed, basicBOOLEAN98 (ASCII 'b')Boolean value, 0 is FALSE and 1 is TRUE. Everything else is invalid.
fixed, basicINT16110 (ASCII 'n')16-bit signed integer
fixed, basicUINT16113 (ASCII 'q')16-bit unsigned integer
fixed, basicINT32105 (ASCII 'i')32-bit signed integer
fixed, basicUINT32117 (ASCII 'u')32-bit unsigned integer
fixed, basicINT64120 (ASCII 'x')64-bit signed integer
fixed, basicUINT64116 (ASCII 't')64-bit unsigned integer
fixed, basicDOUBLE100 (ASCII 'd')IEEE 754 double
string-like, basicSTRING115 (ASCII 's')UTF-8 string (must be valid UTF-8). Must be nul terminated and contain no other nul bytes.
string-like, basicOBJECT_PATH111 (ASCII 'o')Name of an object instance
string-like, basicSIGNATURE103 (ASCII 'g')A type signature
containerARRAY97 (ASCII 'a')Array
containerSTRUCT114 (ASCII 'r'), 40 (ASCII '('), 41 (ASCII ')')Struct; type code 114 'r' is reserved for use in bindings and implementations to represent the general concept of a struct, and must not appear in signatures used on D-Bus.
containerVARIANT118 (ASCII 'v')Variant type (the type of the value is part of the value itself)
containerDICT_ENTRY101 (ASCII 'e'), 123 (ASCII '{'), 125 (ASCII '}')Entry in a dict or map (array of key-value pairs). Type code 101 'e' is reserved for use in bindings and implementations to represent the general concept of a dict or dict-entry, and must not appear in signatures used on D-Bus.
fixed, basicUNIX_FD104 (ASCII 'h')Unix file descriptor
reserved(reserved)109 (ASCII 'm')Reserved for a 'maybe' type compatible with the one in GVariant, and must not appear in signatures used on D-Bus until specified here
reserved(reserved)42 (ASCII '*')Reserved for use in bindings/implementations to represent any single complete type, and must not appear in signatures used on D-Bus.
reserved(reserved)63 (ASCII '?')Reserved for use in bindings/implementations to represent any basic type, and must not appear in signatures used on D-Bus.
reserved(reserved)64 (ASCII '@'), 38 (ASCII '&'), 94 (ASCII '^')Reserved for internal use by bindings/implementations, and must not appear in signatures used on D-Bus. GVariant uses these type-codes to encode calling conventions.

 

Marshaling (Wire Format)

D-Bus defines a marshalling format for its type system, which is used in D-Bus messages. This is not the only possible marshalling format for the type system: for instance, GVariant (part of GLib) re-uses the D-Bus type system but implements an alternative marshalling format.

Byte order and alignment

Given a type signature, a block of bytes can be converted into typed values. This section describes the format of the block of bytes. Byte order and alignment issues are handled uniformly for all D-Bus types.

A block of bytes has an associated byte order. The byte order has to be discovered in some way; for D-Bus messages, the byte order is part of the message header as described in the section called “Message Format”. For now, assume that the byte order is known to be either little endian or big endian.

Each value in a block of bytes is aligned "naturally," for example 4-byte values are aligned to a 4-byte boundary, and 8-byte values to an 8-byte boundary. Boundaries are calculated globally, with respect to the first byte in the message. To properly align a value, alignment padding may be necessary before the value. The alignment padding must always be the minimum required padding to properly align the following value; and it must always be made up of nul bytes. The alignment padding must not be left uninitialized (it can't contain garbage), and more padding than required must not be used.

As an exception to natural alignment, STRUCT and DICT_ENTRY values are always aligned to an 8-byte boundary, regardless of the alignments of their contents.

Marshalling basic types

To marshal and unmarshal fixed types, you simply read one value from the data block corresponding to each type code in the signature. All signed integer values are encoded in two's complement, DOUBLE values are IEEE 754 double-precision floating-point, and BOOLEAN values are encoded in 32 bits (of which only the least significant bit is used).

The string-like types (STRING, OBJECT_PATH and SIGNATURE) are all marshalled as a fixed-length unsigned integer n giving the length of the variable part, followed by n nonzero bytes of UTF-8 text, followed by a single zero (nul) byte which is not considered to be part of the text. The alignment of the string-like type is the same as the alignment of n: any padding required for n appears immediately before n itself. There is never any alignment padding between n and the string text, or between the string text and the trailing nul. The alignment padding for the next value in the message (if there is one) starts after the trailing nul.

For the STRING and OBJECT_PATH types, n is encoded in 4 bytes (a UINT32), leading to 4-byte alignment. For the SIGNATURE type, n is encoded as a single byte (a UINT8). As a result, alignment padding is never required before a SIGNATURE.

For example, if the current position is a multiple of 8 bytes from the beginning of a little-endian message, strings ‘foo’, ‘+’ and ‘bar’ would be serialized in sequence as follows:

                                          no padding required, we are already at a multiple of 4
0x03 0x00 0x00 0x00                       length of ‘foo’ = 3
                    0x66 0x6f 0x6f        ‘foo’
                                   0x00   trailing nul

                                          no padding required, we are already at a multiple of 4
0x01 0x00 0x00 0x00                       length of ‘+’ = 1
                    0x2b                  ‘+’
                         0x00             trailing nul

                               0x00 0x00  2 bytes of padding to reach next multiple of 4
0x03 0x00 0x00 0x00                       length of ‘bar’ = 1
                    0x62 0x61 0x72        ‘bar’
                                    0x00  trailing nul
        

Marshalling containers

Arrays are marshalled as a UINT32 n giving the length of the array data in bytes, followed by alignment padding to the alignment boundary of the array element type, followed by the n bytes of the array elements marshalled in sequence. n does not include the padding after the length, or any padding after the last element. i.e. n should be divisible by the number of elements in the array.

For instance, if the current position in the message is a multiple of 8 bytes and the byte-order is big-endian, an array containing only the 64-bit integer 5 would be marshalled as:

00 00 00 08               n = 8 bytes of data
00 00 00 00               padding to 8-byte boundary
00 00 00 00  00 00 00 05  first element = 5
        

Arrays have a maximum length defined to be 2 to the 26th power or 67108864 (64 MiB). Implementations must not send or accept arrays exceeding this length.

Structs and dict entries are marshalled in the same way as their contents, but their alignment is always to an 8-byte boundary, even if their contents would normally be less strictly aligned.

Variants are marshalled as the SIGNATURE of the contents (which must be a single complete type), followed by a marshalled value with the type given by that signature. The variant has the same 1-byte alignment as the signature, which means that alignment padding before a variant is never needed. Use of variants must not cause a total message depth to be larger than 64, including other container types such as structures. (See Valid Signatures.)

Summary of D-Bus marshalling

Given all this, the types are marshaled on the wire as follows:

Conventional NameEncodingAlignment
INVALIDNot applicable; cannot be marshaled.N/A
BYTEA single 8-bit byte.1
BOOLEANAs for UINT32, but only 0 and 1 are valid values.4
INT1616-bit signed integer in the message's byte order.2
UINT1616-bit unsigned integer in the message's byte order.2
INT3232-bit signed integer in the message's byte order.4
UINT3232-bit unsigned integer in the message's byte order.4
INT6464-bit signed integer in the message's byte order.8
UINT6464-bit unsigned integer in the message's byte order.8
DOUBLE64-bit IEEE 754 double in the message's byte order.8
STRINGUINT32 indicating the string's length in bytes excluding its terminating nul, followed by non-nul string data of the given length, followed by a terminating nul byte.4 (for the length)
OBJECT_PATHExactly the same as STRING except the content must be a valid object path (see above).4 (for the length)
SIGNATUREThe same as STRING except the length is a single byte (thus signatures have a maximum length of 255) and the content must be a valid signature (see above).1
ARRAYUINT32 giving the length of the array data in bytes, followed by alignment padding to the alignment boundary of the array element type, followed by each array element.4 (for the length)
STRUCTA struct must start on an 8-byte boundary regardless of the type of the struct fields. The struct value consists of each field marshaled in sequence starting from that 8-byte alignment boundary.8
VARIANTThe marshaled SIGNATURE of a single complete type, followed by a marshaled value with the type given in the signature.1 (alignment of the signature)
DICT_ENTRYIdentical to STRUCT.8
UNIX_FD32-bit unsigned integer in the message's byte order. The actual file descriptors need to be transferred out-of-band via some platform specific mechanism. On the wire, values of this type store the index to the file descriptor in the array of file descriptors that accompany the message.4

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值