From: Lennart Poettering Date: Tue, 17 Dec 2013 01:43:45 +0000 (+0100) Subject: bus: remarshal messages when necessary before sending X-Git-Tag: v209~863 X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=commitdiff_plain;h=e1c433c6218b3e3bcc2621bdfa575a77017bb9ae bus: remarshal messages when necessary before sending --- diff --git a/src/libsystemd-bus/bus-message.c b/src/libsystemd-bus/bus-message.c index 3f70f6f30..1a461e62e 100644 --- a/src/libsystemd-bus/bus-message.c +++ b/src/libsystemd-bus/bus-message.c @@ -35,6 +35,7 @@ #include "bus-type.h" #include "bus-signature.h" #include "bus-gvariant.h" +#include "bus-util.h" static int message_append_basic(sd_bus_message *m, char type, const void *p, const void **stored); @@ -5407,3 +5408,87 @@ _public_ sd_bus *sd_bus_message_get_bus(sd_bus_message *m) { return m->bus; } + +int bus_message_remarshal(sd_bus *bus, sd_bus_message **m) { + _cleanup_bus_message_unref_ sd_bus_message *n = NULL; + usec_t timeout; + int r; + + assert(bus); + assert(m); + assert(*m); + + switch ((*m)->header->type) { + + case SD_BUS_MESSAGE_SIGNAL: + r = sd_bus_message_new_signal(bus, (*m)->path, (*m)->interface, (*m)->member, &n); + if (r < 0) + return r; + + break; + + case SD_BUS_MESSAGE_METHOD_CALL: + r = sd_bus_message_new_method_call(bus, (*m)->destination, (*m)->path, (*m)->interface, (*m)->member, &n); + if (r < 0) + return r; + + break; + + case SD_BUS_MESSAGE_METHOD_RETURN: + case SD_BUS_MESSAGE_METHOD_ERROR: + + n = message_new(bus, (*m)->header->type); + if (!n) + return -ENOMEM; + + n->reply_serial = (*m)->reply_serial; + r = message_append_field_uint32(n, BUS_MESSAGE_HEADER_REPLY_SERIAL, n->reply_serial); + if (r < 0) + return r; + + if ((*m)->header->type == SD_BUS_MESSAGE_METHOD_ERROR && (*m)->error.name) { + r = message_append_field_string(n, BUS_MESSAGE_HEADER_ERROR_NAME, SD_BUS_TYPE_STRING, (*m)->error.name, &n->error.message); + if (r < 0) + return r; + + n->error._need_free = -1; + } + + break; + + default: + return -EINVAL; + } + + if ((*m)->destination && !n->destination) { + r = message_append_field_string(n, BUS_MESSAGE_HEADER_DESTINATION, SD_BUS_TYPE_STRING, (*m)->destination, &n->destination); + if (r < 0) + return r; + } + + if ((*m)->sender && !n->sender) { + r = message_append_field_string(n, BUS_MESSAGE_HEADER_SENDER, SD_BUS_TYPE_STRING, (*m)->sender, &n->sender); + if (r < 0) + return r; + } + + n->header->flags |= (*m)->header->flags & (BUS_MESSAGE_NO_REPLY_EXPECTED|BUS_MESSAGE_NO_AUTO_START); + + r = sd_bus_message_copy(n, *m, true); + if (r < 0) + return r; + + timeout = (*m)->timeout; + if (timeout == 0 && !((*m)->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)) + timeout = BUS_DEFAULT_TIMEOUT; + + r = bus_message_seal(n, (*m)->header->serial, timeout); + if (r < 0) + return r; + + sd_bus_message_unref(*m); + *m = n; + n = NULL; + + return 0; +} diff --git a/src/libsystemd-bus/bus-message.h b/src/libsystemd-bus/bus-message.h index 9ef92cf28..a9d42c345 100644 --- a/src/libsystemd-bus/bus-message.h +++ b/src/libsystemd-bus/bus-message.h @@ -231,3 +231,5 @@ void bus_body_part_unmap(struct bus_body_part *part); int bus_message_to_errno(sd_bus_message *m); int bus_message_new_synthetic_error(sd_bus *bus, uint64_t serial, const sd_bus_error *e, sd_bus_message **m); + +int bus_message_remarshal(sd_bus *bus, sd_bus_message **m); diff --git a/src/libsystemd-bus/sd-bus.c b/src/libsystemd-bus/sd-bus.c index 76a27ec3c..338ce0619 100644 --- a/src/libsystemd-bus/sd-bus.c +++ b/src/libsystemd-bus/sd-bus.c @@ -1319,14 +1319,6 @@ static int bus_seal_message(sd_bus *b, sd_bus_message *m, usec_t timeout) { assert(b); assert(m); - if (b->message_version != 0 && - m->header->version != b->message_version) - return -EPERM; - - if (b->message_endian != 0 && - m->header->endian != b->message_endian) - return -EPERM; - if (m->sealed) { /* If we copy the same message to multiple * destinations, avoid using the same serial @@ -1341,6 +1333,18 @@ static int bus_seal_message(sd_bus *b, sd_bus_message *m, usec_t timeout) { return bus_message_seal(m, ++b->serial, timeout); } +static int bus_remarshal_message(sd_bus *b, sd_bus_message **m) { + assert(b); + + /* Do packet version and endianess already match? */ + if ((b->message_version == 0 || b->message_version == (*m)->header->version) && + (b->message_endian == 0 || b->message_endian == (*m)->header->endian)) + return 0; + + /* No? Then remarshal! */ + return bus_message_remarshal(b, m); +} + int bus_seal_synthetic_message(sd_bus *b, sd_bus_message *m) { assert(b); assert(m); @@ -1452,7 +1456,8 @@ static int dispatch_rqueue(sd_bus *bus, sd_bus_message **m) { } } -_public_ int sd_bus_send(sd_bus *bus, sd_bus_message *m, uint64_t *serial) { +_public_ int sd_bus_send(sd_bus *bus, sd_bus_message *_m, uint64_t *serial) { + _cleanup_bus_message_unref_ sd_bus_message *m = sd_bus_message_ref(_m); int r; assert_return(bus, -EINVAL); @@ -1477,6 +1482,12 @@ _public_ int sd_bus_send(sd_bus *bus, sd_bus_message *m, uint64_t *serial) { if (r < 0) return r; + /* Remarshall if we have to. This will possible unref the + * message and place a replacement in m */ + r = bus_remarshal_message(bus, &m); + if (r < 0) + return r; + /* If this is a reply and no reply was requested, then let's * suppress this, if we can */ if (m->dont_send && !serial) @@ -1567,12 +1578,13 @@ static int timeout_compare(const void *a, const void *b) { _public_ int sd_bus_call_async( sd_bus *bus, - sd_bus_message *m, + sd_bus_message *_m, sd_bus_message_handler_t callback, void *userdata, uint64_t usec, uint64_t *serial) { + _cleanup_bus_message_unref_ sd_bus_message *m = sd_bus_message_ref(_m); struct reply_callback *c; int r; @@ -1596,6 +1608,10 @@ _public_ int sd_bus_call_async( if (r < 0) return r; + r = bus_remarshal_message(bus, &m); + if (r < 0) + return r; + c = new0(struct reply_callback, 1); if (!c) return -ENOMEM; @@ -1674,11 +1690,12 @@ int bus_ensure_running(sd_bus *bus) { _public_ int sd_bus_call( sd_bus *bus, - sd_bus_message *m, + sd_bus_message *_m, uint64_t usec, sd_bus_error *error, sd_bus_message **reply) { + _cleanup_bus_message_unref_ sd_bus_message *m = sd_bus_message_ref(_m); usec_t timeout; uint64_t serial; unsigned i; @@ -1702,6 +1719,10 @@ _public_ int sd_bus_call( if (r < 0) return r; + r = bus_remarshal_message(bus, &m); + if (r < 0) + return r; + r = sd_bus_send(bus, m, &serial); if (r < 0) return r;