chiark / gitweb /
bus-message: fix typo
[elogind.git] / src / libsystemd-bus / bus-message.c
index 3a748356743f99ae63c0dc0bb4b17433061673e0..ec2dd07dbaa9069085363ccb71a59e86eddec561 100644 (file)
@@ -23,6 +23,7 @@
 
 #include "util.h"
 #include "utf8.h"
+#include "strv.h"
 
 #include "sd-bus.h"
 #include "bus-message.h"
@@ -30,7 +31,8 @@
 #include "bus-type.h"
 #include "bus-signature.h"
 
-int message_append_basic(sd_bus_message *m, char type, const void *p, const void **stored);
+static int message_parse_fields(sd_bus_message *m);
+static int message_append_basic(sd_bus_message *m, char type, const void *p, const void **stored);
 
 static void reset_containers(sd_bus_message *m) {
         unsigned i;
@@ -125,8 +127,6 @@ static void *message_extend_fields(sd_bus_message *m, size_t align, size_t sz) {
                         m->destination = (const char*) m->fields + (m->destination - (const char*) o);
                 if (m->sender)
                         m->sender = (const char*) m->fields + (m->sender - (const char*) o);
-                if (m->signature)
-                        m->signature = (const char*) m->fields + (m->signature - (const char*) o);
                 if (m->error.name)
                         m->error.name = (const char*) m->fields + (m->error.name - (const char*) o);
         }
@@ -224,21 +224,76 @@ static int message_append_field_uint32(sd_bus_message *m, uint8_t h, uint32_t x)
         return 0;
 }
 
+int bus_message_from_malloc(void *buffer, size_t length, sd_bus_message **ret) {
+        sd_bus_message *m;
+        struct bus_header *h;
+        size_t total, fs, bs;
+        int r;
+
+        assert(buffer || length <= 0);
+        assert(ret);
+
+        if (length < sizeof(struct bus_header))
+                return -EBADMSG;
+
+        h = buffer;
+        if (h->version != 1)
+                return -EBADMSG;
+
+        if (h->serial == 0)
+                return -EBADMSG;
+
+        if (h->type == _SD_BUS_MESSAGE_TYPE_INVALID)
+                return -EBADMSG;
+
+        if (h->endian == SD_BUS_NATIVE_ENDIAN) {
+                fs = h->fields_size;
+                bs = h->body_size;
+        } else if (h->endian == SD_BUS_REVERSE_ENDIAN) {
+                fs = bswap_32(h->fields_size);
+                bs = bswap_32(h->body_size);
+        } else
+                return -EBADMSG;
+
+        total = sizeof(struct bus_header) + ALIGN_TO(fs, 8) + bs;
+        if (length != total)
+                return -EBADMSG;
+
+        m = new0(sd_bus_message, 1);
+        if (!m)
+                return -ENOMEM;
+
+        m->n_ref = 1;
+        m->header = h;
+        m->free_header = true;
+        m->fields = (uint8_t*) buffer + sizeof(struct bus_header);
+        m->body = (uint8_t*) buffer + sizeof(struct bus_header) + ALIGN_TO(fs, 8);
+        m->sealed = true;
+
+        m->n_iovec = 1;
+        m->iovec[0].iov_base = buffer;
+        m->iovec[0].iov_len = length;
+
+        r = message_parse_fields(m);
+        if (r < 0) {
+                message_free(m);
+                return r;
+        }
+
+        *ret = m;
+        return 0;
+}
+
 static sd_bus_message *message_new(sd_bus *bus, uint8_t type) {
         sd_bus_message *m;
 
-        m = malloc0(ALIGN(sizeof(struct sd_bus_message)) + sizeof(struct bus_header));
+        m = malloc0(ALIGN(sizeof(sd_bus_message)) + sizeof(struct bus_header));
         if (!m)
                 return NULL;
 
         m->n_ref = 1;
         m->header = (struct bus_header*) ((uint8_t*) m + ALIGN(sizeof(struct sd_bus_message)));
-
-#if __BYTE_ORDER == __BIG_ENDIAN
-        m->header->endian = SD_BUS_BIG_ENDIAN;
-#else
-        m->header->endian = SD_BUS_LITTLE_ENDIAN;
-#endif
+        m->header->endian = SD_BUS_NATIVE_ENDIAN;
         m->header->type = type;
         m->header->version = bus ? bus->message_version : 1;
 
@@ -268,6 +323,8 @@ int sd_bus_message_new_signal(
         if (!t)
                 return -ENOMEM;
 
+        t->header->flags |= SD_BUS_MESSAGE_NO_REPLY_EXPECTED;
+
         r = message_append_field_string(t, SD_BUS_MESSAGE_HEADER_PATH, SD_BUS_TYPE_OBJECT_PATH, path, &t->path);
         if (r < 0)
                 goto fail;
@@ -355,6 +412,7 @@ static int message_new_reply(
         if (!t)
                 return -ENOMEM;
 
+        t->header->flags |= SD_BUS_MESSAGE_NO_REPLY_EXPECTED;
         t->reply_serial = BUS_MESSAGE_SERIAL(call);
 
         r = message_append_field_uint32(t, SD_BUS_MESSAGE_HEADER_REPLY_SERIAL, t->reply_serial);
@@ -370,6 +428,7 @@ static int message_new_reply(
         t->dont_send = !!(call->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED);
 
         *m = t;
+        return 0;
 
 fail:
         message_free(t);
@@ -393,9 +452,7 @@ int sd_bus_message_new_method_error(
         sd_bus_message *t;
         int r;
 
-        if (!e)
-                return -EINVAL;
-        if (!e->name)
+        if (!sd_bus_error_is_set(e))
                 return -EINVAL;
         if (!m)
                 return -EINVAL;
@@ -1491,7 +1548,7 @@ static int bus_message_enter_array(
                 return r;
 
         if (BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q) > 67108864)
-                return -E2BIG;
+                return -EBADMSG;
 
         r = message_peek_body(m, &rindex, alignment, 0, NULL);
         if (r < 0)
@@ -1752,6 +1809,8 @@ int sd_bus_message_peek_type(sd_bus_message *m, char *type, const char **content
                         if (r < 0)
                                 return r;
 
+                        assert(l >= 1);
+
                         sig = strndup(c->signature + c->index + 1, l);
                         if (!sig)
                                 return -ENOMEM;
@@ -1837,7 +1896,7 @@ eof:
         return 0;
 }
 
-int sd_bus_message_rewind(sd_bus_message *m, bool complete) {
+int sd_bus_message_rewind(sd_bus_message *m, int complete) {
         struct bus_container *c;
 
         if (!m)
@@ -2011,15 +2070,368 @@ int sd_bus_message_read(sd_bus_message *m, const char *types, ...) {
         return r;
 }
 
-int bus_message_parse(sd_bus_message *m) {
+static int message_peek_fields(
+                sd_bus_message *m,
+                size_t *rindex,
+                size_t align,
+                size_t nbytes,
+                void **ret) {
+
+        assert(m);
+        assert(rindex);
+        assert(align > 0);
+
+        return buffer_peek(m->fields, BUS_MESSAGE_FIELDS_SIZE(m), rindex, align, nbytes, ret);
+}
+
+static int message_peek_field_string(
+                sd_bus_message *m,
+                size_t *ri,
+                const char **ret) {
+
+        size_t l;
+        int r;
+        void *q;
+
+        assert(m);
+        assert(ri);
+
+        r = message_peek_fields(m, ri, 4, 4, &q);
+        if (r < 0)
+                return r;
+
+        l = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q);
+        r = message_peek_fields(m, ri, 1, l+1, &q);
+        if (r < 0)
+                return r;
+
+        if (!validate_string(q, l))
+                return -EBADMSG;
+
+        if (ret)
+                *ret = q;
+
+        return 0;
+}
+
+static int message_peek_field_signature(
+                sd_bus_message *m,
+                size_t *ri,
+                const char **ret) {
+
+        size_t l;
+        int r;
+        void *q;
+
+        assert(m);
+        assert(ri);
+
+        r = message_peek_fields(m, ri, 1, 1, &q);
+        if (r < 0)
+                return r;
+
+        l = *(uint8_t*) q;
+        r = message_peek_fields(m, ri, 1, l+1, &q);
+        if (r < 0)
+                return r;
+
+        if (!validate_signature(q, l))
+                return -EBADMSG;
+
+        if (ret)
+                *ret = q;
+
+        return 0;
+}
+
+static int message_peek_field_uint32(
+                sd_bus_message *m,
+                size_t *ri,
+                uint32_t *ret) {
+
+        int r;
+        void *q;
+
+        assert(m);
+        assert(ri);
+
+        r = message_peek_fields(m, ri, 4, 4, &q);
+        if (r < 0)
+                return r;
+
+        if (ret)
+                *ret = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q);
+
+        return 0;
+}
+
+static int message_skip_fields(
+                sd_bus_message *m,
+                size_t *ri,
+                uint32_t array_size,
+                const char **signature) {
+
+        size_t original_index;
+        int r;
+
+        assert(m);
+        assert(ri);
+        assert(signature);
+
+        original_index = *ri;
+
+        for (;;) {
+                char t;
+                void *q;
+                size_t l;
+
+                if (array_size != (uint32_t) -1 &&
+                    array_size <= *ri - original_index)
+                        return 0;
+
+                t = **signature;
+                if (!t)
+                        return 0;
+
+                if (t == SD_BUS_TYPE_STRING ||
+                    t == SD_BUS_TYPE_OBJECT_PATH) {
+
+                        r = message_peek_field_string(m, ri, NULL);
+                        if (r < 0)
+                                return r;
+
+                        (*signature)++;
+
+                } else if (t == SD_BUS_TYPE_SIGNATURE) {
+
+                        r = message_peek_field_signature(m, ri, NULL);
+                        if (r < 0)
+                                return r;
+
+                        (*signature)++;
+
+                } else if (bus_type_is_basic(t)) {
+                        size_t align, k;
+
+                        align = bus_type_get_alignment(t);
+                        k = bus_type_get_size(t);
+
+                        r = message_peek_fields(m, ri, align, k, NULL);
+                        if (r < 0)
+                                return r;
+
+                        (*signature)++;
+
+                } else if (t == SD_BUS_TYPE_ARRAY) {
+
+                        r = signature_element_length(*signature+1, &l);
+                        if (r < 0)
+                                return r;
+
+                        assert(l >= 1);
+                        {
+                                char sig[l-1], *s;
+                                size_t nas;
+                                int alignment;
+
+                                strncpy(sig, *signature + 1, l-1);
+                                s = sig;
+
+                                alignment = bus_type_get_alignment(sig[0]);
+                                if (alignment < 0)
+                                        return alignment;
+
+                                r = message_peek_fields(m, ri, 4, 4, &q);
+                                if (r < 0)
+                                        return r;
+
+                                nas = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q);
+                                if (nas > 67108864)
+                                        return -EBADMSG;
+
+                                r = message_peek_fields(m, ri, alignment, 0, NULL);
+                                if (r < 0)
+                                        return r;
+
+                                r = message_skip_fields(m, ri, nas, (const char**) &s);
+                                if (r < 0)
+                                        return r;
+                        }
+
+                        (*signature) += 1 + l;
+
+                } else if (t == SD_BUS_TYPE_VARIANT) {
+                        const char *s;
+
+                        r = message_peek_field_signature(m, ri, &s);
+                        if (r < 0)
+                                return r;
+
+                        r = message_skip_fields(m, ri, (uint32_t) -1, (const char**) &s);
+                        if (r < 0)
+                                return r;
+
+                        (*signature)++;
+
+                } else if (t == SD_BUS_TYPE_STRUCT ||
+                           t == SD_BUS_TYPE_DICT_ENTRY) {
+
+                        r = signature_element_length(*signature, &l);
+                        if (r < 0)
+                                return r;
+
+                        assert(l >= 2);
+                        {
+                                char sig[l-1], *s;
+                                strncpy(sig, *signature + 1, l-1);
+                                s = sig;
+
+                                r = message_skip_fields(m, ri, (uint32_t) -1, (const char**) &s);
+                                if (r < 0)
+                                        return r;
+                        }
+
+                        *signature += l;
+                } else
+                        return -EINVAL;
+        }
+}
+
+static int message_parse_fields(sd_bus_message *m) {
+        size_t ri;
+        int r;
+
         assert(m);
 
-        if (m->header->version != 1)
-                return -EIO;
+        for (ri = 0; ri < BUS_MESSAGE_FIELDS_SIZE(m); ) {
+                const char *signature;
+                uint8_t *header;
+
+                r = message_peek_fields(m, &ri, 8, 1, (void**) &header);
+                if (r < 0)
+                        return r;
+
+                r = message_peek_field_signature(m, &ri, &signature);
+                if (r < 0)
+                        return r;
+
+                switch (*header) {
+                case _SD_BUS_MESSAGE_HEADER_INVALID:
+                        return -EBADMSG;
+
+                case SD_BUS_MESSAGE_HEADER_PATH:
+                        if (!streq(signature, "o"))
+                                return -EBADMSG;
+
+                        r = message_peek_field_string(m, &ri, &m->path);
+                        break;
+
+                case SD_BUS_MESSAGE_HEADER_INTERFACE:
+                        if (!streq(signature, "s"))
+                                return -EBADMSG;
+
+                        r = message_peek_field_string(m, &ri, &m->interface);
+                        break;
+
+                case SD_BUS_MESSAGE_HEADER_MEMBER:
+                        if (!streq(signature, "s"))
+                                return -EBADMSG;
+
+                        r = message_peek_field_string(m, &ri, &m->member);
+                        break;
+
+                case SD_BUS_MESSAGE_HEADER_ERROR_NAME:
+                        if (!streq(signature, "s"))
+                                return -EBADMSG;
+
+                        r = message_peek_field_string(m, &ri, &m->error.name);
+                        break;
+
+                case SD_BUS_MESSAGE_HEADER_DESTINATION:
+                        if (!streq(signature, "s"))
+                                return -EBADMSG;
+
+                        r = message_peek_field_string(m, &ri, &m->destination);
+                        break;
+
+                case SD_BUS_MESSAGE_HEADER_SENDER:
+                        if (!streq(signature, "s"))
+                                return -EBADMSG;
+
+                        r = message_peek_field_string(m, &ri, &m->sender);
+                        break;
+
+
+                case SD_BUS_MESSAGE_HEADER_SIGNATURE: {
+                        const char *s;
+                        char *c;
+
+                        if (!streq(signature, "g"))
+                                return -EBADMSG;
+
+                        r = message_peek_field_signature(m, &ri, &s);
+                        if (r < 0)
+                                return r;
+
+                        c = strdup(s);
+                        if (!c)
+                                return -ENOMEM;
+
+                        free(m->root_container.signature);
+                        m->root_container.signature = c;
+
+                        r = 0;
+                        break;
+                }
+
+                case SD_BUS_MESSAGE_HEADER_REPLY_SERIAL:
+                        if (!streq(signature, "u"))
+                                return -EBADMSG;
+
+                        r = message_peek_field_uint32(m, &ri, &m->reply_serial);
+                        break;
+
+                default:
+                        r = message_skip_fields(m, &ri, (uint32_t) -1, (const char **) &signature);
+                }
+
+                if (r < 0)
+                        return r;
+        }
+
+        if (isempty(m->root_container.signature) != (BUS_MESSAGE_BODY_SIZE(m) == 0))
+                return -EBADMSG;
+
+        switch (m->header->type) {
+
+        case SD_BUS_MESSAGE_TYPE_SIGNAL:
+                if (!m->path || !m->interface || !m->member)
+                        return -EBADMSG;
+                break;
+
+        case SD_BUS_MESSAGE_TYPE_METHOD_CALL:
+
+                if (!m->path || !m->member)
+                        return -EBADMSG;
+
+                break;
+
+        case SD_BUS_MESSAGE_TYPE_METHOD_RETURN:
+
+                if (m->reply_serial == 0)
+                        return -EBADMSG;
+                break;
+
+        case SD_BUS_MESSAGE_TYPE_METHOD_ERROR:
+
+                if (m->reply_serial == 0 || !m->error.name)
+                        return -EBADMSG;
+                break;
+        }
 
-        if (m->header->endian != SD_BUS_BIG_ENDIAN &&
-            m->header->endian != SD_BUS_LITTLE_ENDIAN)
-                return -EIO;
+        /* Try to read the error message, but if we can't it's a non-issue */
+        if (m->header->type == SD_BUS_MESSAGE_TYPE_METHOD_ERROR)
+                sd_bus_message_read(m, "s", &m->error.message);
 
         return 0;
 }
@@ -2068,7 +2480,7 @@ int bus_message_seal(sd_bus_message *m, uint64_t serial) {
 
         /* If there's a non-trivial signature set, then add it in here */
         if (!isempty(m->root_container.signature)) {
-                r = message_append_field_signature(m, SD_BUS_MESSAGE_HEADER_SIGNATURE, m->root_container.signature, &m->signature);
+                r = message_append_field_signature(m, SD_BUS_MESSAGE_HEADER_SIGNATURE, m->root_container.signature, NULL);
                 if (r < 0)
                         return r;
         }
@@ -2139,7 +2551,7 @@ int bus_message_dump(sd_bus_message *m) {
                strna(m->member),
                strna(m->destination),
                strna(m->sender),
-               strna(m->signature),
+               strna(m->root_container.signature),
                m->reply_serial,
                strna(m->error.name),
                strna(m->error.message),
@@ -2151,7 +2563,7 @@ int bus_message_dump(sd_bus_message *m) {
                 return r;
         }
 
-        printf("BEGIN_MESSAGE \"%s\" {\n", strempty(m->signature));
+        printf("BEGIN_MESSAGE \"%s\" {\n", strempty(m->root_container.signature));
 
         for(;;) {
                 _cleanup_free_ char *prefix = NULL;
@@ -2321,3 +2733,34 @@ int bus_message_get_blob(sd_bus_message *m, void **buffer, size_t *sz) {
 
         return 0;
 }
+
+int bus_message_read_strv_extend(sd_bus_message *m, char ***l) {
+        int r;
+
+        assert(m);
+        assert(l);
+
+        r = sd_bus_message_enter_container(m, 'a', "s");
+        if (r < 0)
+                return r;
+
+        for (;;) {
+                const char *s;
+
+                r = sd_bus_message_read_basic(m, 's', &s);
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        break;
+
+                r = strv_extend(l, s);
+                if (r < 0)
+                        return r;
+        }
+
+        r = sd_bus_message_exit_container(m);
+        if (r < 0)
+                return r;
+
+        return 0;
+}