m->n_iovec = 1;
m->iovec[0].iov_base = buffer;
m->iovec[0].iov_len = length;
+ m->size = length;
r = message_parse_fields(m);
if (r < 0)
m->header->endian = SD_BUS_NATIVE_ENDIAN;
m->header->type = type;
m->header->version = bus ? bus->message_version : 1;
- m->allow_fds = !bus || bus->can_fds;
+ m->allow_fds = !bus || bus->can_fds || (bus->state != BUS_HELLO && bus->state != BUS_RUNNING);
return m;
}
return -EINVAL;
if (!m)
return -EINVAL;
+ if (bus && bus->state == BUS_UNSET)
+ return -ENOTCONN;
t = message_new(bus, SD_BUS_MESSAGE_TYPE_SIGNAL);
if (!t)
return -EINVAL;
if (!m)
return -EINVAL;
+ if (bus && bus->state == BUS_UNSET)
+ return -ENOTCONN;
t = message_new(bus, SD_BUS_MESSAGE_TYPE_METHOD_CALL);
if (!t)
return -EINVAL;
if (!m)
return -EINVAL;
+ if (bus && bus->state == BUS_UNSET)
+ return -ENOTCONN;
t = message_new(bus, type);
if (!t)
int message_append_basic(sd_bus_message *m, char type, const void *p, const void **stored) {
struct bus_container *c;
- size_t sz, align;
+ ssize_t align, sz;
uint32_t k;
void *a;
char *e = NULL;
int fd = -1;
- uint32_t fdi;
+ uint32_t fdi = 0;
int r;
if (!m)
return 0;
}
-static int message_append_ap(
+
+typedef struct {
+ const char *types;
+ unsigned n_struct;
+ unsigned n_array;
+} TypeStack;
+
+static int type_stack_push(TypeStack *stack, unsigned max, unsigned *i, const char *types, unsigned n_struct, unsigned n_array) {
+ assert(stack);
+ assert(max > 0);
+
+ if (*i >= max)
+ return -EINVAL;
+
+ stack[*i].types = types;
+ stack[*i].n_struct = n_struct;
+ stack[*i].n_array = n_array;
+ (*i)++;
+
+ return 0;
+}
+
+static int type_stack_pop(TypeStack *stack, unsigned max, unsigned *i, const char **types, unsigned *n_struct, unsigned *n_array) {
+ assert(stack);
+ assert(max > 0);
+ assert(types);
+ assert(n_struct);
+ assert(n_array);
+
+ if (*i <= 0)
+ return 0;
+
+ (*i)--;
+ *types = stack[*i].types;
+ *n_struct = stack[*i].n_struct;
+ *n_array = stack[*i].n_array;
+
+ return 1;
+}
+
+int bus_message_append_ap(
sd_bus_message *m,
const char *types,
va_list ap) {
- const char *t;
+ unsigned n_array, n_struct;
+ TypeStack stack[BUS_CONTAINER_DEPTH];
+ unsigned stack_ptr = 0;
int r;
assert(m);
- assert(types);
- for (t = types; *t; t++) {
+ if (!types)
+ return 0;
+
+ n_array = (unsigned) -1;
+ n_struct = strlen(types);
+
+ for (;;) {
+ const char *t;
+
+ if (n_array == 0 || (n_array == (unsigned) -1 && n_struct == 0)) {
+ r = type_stack_pop(stack, ELEMENTSOF(stack), &stack_ptr, &types, &n_struct, &n_array);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ break;
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return r;
+
+ continue;
+ }
+
+ t = types;
+ if (n_array != (unsigned) -1)
+ n_array --;
+ else {
+ types ++;
+ n_struct--;
+ }
+
switch (*t) {
case SD_BUS_TYPE_BYTE: {
return r;
{
- unsigned i, n;
char s[k + 1];
-
memcpy(s, t + 1, k);
s[k] = 0;
- t += k;
r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, s);
if (r < 0)
return r;
+ }
- n = va_arg(ap, unsigned);
- for (i = 0; i < n; i++) {
- r = message_append_ap(m, s, ap);
- if (r < 0)
- return r;
- }
-
- r = sd_bus_message_close_container(m);
+ if (n_array == (unsigned) -1) {
+ types += k;
+ n_struct -= k;
}
+ r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array);
+ if (r < 0)
+ return r;
+
+ types = t + 1;
+ n_struct = k;
+ n_array = va_arg(ap, unsigned);
+
break;
}
if (r < 0)
return r;
- r = message_append_ap(m, s, ap);
+ r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array);
if (r < 0)
return r;
- r = sd_bus_message_close_container(m);
+ types = s;
+ n_struct = strlen(s);
+ n_array = (unsigned) -1;
+
break;
}
r = sd_bus_message_open_container(m, *t == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY, s);
if (r < 0)
return r;
+ }
- t += k - 1;
+ if (n_array == (unsigned) -1) {
+ types += k - 1;
+ n_struct -= k - 1;
+ }
- r = message_append_ap(m, s, ap);
- if (r < 0)
- return r;
+ r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array);
+ if (r < 0)
+ return r;
- r = sd_bus_message_close_container(m);
- }
+ types = t + 1;
+ n_struct = k - 2;
+ n_array = (unsigned) -1;
break;
}
if (m->sealed)
return -EPERM;
if (!types)
- return -EINVAL;
+ return 0;
va_start(ap, types);
- r = message_append_ap(m, types, ap);
+ r = bus_message_append_ap(m, types, ap);
va_end(ap);
return r;
}
default: {
- size_t sz, align, rindex;
+ ssize_t sz, align;
+ size_t rindex;
align = bus_type_get_alignment(type);
sz = bus_type_get_size(type);
+ assert(align > 0 && sz > 0);
rindex = m->rindex;
r = message_peek_body(m, &rindex, align, sz, &q);
return !isempty(c->signature);
}
+static int message_read_ap(
+ sd_bus_message *m,
+ const char *types,
+ va_list ap) {
-static int message_read_ap(sd_bus_message *m, const char *types, va_list ap) {
- const char *t;
+ unsigned n_array, n_struct;
+ TypeStack stack[BUS_CONTAINER_DEPTH];
+ unsigned stack_ptr = 0;
int r;
assert(m);
- assert(types);
- for (t = types; *t; t++) {
+ if (!types)
+ return 0;
+
+ /* Ideally, we'd just call ourselves recursively on every
+ * complex type. However, the state of a va_list that is
+ * passed to a function is undefined after that function
+ * returns. This means we need to docode the va_list linearly
+ * in a single stackframe. We hence implement our own
+ * home-grown stack in an array. */
+
+ n_array = (unsigned) -1;
+ n_struct = strlen(types);
+
+ for (;;) {
+ const char *t;
+
+ if (n_array == 0 || (n_array == (unsigned) -1 && n_struct == 0)) {
+ r = type_stack_pop(stack, ELEMENTSOF(stack), &stack_ptr, &types, &n_struct, &n_array);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ break;
+
+ r = sd_bus_message_exit_container(m);
+ if (r < 0)
+ return r;
+
+ continue;
+ }
+
+ t = types;
+ if (n_array != (unsigned) -1)
+ n_array --;
+ else {
+ types ++;
+ n_struct--;
+ }
+
switch (*t) {
case SD_BUS_TYPE_BYTE:
p = va_arg(ap, void*);
r = sd_bus_message_read_basic(m, *t, p);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return -ENXIO;
+
break;
}
return r;
{
- unsigned i, n;
char s[k + 1];
-
memcpy(s, t + 1, k);
s[k] = 0;
- t += k;
r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, s);
if (r < 0)
return r;
if (r == 0)
return -ENXIO;
+ }
- n = va_arg(ap, unsigned);
- for (i = 0; i < n; i++) {
- r = message_read_ap(m, s, ap);
- if (r < 0)
- return r;
- }
-
- r = sd_bus_message_exit_container(m);
+ if (n_array == (unsigned) -1) {
+ types += k;
+ n_struct -= k;
}
+ r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array);
+ if (r < 0)
+ return r;
+
+ types = t + 1;
+ n_struct = k;
+ n_array = va_arg(ap, unsigned);
+
break;
}
if (r == 0)
return -ENXIO;
- r = message_read_ap(m, s, ap);
+ r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array);
if (r < 0)
return r;
- if (r == 0)
- return -ENXIO;
- r = sd_bus_message_exit_container(m);
+ types = s;
+ n_struct = strlen(s);
+ n_array = (unsigned) -1;
+
break;
}
return r;
if (r == 0)
return -ENXIO;
+ }
- t += k - 1;
+ if (n_array == (unsigned) -1) {
+ types += k - 1;
+ n_struct -= k - 1;
+ }
- r = message_read_ap(m, s, ap);
- if (r < 0)
- return r;
- if (r == 0)
- return -ENXIO;
+ r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array);
+ if (r < 0)
+ return r;
- r = sd_bus_message_exit_container(m);
- }
+ types = t + 1;
+ n_struct = k - 2;
+ n_array = (unsigned) -1;
break;
}
default:
- r = -EINVAL;
+ return -EINVAL;
}
-
- if (r < 0)
- return r;
- if (r == 0)
- return -ENXIO;
}
return 1;
(*signature)++;
} else if (bus_type_is_basic(t)) {
- size_t align, k;
+ ssize_t align, k;
align = bus_type_get_alignment(t);
k = bus_type_get_size(t);
+ assert(align > 0 && k > 0);
r = message_peek_fields(m, ri, align, k, NULL);
if (r < 0)
return 0;
}
+
+const char* bus_message_get_arg(sd_bus_message *m, unsigned i) {
+ int r;
+ const char *t;
+ char type;
+
+ assert(m);
+
+ r = sd_bus_message_rewind(m, true);
+ if (r < 0)
+ return NULL;
+
+ while (i > 0) {
+ r = sd_bus_message_peek_type(m, &type, NULL);
+ if (r < 0)
+ return NULL;
+
+ if (type != SD_BUS_TYPE_STRING &&
+ type != SD_BUS_TYPE_OBJECT_PATH &&
+ type != SD_BUS_TYPE_SIGNATURE)
+ return NULL;
+
+ r = sd_bus_message_read_basic(m, type, &t);
+ if (r < 0)
+ return NULL;
+
+ i--;
+ }
+
+ r = sd_bus_message_rewind(m, true);
+ if (r < 0)
+ return NULL;
+
+ return t;
+}