mirror of
https://github.com/systemd/systemd-stable.git
synced 2025-03-12 08:58:20 +03:00
Revert "Revert "sd-bus: change serialization of kdbus messages to qualify in their entirety as gvariant objects""
This reverts commit 954871d8ba15911d014f76ed2c7a9492953cf39d.
This commit is contained in:
parent
38ab096869
commit
2ac7c17f9d
@ -18,11 +18,8 @@ Known differences between dbus1 and kdbus:
|
||||
|
||||
- Serial numbers of synthesized messages are always (uint32_t) -1.
|
||||
|
||||
- The org.freedesktop.DBus "driver" service is not special on
|
||||
kdbus. It is a bus activated service like any other with its own
|
||||
unique name.
|
||||
|
||||
- NameOwnerChanged is a synthetic message, generated locally and not
|
||||
by the driver.
|
||||
by the driver. On dbus1 only the Disconnected message was
|
||||
synthesized like this.
|
||||
|
||||
- There's no standard per-session bus anymore. Only a per-user bus.
|
||||
|
@ -1,8 +1,9 @@
|
||||
How we use GVariant for serializing D-Bus messages
|
||||
--------------------------------------------------
|
||||
|
||||
We stay as close to the original dbus1 framing as possible. dbus1 has
|
||||
the following framing:
|
||||
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)"
|
||||
@ -20,40 +21,86 @@ The header consists of the following:
|
||||
y Flags
|
||||
y Protocol version, '1'
|
||||
u Length of the body, i.e. the length of part 4 above
|
||||
u Serial number
|
||||
u 32bit Serial number
|
||||
|
||||
= 12 bytes
|
||||
|
||||
This header is then followed by the the fields array, whose first
|
||||
value is a 32bit array size.
|
||||
|
||||
When using GVariant we keep the basic structure in place, only
|
||||
slightly extend the header, and define protocol version '2'. The new
|
||||
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 Length of the body, i.e. the length of part 4 above
|
||||
u Serial number
|
||||
u Length of the additional header fields array
|
||||
u Reserved, must be 0
|
||||
t 64bit Cookie
|
||||
|
||||
= 16 bytes
|
||||
|
||||
This has the nice benefit that the beginning of the additional header
|
||||
fields array is aligned to an 8 byte boundary. Also, in dbus1
|
||||
marshalling arrays start with a length value of 32bit, which means in
|
||||
both dbus1 and gvariant marshallings the size of the header fields
|
||||
array will be at the same location between bytes 12 and 16. To
|
||||
visualize that:
|
||||
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 | Body Length | Serial | Fields Length |
|
||||
Common: | E | T | F | V | ...
|
||||
|
||||
dbus1: | ... (as above) ... | Fields array ...
|
||||
dbus1: | (as above) | Body Length | Serial | Fields Length | Fields array ...
|
||||
|
||||
gvariant: | ... (as above) ... | 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.
|
||||
|
@ -247,3 +247,63 @@ int bus_gvariant_is_fixed_size(const char *signature) {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t bus_gvariant_determine_word_size(size_t sz, size_t extra) {
|
||||
if (sz + extra <= 0xFF)
|
||||
return 1;
|
||||
else if (sz + extra*2 <= 0xFFFF)
|
||||
return 2;
|
||||
else if (sz + extra*4 <= 0xFFFFFFFF)
|
||||
return 4;
|
||||
else
|
||||
return 8;
|
||||
}
|
||||
|
||||
size_t bus_gvariant_read_word_le(void *p, size_t sz) {
|
||||
union {
|
||||
uint16_t u16;
|
||||
uint32_t u32;
|
||||
uint64_t u64;
|
||||
} x;
|
||||
|
||||
assert(p);
|
||||
|
||||
if (sz == 1)
|
||||
return *(uint8_t*) p;
|
||||
|
||||
memcpy(&x, p, sz);
|
||||
|
||||
if (sz == 2)
|
||||
return le16toh(x.u16);
|
||||
else if (sz == 4)
|
||||
return le32toh(x.u32);
|
||||
else if (sz == 8)
|
||||
return le64toh(x.u64);
|
||||
|
||||
assert_not_reached("unknown word width");
|
||||
}
|
||||
|
||||
void bus_gvariant_write_word_le(void *p, size_t sz, size_t value) {
|
||||
union {
|
||||
uint16_t u16;
|
||||
uint32_t u32;
|
||||
uint64_t u64;
|
||||
} x;
|
||||
|
||||
assert(p);
|
||||
assert(sz == 8 || (value < (1ULL << (sz*8))));
|
||||
|
||||
if (sz == 1) {
|
||||
*(uint8_t*) p = value;
|
||||
return;
|
||||
} else if (sz == 2)
|
||||
x.u16 = htole16((uint16_t) value);
|
||||
else if (sz == 4)
|
||||
x.u32 = htole32((uint32_t) value);
|
||||
else if (sz == 8)
|
||||
x.u64 = htole64((uint64_t) value);
|
||||
else
|
||||
assert_not_reached("unknown word width");
|
||||
|
||||
memcpy(p, &x, sz);
|
||||
}
|
||||
|
@ -26,3 +26,7 @@
|
||||
int bus_gvariant_get_size(const char *signature) _pure_;
|
||||
int bus_gvariant_get_alignment(const char *signature) _pure_;
|
||||
int bus_gvariant_is_fixed_size(const char *signature) _pure_;
|
||||
|
||||
size_t bus_gvariant_determine_word_size(size_t sz, size_t extra);
|
||||
void bus_gvariant_write_word_le(void *p, size_t sz, size_t value);
|
||||
size_t bus_gvariant_read_word_le(void *p, size_t sz);
|
||||
|
@ -314,7 +314,7 @@ static int bus_message_setup_kmsg(sd_bus *b, sd_bus_message *m) {
|
||||
m->kdbus->dst_id = destination ? unique : KDBUS_DST_ID_BROADCAST;
|
||||
|
||||
m->kdbus->payload_type = KDBUS_PAYLOAD_DBUS;
|
||||
m->kdbus->cookie = (uint64_t) m->header->serial;
|
||||
m->kdbus->cookie = m->header->dbus2.cookie;
|
||||
m->kdbus->priority = m->priority;
|
||||
|
||||
if (m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
|
||||
@ -416,9 +416,12 @@ static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k) {
|
||||
struct kdbus_item *d;
|
||||
unsigned n_fds = 0;
|
||||
_cleanup_free_ int *fds = NULL;
|
||||
struct bus_header *h = NULL;
|
||||
size_t total, n_bytes = 0, idx = 0;
|
||||
struct bus_header *header = NULL;
|
||||
void *footer = NULL;
|
||||
size_t header_size = 0, footer_size = 0;
|
||||
size_t n_bytes = 0, idx = 0;
|
||||
const char *destination = NULL, *seclabel = NULL;
|
||||
bool last_was_memfd = false;
|
||||
int r;
|
||||
|
||||
assert(bus);
|
||||
@ -433,21 +436,24 @@ static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k) {
|
||||
switch (d->type) {
|
||||
|
||||
case KDBUS_ITEM_PAYLOAD_OFF:
|
||||
if (!h) {
|
||||
h = (struct bus_header *)((uint8_t *)k + d->vec.offset);
|
||||
|
||||
if (!bus_header_is_complete(h, d->vec.size))
|
||||
return -EBADMSG;
|
||||
if (!header) {
|
||||
header = (struct bus_header*)((uint8_t*) k + d->vec.offset);
|
||||
header_size = d->vec.size;
|
||||
}
|
||||
|
||||
footer = (uint8_t*) k + d->vec.offset;
|
||||
footer_size = d->vec.size;
|
||||
|
||||
n_bytes += d->vec.size;
|
||||
last_was_memfd = false;
|
||||
break;
|
||||
|
||||
case KDBUS_ITEM_PAYLOAD_MEMFD:
|
||||
if (!h)
|
||||
if (!header) /* memfd cannot be first part */
|
||||
return -EBADMSG;
|
||||
|
||||
n_bytes += d->memfd.size;
|
||||
last_was_memfd = true;
|
||||
break;
|
||||
|
||||
case KDBUS_ITEM_FDS: {
|
||||
@ -471,23 +477,29 @@ static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!h)
|
||||
if (last_was_memfd) /* memfd cannot be last part */
|
||||
return -EBADMSG;
|
||||
|
||||
r = bus_header_message_size(h, &total);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (!header)
|
||||
return -EBADMSG;
|
||||
|
||||
if (n_bytes != total)
|
||||
if (header_size < sizeof(struct bus_header))
|
||||
return -EBADMSG;
|
||||
|
||||
/* on kdbus we only speak native endian gvariant, never dbus1
|
||||
* marshalling or reverse endian */
|
||||
if (h->version != 2 ||
|
||||
h->endian != BUS_NATIVE_ENDIAN)
|
||||
if (header->version != 2 ||
|
||||
header->endian != BUS_NATIVE_ENDIAN)
|
||||
return -EPROTOTYPE;
|
||||
|
||||
r = bus_message_from_header(bus, h, sizeof(struct bus_header), fds, n_fds, NULL, seclabel, 0, &m);
|
||||
r = bus_message_from_header(
|
||||
bus,
|
||||
header, header_size,
|
||||
footer, footer_size,
|
||||
n_bytes,
|
||||
fds, n_fds,
|
||||
NULL,
|
||||
seclabel, 0, &m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -526,11 +538,11 @@ static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k) {
|
||||
|
||||
if (idx >= begin_body) {
|
||||
if (!part->is_zero)
|
||||
part->data = (uint8_t *)k + d->vec.offset;
|
||||
part->data = (uint8_t* )k + d->vec.offset;
|
||||
part->size = d->vec.size;
|
||||
} else {
|
||||
if (!part->is_zero)
|
||||
part->data = (uint8_t *)k + d->vec.offset + (begin_body - idx);
|
||||
part->data = (uint8_t*) k + d->vec.offset + (begin_body - idx);
|
||||
part->size = d->vec.size - (begin_body - idx);
|
||||
}
|
||||
|
||||
@ -567,10 +579,11 @@ static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k) {
|
||||
case KDBUS_ITEM_PIDS:
|
||||
|
||||
/* The PID/TID might be missing, when the data
|
||||
* is faked by some data bus proxy and it
|
||||
* lacks that information about the real
|
||||
* client since SO_PEERCRED is used for
|
||||
* that. */
|
||||
* is faked by a bus proxy and it lacks that
|
||||
* information about the real client (since
|
||||
* SO_PEERCRED is used for that). Also kernel
|
||||
* namespacing might make some of this data
|
||||
* unavailable when untranslatable. */
|
||||
|
||||
if (d->pids.pid > 0) {
|
||||
m->creds.pid = (pid_t) d->pids.pid;
|
||||
@ -586,7 +599,8 @@ static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k) {
|
||||
|
||||
case KDBUS_ITEM_CREDS:
|
||||
|
||||
/* EUID/SUID/FSUID/EGID/SGID/FSGID might be missing too (see above). */
|
||||
/* EUID/SUID/FSUID/EGID/SGID/FSGID might be
|
||||
* missing too (see above). */
|
||||
|
||||
if ((uid_t) d->creds.uid != UID_INVALID) {
|
||||
m->creds.uid = (uid_t) d->creds.uid;
|
||||
@ -664,7 +678,6 @@ static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k) {
|
||||
goto fail;
|
||||
|
||||
m->creds.cgroup_root = bus->cgroup_root;
|
||||
|
||||
break;
|
||||
|
||||
case KDBUS_ITEM_AUDIT:
|
||||
@ -767,7 +780,7 @@ static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k) {
|
||||
goto fail;
|
||||
|
||||
/* Refuse messages if kdbus and dbus1 cookie doesn't match up */
|
||||
if ((uint64_t) m->header->serial != k->cookie) {
|
||||
if ((uint64_t) m->header->dbus2.cookie != k->cookie) {
|
||||
r = -EBADMSG;
|
||||
goto fail;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -99,7 +99,18 @@ struct sd_bus_message {
|
||||
bool release_kdbus:1;
|
||||
bool poisoned:1;
|
||||
|
||||
/* The first and last bytes of the message */
|
||||
struct bus_header *header;
|
||||
void *footer;
|
||||
|
||||
/* How many bytes are accessible in the above pointers */
|
||||
size_t header_accessible;
|
||||
size_t footer_accessible;
|
||||
|
||||
size_t fields_size;
|
||||
size_t body_size;
|
||||
size_t user_body_size;
|
||||
|
||||
struct bus_body_part body;
|
||||
struct bus_body_part *body_end;
|
||||
unsigned n_body_parts;
|
||||
@ -112,7 +123,7 @@ struct sd_bus_message {
|
||||
int *fds;
|
||||
|
||||
struct bus_container root_container, *containers;
|
||||
unsigned n_containers;
|
||||
size_t n_containers;
|
||||
size_t containers_allocated;
|
||||
|
||||
struct iovec *iovec;
|
||||
@ -138,7 +149,9 @@ struct sd_bus_message {
|
||||
unsigned n_header_offsets;
|
||||
};
|
||||
|
||||
#define BUS_MESSAGE_NEED_BSWAP(m) ((m)->header->endian != BUS_NATIVE_ENDIAN)
|
||||
static inline bool BUS_MESSAGE_NEED_BSWAP(sd_bus_message *m) {
|
||||
return m->header->endian != BUS_NATIVE_ENDIAN;
|
||||
}
|
||||
|
||||
static inline uint16_t BUS_MESSAGE_BSWAP16(sd_bus_message *m, uint16_t u) {
|
||||
return BUS_MESSAGE_NEED_BSWAP(m) ? bswap_16(u) : u;
|
||||
@ -153,29 +166,23 @@ static inline uint64_t BUS_MESSAGE_BSWAP64(sd_bus_message *m, uint64_t u) {
|
||||
}
|
||||
|
||||
static inline uint64_t BUS_MESSAGE_COOKIE(sd_bus_message *m) {
|
||||
/* Note that we return the serial converted to a 64bit value here */
|
||||
return BUS_MESSAGE_BSWAP32(m, m->header->serial);
|
||||
if (m->header->version == 2)
|
||||
return BUS_MESSAGE_BSWAP64(m, m->header->dbus2.cookie);
|
||||
|
||||
return BUS_MESSAGE_BSWAP32(m, m->header->dbus1.serial);
|
||||
}
|
||||
|
||||
static inline uint32_t BUS_MESSAGE_BODY_SIZE(sd_bus_message *m) {
|
||||
return BUS_MESSAGE_BSWAP32(m, m->header->body_size);
|
||||
}
|
||||
|
||||
static inline uint32_t BUS_MESSAGE_FIELDS_SIZE(sd_bus_message *m) {
|
||||
return BUS_MESSAGE_BSWAP32(m, m->header->fields_size);
|
||||
}
|
||||
|
||||
static inline uint32_t BUS_MESSAGE_SIZE(sd_bus_message *m) {
|
||||
static inline size_t BUS_MESSAGE_SIZE(sd_bus_message *m) {
|
||||
return
|
||||
sizeof(struct bus_header) +
|
||||
ALIGN8(BUS_MESSAGE_FIELDS_SIZE(m)) +
|
||||
BUS_MESSAGE_BODY_SIZE(m);
|
||||
ALIGN8(m->fields_size) +
|
||||
m->body_size;
|
||||
}
|
||||
|
||||
static inline uint32_t BUS_MESSAGE_BODY_BEGIN(sd_bus_message *m) {
|
||||
static inline size_t BUS_MESSAGE_BODY_BEGIN(sd_bus_message *m) {
|
||||
return
|
||||
sizeof(struct bus_header) +
|
||||
ALIGN8(BUS_MESSAGE_FIELDS_SIZE(m));
|
||||
ALIGN8(m->fields_size);
|
||||
}
|
||||
|
||||
static inline void* BUS_MESSAGE_FIELDS(sd_bus_message *m) {
|
||||
@ -193,7 +200,10 @@ int bus_message_read_strv_extend(sd_bus_message *m, char ***l);
|
||||
int bus_message_from_header(
|
||||
sd_bus *bus,
|
||||
void *header,
|
||||
size_t length,
|
||||
size_t header_accessible,
|
||||
void *footer,
|
||||
size_t footer_accessible,
|
||||
size_t message_size,
|
||||
int *fds,
|
||||
unsigned n_fds,
|
||||
const struct ucred *ucred,
|
||||
@ -217,9 +227,6 @@ int bus_message_append_ap(sd_bus_message *m, const char *types, va_list ap);
|
||||
|
||||
int bus_message_parse_fields(sd_bus_message *m);
|
||||
|
||||
bool bus_header_is_complete(struct bus_header *h, size_t size);
|
||||
int bus_header_message_size(struct bus_header *h, size_t *sum);
|
||||
|
||||
struct bus_body_part *message_append_part(sd_bus_message *m);
|
||||
|
||||
#define MESSAGE_FOREACH_PART(part, i, m) \
|
||||
|
@ -23,21 +23,38 @@
|
||||
|
||||
#include <endian.h>
|
||||
|
||||
#include "macro.h"
|
||||
|
||||
/* Packet header */
|
||||
|
||||
struct bus_header {
|
||||
struct _packed_ bus_header {
|
||||
/* The first four fields are identical for dbus1, and dbus2 */
|
||||
uint8_t endian;
|
||||
uint8_t type;
|
||||
uint8_t flags;
|
||||
uint8_t version;
|
||||
uint32_t body_size;
|
||||
|
||||
/* Note that what the bus spec calls "serial" we'll call
|
||||
"cookie" instead, because we don't want to imply that the
|
||||
cookie was in any way monotonically increasing. */
|
||||
uint32_t serial;
|
||||
uint32_t fields_size;
|
||||
} _packed_;
|
||||
union _packed_ {
|
||||
/* dbus1: Used for SOCK_STREAM connections */
|
||||
struct _packed_ {
|
||||
uint32_t body_size;
|
||||
|
||||
/* Note that what the bus spec calls "serial" we'll call
|
||||
"cookie" instead, because we don't want to imply that the
|
||||
cookie was in any way monotonically increasing. */
|
||||
uint32_t serial;
|
||||
uint32_t fields_size;
|
||||
} dbus1;
|
||||
|
||||
/* dbus2: Used for kdbus connections */
|
||||
struct _packed_ {
|
||||
uint32_t _reserved;
|
||||
uint64_t cookie;
|
||||
} dbus2;
|
||||
|
||||
/* Note that both header versions have the same size! */
|
||||
};
|
||||
};
|
||||
|
||||
/* Endianness */
|
||||
|
||||
|
@ -132,7 +132,7 @@ static void test_bus_gvariant_get_alignment(void) {
|
||||
|
||||
static void test_marshal(void) {
|
||||
_cleanup_bus_message_unref_ sd_bus_message *m = NULL, *n = NULL;
|
||||
_cleanup_bus_unref_ sd_bus *bus = NULL;
|
||||
_cleanup_bus_close_unref_ sd_bus *bus = NULL;
|
||||
_cleanup_free_ void *blob;
|
||||
size_t sz;
|
||||
int r;
|
||||
@ -145,6 +145,8 @@ static void test_marshal(void) {
|
||||
|
||||
assert_se(sd_bus_message_new_method_call(bus, &m, "a.service.name", "/an/object/path/which/is/really/really/long/so/that/we/hit/the/eight/bit/boundary/by/quite/some/margin/to/test/this/stuff/that/it/really/works", "an.interface.name", "AMethodName") >= 0);
|
||||
|
||||
assert_cc(sizeof(struct bus_header) == 16);
|
||||
|
||||
assert_se(sd_bus_message_append(m,
|
||||
"a(usv)", 3,
|
||||
4711, "first-string-parameter", "(st)", "X", (uint64_t) 1111,
|
||||
@ -162,13 +164,15 @@ static void test_marshal(void) {
|
||||
g_type_init();
|
||||
#endif
|
||||
|
||||
v = g_variant_new_from_data(G_VARIANT_TYPE("(yyyyuuua(yv))"), m->header, sizeof(struct bus_header) + BUS_MESSAGE_FIELDS_SIZE(m), false, NULL, NULL);
|
||||
v = g_variant_new_from_data(G_VARIANT_TYPE("(yyyyuta{tv})"), m->header, sizeof(struct bus_header) + m->fields_size, false, NULL, NULL);
|
||||
assert_se(g_variant_is_normal_form(v));
|
||||
t = g_variant_print(v, TRUE);
|
||||
printf("%s\n", t);
|
||||
g_free(t);
|
||||
g_variant_unref(v);
|
||||
|
||||
v = g_variant_new_from_data(G_VARIANT_TYPE("(a(usv))"), m->body.data, BUS_MESSAGE_BODY_SIZE(m), false, NULL, NULL);
|
||||
v = g_variant_new_from_data(G_VARIANT_TYPE("(a(usv))"), m->body.data, m->user_body_size, false, NULL, NULL);
|
||||
assert_se(g_variant_is_normal_form(v));
|
||||
t = g_variant_print(v, TRUE);
|
||||
printf("%s\n", t);
|
||||
g_free(t);
|
||||
@ -180,6 +184,20 @@ static void test_marshal(void) {
|
||||
|
||||
assert_se(bus_message_get_blob(m, &blob, &sz) >= 0);
|
||||
|
||||
#ifdef HAVE_GLIB
|
||||
{
|
||||
GVariant *v;
|
||||
char *t;
|
||||
|
||||
v = g_variant_new_from_data(G_VARIANT_TYPE("(yyyyuta{tv}v)"), blob, sz, false, NULL, NULL);
|
||||
assert_se(g_variant_is_normal_form(v));
|
||||
t = g_variant_print(v, TRUE);
|
||||
printf("%s\n", t);
|
||||
g_free(t);
|
||||
g_variant_unref(v);
|
||||
}
|
||||
#endif
|
||||
|
||||
assert_se(bus_message_from_malloc(bus, blob, sz, NULL, 0, NULL, NULL, &n) >= 0);
|
||||
blob = NULL;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user