chiark / gitweb /
bus: add API for appending/reading fixed arrays
authorLennart Poettering <lennart@poettering.net>
Thu, 9 May 2013 18:00:51 +0000 (20:00 +0200)
committerLennart Poettering <lennart@poettering.net>
Thu, 9 May 2013 18:01:21 +0000 (20:01 +0200)
src/libsystemd-bus/bus-message.c
src/libsystemd-bus/bus-message.h
src/libsystemd-bus/bus-type.c
src/libsystemd-bus/bus-type.h
src/libsystemd-bus/test-bus-marshal.c
src/systemd/sd-bus.h

index 835a9f9a443efcd47777470d05fbae85c25de91e..afd4551b4ef0cbf175c19716aa117c6cecfc09c6 100644 (file)
@@ -1438,6 +1438,7 @@ int sd_bus_message_open_container(
         struct bus_container *c, *w;
         uint32_t *array_size = NULL;
         char *signature;
+        size_t before;
         int r;
 
         if (!m)
@@ -1459,6 +1460,11 @@ int sd_bus_message_open_container(
         if (!signature)
                 return -ENOMEM;
 
+        /* Save old index in the parent container, in case we have to
+         * abort this container */
+        c->saved_index = c->index;
+        before = m->header->body_size;
+
         if (type == SD_BUS_TYPE_ARRAY)
                 r = bus_message_open_array(m, c, contents, &array_size);
         else if (type == SD_BUS_TYPE_VARIANT)
@@ -1481,7 +1487,8 @@ int sd_bus_message_open_container(
         w->signature = signature;
         w->index = 0;
         w->array_size = array_size;
-        w->begin = 0;
+        w->before = before;
+        w->begin = m->rindex;
 
         return 0;
 }
@@ -1507,6 +1514,36 @@ int sd_bus_message_close_container(sd_bus_message *m) {
         return 0;
 }
 
+static void message_abort_container(sd_bus_message *m) {
+        struct bus_container *c;
+        size_t delta;
+
+        assert(m);
+        assert(!m->sealed);
+        assert(m->n_containers > 0);
+
+        c = message_get_container(m);
+
+        /* Undo appends */
+        assert(m->header->body_size >= c->before);
+        delta = m->header->body_size - c->before;
+        m->header->body_size = c->before;
+
+        /* Free container */
+        free(c->signature);
+        m->n_containers--;
+
+        /* Correct index of new top-level container */
+        c = message_get_container(m);
+        c->index = c->saved_index;
+
+        /* Correct array sizes all the way up */
+        for (c = m->containers; c < m->containers + m->n_containers; c++)
+                if (c->array_size) {
+                        assert(*c->array_size >= delta);
+                        *c->array_size -= delta;
+                }
+}
 
 typedef struct {
         const char *types;
@@ -1762,6 +1799,68 @@ int sd_bus_message_append(sd_bus_message *m, const char *types, ...) {
         return r;
 }
 
+int sd_bus_message_append_array_ptr(sd_bus_message *m, char type, size_t size, void **ptr) {
+        ssize_t align, sz;
+        void *a;
+        int r;
+
+        if (!m)
+                return -EINVAL;
+        if (m->sealed)
+                return -EPERM;
+        if (!bus_type_is_trivial(type))
+                return -EINVAL;
+        if (!ptr && size > 0)
+                return -EINVAL;
+
+        align = bus_type_get_alignment(type);
+        sz = bus_type_get_size(type);
+
+        assert_se(align > 0);
+        assert_se(sz > 0);
+
+        if (size % sz != 0)
+                return -EINVAL;
+
+        r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, CHAR_TO_STR(type));
+        if (r < 0)
+                return r;
+
+        a = message_extend_body(m, align, size);
+        if (!a) {
+                r = -ENOMEM;
+                goto fail;
+        }
+
+        r = sd_bus_message_close_container(m);
+        if (r < 0)
+                goto fail;
+
+        *ptr = a;
+        return 0;
+
+fail:
+        message_abort_container(m);
+        return r;
+}
+
+int sd_bus_message_append_array(sd_bus_message *m, char type, const void *ptr, size_t size) {
+        int r;
+        void *p;
+
+        if (!ptr && size > 0)
+                return -EINVAL;
+
+        r = sd_bus_message_append_array_ptr(m, type, size, &p);
+        if (r < 0)
+                return r;
+
+        if (size > 0)
+                memcpy(p, ptr, size);
+
+        return 0;
+}
+
 static int buffer_peek(const void *p, uint32_t sz, size_t *rindex, size_t align, size_t nbytes, void **r) {
         size_t k, start, n;
 
@@ -1990,7 +2089,7 @@ int sd_bus_message_read_basic(sd_bus_message *m, char type, void *p) {
                         assert_not_reached("Unknown basic type...");
                 }
 
-                        m->rindex = rindex;
+                m->rindex = rindex;
 
                 break;
         }
@@ -2186,6 +2285,7 @@ int sd_bus_message_enter_container(sd_bus_message *m, char type, const char *con
         struct bus_container *c, *w;
         uint32_t *array_size = NULL;
         char *signature;
+        size_t before;
         int r;
 
         if (!m)
@@ -2228,6 +2328,9 @@ int sd_bus_message_enter_container(sd_bus_message *m, char type, const char *con
         if (!signature)
                 return -ENOMEM;
 
+        c->saved_index = c->index;
+        before = m->rindex;
+
         if (type == SD_BUS_TYPE_ARRAY)
                 r = bus_message_enter_array(m, c, contents, &array_size);
         else if (type == SD_BUS_TYPE_VARIANT)
@@ -2250,6 +2353,7 @@ int sd_bus_message_enter_container(sd_bus_message *m, char type, const char *con
         w->signature = signature;
         w->index = 0;
         w->array_size = array_size;
+        w->before = before;
         w->begin = m->rindex;
 
         return 1;
@@ -2284,6 +2388,28 @@ int sd_bus_message_exit_container(sd_bus_message *m) {
         return 1;
 }
 
+static void message_quit_container(sd_bus_message *m) {
+        struct bus_container *c;
+
+        assert(m);
+        assert(m->sealed);
+        assert(m->n_containers > 0);
+
+        c = message_get_container(m);
+
+        /* Undo seeks */
+        assert(m->rindex >= c->before);
+        m->rindex = c->before;
+
+        /* Free container */
+        free(c->signature);
+        m->n_containers--;
+
+        /* Correct index of new top-level container */
+        c = message_get_container(m);
+        c->index = c->saved_index;
+}
+
 int sd_bus_message_peek_type(sd_bus_message *m, char *type, const char **contents) {
         struct bus_container *c;
         int r;
@@ -2627,6 +2753,59 @@ int sd_bus_message_read(sd_bus_message *m, const char *types, ...) {
         return r;
 }
 
+int sd_bus_message_read_array(sd_bus_message *m, char type, const void **ptr, size_t *size) {
+        struct bus_container *c;
+        void *p;
+        size_t sz;
+        ssize_t align;
+        int r;
+
+        if (!m)
+                return -EINVAL;
+        if (!m->sealed)
+                return -EPERM;
+        if (!bus_type_is_trivial(type))
+                return -EINVAL;
+        if (!ptr)
+                return -EINVAL;
+        if (!size)
+                return -EINVAL;
+        if (BUS_MESSAGE_NEED_BSWAP(m))
+                return -ENOTSUP;
+
+        align = bus_type_get_alignment(type);
+        if (align < 0)
+                return align;
+
+        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, CHAR_TO_STR(type));
+        if (r < 0)
+                return r;
+
+        c = message_get_container(m);
+        sz = BUS_MESSAGE_BSWAP32(m, *c->array_size);
+
+        r = message_peek_body(m, &m->rindex, align, sz, &p);
+        if (r < 0)
+                goto fail;
+        if (r == 0) {
+                r = -EBADMSG;
+                goto fail;
+        }
+
+        r = sd_bus_message_exit_container(m);
+        if (r < 0)
+                goto fail;
+
+        *ptr = (const void*) p;
+        *size = sz;
+
+        return 1;
+
+fail:
+        message_quit_container(m);
+        return r;
+}
+
 static int message_peek_fields(
                 sd_bus_message *m,
                 size_t *rindex,
index 9c0829c7fabe7174b01de62914d81e290f755b24..eafbb7c6ce71bda89fc124a6972c9a8df14546e3 100644 (file)
@@ -34,10 +34,10 @@ struct bus_container {
         char enclosing;
 
         char *signature;
-        unsigned index;
+        unsigned index, saved_index;
 
         uint32_t *array_size;
-        size_t begin;
+        size_t before, begin;
 };
 
 struct bus_header {
index 0557328085cf27593f46af4d11e613991e0cc933..6354c84f2c59ad02211d8c8ea554bba3aa94e7c3 100644 (file)
@@ -92,6 +92,23 @@ bool bus_type_is_basic(char c) {
         return !!memchr(valid, c, sizeof(valid));
 }
 
+bool bus_type_is_trivial(char c) {
+        static const char valid[] = {
+                SD_BUS_TYPE_BYTE,
+                SD_BUS_TYPE_BOOLEAN,
+                SD_BUS_TYPE_INT16,
+                SD_BUS_TYPE_UINT16,
+                SD_BUS_TYPE_INT32,
+                SD_BUS_TYPE_UINT32,
+                SD_BUS_TYPE_INT64,
+                SD_BUS_TYPE_UINT64,
+                SD_BUS_TYPE_DOUBLE
+        };
+
+        return !!memchr(valid, c, sizeof(valid));
+}
+
+
 bool bus_type_is_container(char c) {
         static const char valid[] = {
                 SD_BUS_TYPE_ARRAY,
index e2611360846313038d587d4d5874d09542c2fe30..122628c66bc38c19c8e786b128ec5e7b1185f11e 100644 (file)
@@ -29,6 +29,7 @@
 bool bus_type_is_valid(char c);
 bool bus_type_is_valid_in_signature(char c);
 bool bus_type_is_basic(char c);
+bool bus_type_is_trivial(char c);
 bool bus_type_is_container(char c);
 int bus_type_get_alignment(char c);
 int bus_type_get_size(char c);
index 20ae723fbe1a3640014399ec98c690f81f86d485..ac519531f79fca90f8d0906b5b6a92a2ec6ea75d 100644 (file)
@@ -43,6 +43,7 @@ int main(int argc, char *argv[]) {
         void *buffer = NULL;
         size_t sz;
         char *h;
+        const int32_t integer_array[] = { -1, -2, 0, 1, 2 }, *return_array;
 
         r = sd_bus_message_new_method_call(NULL, "foobar.waldo", "/", "foobar.waldo", "Piep", &m);
         assert_se(r >= 0);
@@ -77,6 +78,9 @@ int main(int argc, char *argv[]) {
         r = sd_bus_message_close_container(m);
         assert_se(r >= 0);
 
+        r = sd_bus_message_append_array(m, 'i', integer_array, sizeof(integer_array));
+        assert_se(r >= 0);
+
         r = bus_message_seal(m, 4711);
         assert_se(r >= 0);
 
@@ -168,6 +172,11 @@ int main(int argc, char *argv[]) {
         assert_se(streq(x, "foobar"));
         assert_se(streq(y, "waldo"));
 
+        r = sd_bus_message_read_array(m, 'i', (const void**) &return_array, &sz);
+        assert_se(r > 0);
+        assert_se(sz == sizeof(integer_array));
+        assert_se(memcmp(integer_array, return_array, sz) == 0);
+
         r = sd_bus_message_peek_type(m, NULL, NULL);
         assert_se(r == 0);
 
index c1ec50871fd0bca315e3996e3b0fdaaedb4189f7..2dab93d9168c358c29f9090b39619527e1874719 100644 (file)
@@ -41,15 +41,10 @@ extern "C" {
 #endif
 
 /* TODO:
- * - add page donation logic
- * - api for appending/reading fixed arrays
  * - merge busctl into systemctl or so?
  * - default policy (allow uid == 0 and our own uid)
- *
  * - enforce alignment of pointers passed in
  * - negotiation for attach attributes
- *
- * - for kernel and unix transports allow setting the unix user/access mode for the node
  */
 
 typedef struct sd_bus sd_bus;
@@ -173,6 +168,11 @@ int sd_bus_message_exit_container(sd_bus_message *m);
 int sd_bus_message_peek_type(sd_bus_message *m, char *type, const char **contents);
 int sd_bus_message_rewind(sd_bus_message *m, int complete);
 
+int sd_bus_message_append_array(sd_bus_message *m, char type, const void *ptr, size_t size);
+int sd_bus_message_append_array_ptr(sd_bus_message *m, char type, size_t size, void **ptr);
+
+int sd_bus_message_read_array(sd_bus_message *m, char type, const void **ptr, size_t *size);
+
 /* Convenience calls */
 
 int sd_bus_emit_signal(sd_bus *bus, const char *path, const char *interface, const char *member, const char *types, ...);