2013-03-19 20:03:16 +01:00
|
|
|
/***
|
|
|
|
This file is part of systemd.
|
|
|
|
|
|
|
|
Copyright 2013 Lennart Poettering
|
|
|
|
|
|
|
|
systemd is free software; you can redistribute it and/or modify it
|
|
|
|
under the terms of the GNU Lesser General Public License as published by
|
|
|
|
the Free Software Foundation; either version 2.1 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
systemd is distributed in the hope that it will be useful, but
|
|
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
Lesser General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Lesser General Public License
|
|
|
|
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
***/
|
|
|
|
|
2015-01-23 01:13:09 +01:00
|
|
|
#include <math.h>
|
2015-11-16 22:09:36 +01:00
|
|
|
#include <stdlib.h>
|
2013-03-19 20:03:16 +01:00
|
|
|
|
2017-10-03 10:41:51 +02:00
|
|
|
#if HAVE_GLIB
|
2013-03-19 20:03:16 +01:00
|
|
|
#include <gio/gio.h>
|
|
|
|
#endif
|
|
|
|
|
2017-10-03 10:41:51 +02:00
|
|
|
#if HAVE_DBUS
|
2013-11-19 21:12:59 +01:00
|
|
|
#include <dbus/dbus.h>
|
2013-11-06 02:03:05 +01:00
|
|
|
#endif
|
2013-03-19 20:03:16 +01:00
|
|
|
|
|
|
|
#include "sd-bus.h"
|
2015-10-24 22:58:24 +02:00
|
|
|
|
2015-10-27 03:01:06 +01:00
|
|
|
#include "alloc-util.h"
|
2013-11-12 00:12:08 +01:00
|
|
|
#include "bus-dump.h"
|
2014-03-11 19:03:50 +01:00
|
|
|
#include "bus-label.h"
|
2015-10-24 22:58:24 +02:00
|
|
|
#include "bus-message.h"
|
|
|
|
#include "bus-util.h"
|
2015-10-25 13:14:12 +01:00
|
|
|
#include "fd-util.h"
|
2015-10-26 16:41:43 +01:00
|
|
|
#include "hexdecoct.h"
|
2015-11-16 22:09:36 +01:00
|
|
|
#include "log.h"
|
2015-10-24 22:58:24 +02:00
|
|
|
#include "util.h"
|
2014-03-11 19:03:50 +01:00
|
|
|
|
bus: implement bus_path_{en,de}code_unique()
Whenever we provide a bus API that allows clients to create and manage
server-side objects, we need to provide a unique name for these objects.
There are two ways to provide them:
1) Let the server choose a name and return it as method reply.
2) Let the client pass its name of choice in the method arguments.
The first method is the easiest one to implement. However, it suffers from
a race condition: If a client creates an object asynchronously, it cannot
destroy that object until it received the method reply. It cannot know the
name of the new object, thus, it cannot destroy it. Furthermore, this
method enforces a round-trip. If the client _depends_ on the method call
to succeed (eg., it would close() the connection if it failed), the client
usually has no reason to wait for the method reply. Instead, the client
can immediately schedule further method calls on the newly created object
(in case the API guarantees in-order method-call handling).
The second method fixes both problems: The client passes an object name
with the method-call. The server uses it to create the object. Therefore,
the client can schedule object destruction even if the object-creation
hasn't finished, yet (again, requiring in-order method-call handling).
Furthermore, the client can schedule further method calls on the newly
created object, before the constructor returned.
There're two problems to solve, though:
1) Object names are usually defined via dbus object paths, which are
usually globally namespaced. Therefore, multiple clients must be able
to choose unique object names without interference.
2) If multiple libraries share the same bus connection, they must be
able to choose unique object names without interference.
The first problem is solved easily by prefixing a name with the
unique-bus-name of a connection. The server side must enforce this and
reject any other name.
The second problem is solved by providing unique suffixes from within
sd-bus. As long as sd-bus always returns a fresh new ID, if requested,
multiple libraries will never interfere. This implementation re-uses
bus->cookie as ID generator, which already provides unique IDs for each
bus connection.
This patch introduces two new helpers:
bus_path_encode_unique(sd_bus *bus,
const char *prefix,
const char *sender_id,
const char *external_id,
char **ret_path);
This creates a new object-path via the template
'/prefix/sender_id/external_id'. That is, it appends two new labels to
the given prefix. If 'sender_id' is NULL, it will use
bus->unique_name, if 'external_id' is NULL, it will allocate a fresh,
unique cookie from bus->cookie.
bus_path_decode_unique(const char *path,
const char *prefix,
char **ret_sender,
char **ret_external);
This reverses what bus_path_encode_unique() did. It parses 'path' from
the template '/prefix/sender/external' and returns both suffix-labels
in 'ret_sender' and 'ret_external'. In case the template does not
match, 0 is returned and both output arguments are set to NULL.
Otherwise, 1 is returned and the output arguments contain the decoded
labels.
Note: Client-side allocated IDs are inspired by the Wayland protocol
(which itself was inspired by X11). Wayland uses those IDs heavily
to avoid round-trips. Clients can create server-side objects and
send method calls without any round-trip and waiting for any object
IDs to be returned. But unlike Wayland, DBus uses gobally namespaced
object names. Therefore, we have to add the extra step by adding the
unique-name of the bus connection.
2015-04-10 17:44:30 +02:00
|
|
|
static void test_bus_path_encode_unique(void) {
|
|
|
|
_cleanup_free_ char *a = NULL, *b = NULL, *c = NULL, *d = NULL, *e = NULL;
|
|
|
|
|
|
|
|
assert_se(bus_path_encode_unique(NULL, "/foo/bar", "some.sender", "a.suffix", &a) >= 0 && streq_ptr(a, "/foo/bar/some_2esender/a_2esuffix"));
|
|
|
|
assert_se(bus_path_decode_unique(a, "/foo/bar", &b, &c) > 0 && streq_ptr(b, "some.sender") && streq_ptr(c, "a.suffix"));
|
|
|
|
assert_se(bus_path_decode_unique(a, "/bar/foo", &d, &d) == 0 && !d);
|
|
|
|
assert_se(bus_path_decode_unique("/foo/bar/onlyOneSuffix", "/foo/bar", &d, &d) == 0 && !d);
|
|
|
|
assert_se(bus_path_decode_unique("/foo/bar/_/_", "/foo/bar", &d, &e) > 0 && streq_ptr(d, "") && streq_ptr(e, ""));
|
|
|
|
}
|
|
|
|
|
2014-03-11 19:03:50 +01:00
|
|
|
static void test_bus_path_encode(void) {
|
|
|
|
_cleanup_free_ char *a = NULL, *b = NULL, *c = NULL, *d = NULL, *e = NULL, *f = NULL;
|
|
|
|
|
|
|
|
assert_se(sd_bus_path_encode("/foo/bar", "waldo", &a) >= 0 && streq(a, "/foo/bar/waldo"));
|
|
|
|
assert_se(sd_bus_path_decode(a, "/waldo", &b) == 0 && b == NULL);
|
|
|
|
assert_se(sd_bus_path_decode(a, "/foo/bar", &b) > 0 && streq(b, "waldo"));
|
|
|
|
|
|
|
|
assert_se(sd_bus_path_encode("xxxx", "waldo", &c) < 0);
|
|
|
|
assert_se(sd_bus_path_encode("/foo/", "waldo", &c) < 0);
|
|
|
|
|
|
|
|
assert_se(sd_bus_path_encode("/foo/bar", "", &c) >= 0 && streq(c, "/foo/bar/_"));
|
|
|
|
assert_se(sd_bus_path_decode(c, "/foo/bar", &d) > 0 && streq(d, ""));
|
|
|
|
|
|
|
|
assert_se(sd_bus_path_encode("/foo/bar", "foo.bar", &e) >= 0 && streq(e, "/foo/bar/foo_2ebar"));
|
|
|
|
assert_se(sd_bus_path_decode(e, "/foo/bar", &f) > 0 && streq(f, "foo.bar"));
|
|
|
|
}
|
2013-03-19 20:03:16 +01:00
|
|
|
|
2015-09-25 19:05:23 +02:00
|
|
|
static void test_bus_path_encode_many(void) {
|
|
|
|
_cleanup_free_ char *a = NULL, *b = NULL, *c = NULL, *d = NULL, *e = NULL, *f = NULL;
|
|
|
|
|
|
|
|
assert_se(sd_bus_path_decode_many("/foo/bar", "/prefix/%", NULL) == 0);
|
|
|
|
assert_se(sd_bus_path_decode_many("/prefix/bar", "/prefix/%bar", NULL) == 1);
|
|
|
|
assert_se(sd_bus_path_decode_many("/foo/bar", "/prefix/%/suffix", NULL) == 0);
|
|
|
|
assert_se(sd_bus_path_decode_many("/prefix/foobar/suffix", "/prefix/%/suffix", &a) == 1 && streq_ptr(a, "foobar"));
|
|
|
|
assert_se(sd_bus_path_decode_many("/prefix/one_foo_two/mid/three_bar_four/suffix", "/prefix/one_%_two/mid/three_%_four/suffix", &b, &c) == 1 && streq_ptr(b, "foo") && streq_ptr(c, "bar"));
|
|
|
|
assert_se(sd_bus_path_decode_many("/prefix/one_foo_two/mid/three_bar_four/suffix", "/prefix/one_%_two/mid/three_%_four/suffix", NULL, &d) == 1 && streq_ptr(d, "bar"));
|
|
|
|
|
|
|
|
assert_se(sd_bus_path_decode_many("/foo/bar", "/foo/bar/%", NULL) == 0);
|
|
|
|
assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/foo/bar%", NULL) == 0);
|
|
|
|
assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/foo/%/bar", NULL) == 0);
|
|
|
|
assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/foo/%bar", NULL) == 0);
|
|
|
|
assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/foo/bar/suffix") == 1);
|
|
|
|
assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/foo/%%/suffix", NULL, NULL) == 0); /* multiple '%' are treated verbatim */
|
|
|
|
assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/foo/%/suffi", NULL) == 0);
|
|
|
|
assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/foo/%/suffix", &e) == 1 && streq_ptr(e, "bar"));
|
|
|
|
assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/foo/%/%", NULL, NULL) == 1);
|
|
|
|
assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/%/%/%", NULL, NULL, NULL) == 1);
|
|
|
|
assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "%/%/%", NULL, NULL, NULL) == 0);
|
|
|
|
assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/%/%", NULL, NULL) == 0);
|
|
|
|
assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/%/%/", NULL, NULL) == 0);
|
|
|
|
assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/%/", NULL) == 0);
|
|
|
|
assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/%", NULL) == 0);
|
|
|
|
assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "%", NULL) == 0);
|
|
|
|
|
|
|
|
assert_se(sd_bus_path_encode_many(&f, "/prefix/one_%_two/mid/three_%_four/suffix", "foo", "bar") >= 0 && streq_ptr(f, "/prefix/one_foo_two/mid/three_bar_four/suffix"));
|
|
|
|
}
|
|
|
|
|
2013-11-21 01:03:26 +01:00
|
|
|
static void test_bus_label_escape_one(const char *a, const char *b) {
|
|
|
|
_cleanup_free_ char *t = NULL, *x = NULL, *y = NULL;
|
|
|
|
|
2014-03-11 19:03:50 +01:00
|
|
|
assert_se(t = bus_label_escape(a));
|
2013-11-21 01:03:26 +01:00
|
|
|
assert_se(streq(t, b));
|
|
|
|
|
2014-03-11 19:03:50 +01:00
|
|
|
assert_se(x = bus_label_unescape(t));
|
2013-11-21 01:03:26 +01:00
|
|
|
assert_se(streq(a, x));
|
|
|
|
|
2014-03-11 19:03:50 +01:00
|
|
|
assert_se(y = bus_label_unescape(b));
|
2013-11-21 01:03:26 +01:00
|
|
|
assert_se(streq(a, y));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void test_bus_label_escape(void) {
|
|
|
|
test_bus_label_escape_one("foo123bar", "foo123bar");
|
|
|
|
test_bus_label_escape_one("foo.bar", "foo_2ebar");
|
|
|
|
test_bus_label_escape_one("foo_2ebar", "foo_5f2ebar");
|
|
|
|
test_bus_label_escape_one("", "_");
|
|
|
|
test_bus_label_escape_one("_", "_5f");
|
|
|
|
test_bus_label_escape_one("1", "_31");
|
|
|
|
test_bus_label_escape_one(":1", "_3a1");
|
|
|
|
}
|
|
|
|
|
2013-03-19 20:03:16 +01:00
|
|
|
int main(int argc, char *argv[]) {
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *copy = NULL;
|
2013-03-20 03:15:03 +01:00
|
|
|
int r, boolean;
|
2014-01-12 12:15:29 +01:00
|
|
|
const char *x, *x2, *y, *z, *a, *b, *c, *d, *a_signature;
|
2013-03-19 20:03:16 +01:00
|
|
|
uint8_t u, v;
|
|
|
|
void *buffer = NULL;
|
|
|
|
size_t sz;
|
|
|
|
char *h;
|
2013-05-09 20:00:51 +02:00
|
|
|
const int32_t integer_array[] = { -1, -2, 0, 1, 2 }, *return_array;
|
2013-05-10 01:12:15 +02:00
|
|
|
char *s;
|
2013-10-29 19:30:55 +01:00
|
|
|
_cleanup_free_ char *first = NULL, *second = NULL, *third = NULL;
|
|
|
|
_cleanup_fclose_ FILE *ms = NULL;
|
|
|
|
size_t first_size = 0, second_size = 0, third_size = 0;
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
|
2015-01-23 01:13:09 +01:00
|
|
|
double dbl;
|
|
|
|
uint64_t u64;
|
2013-03-19 20:03:16 +01:00
|
|
|
|
2017-09-19 14:17:57 +02:00
|
|
|
r = sd_bus_default_user(&bus);
|
2014-06-06 18:30:01 +02:00
|
|
|
if (r < 0)
|
|
|
|
return EXIT_TEST_SKIP;
|
|
|
|
|
|
|
|
r = sd_bus_message_new_method_call(bus, &m, "foobar.waldo", "/", "foobar.waldo", "Piep");
|
2013-03-19 20:03:16 +01:00
|
|
|
assert_se(r >= 0);
|
|
|
|
|
2014-03-07 05:24:20 +01:00
|
|
|
r = sd_bus_message_append(m, "");
|
|
|
|
assert_se(r >= 0);
|
|
|
|
|
2013-03-19 20:03:16 +01:00
|
|
|
r = sd_bus_message_append(m, "s", "a string");
|
|
|
|
assert_se(r >= 0);
|
|
|
|
|
2013-03-22 00:24:21 +01:00
|
|
|
r = sd_bus_message_append(m, "s", NULL);
|
2013-11-07 16:44:33 +01:00
|
|
|
assert_se(r >= 0);
|
2013-03-22 00:24:21 +01:00
|
|
|
|
2014-01-12 12:15:29 +01:00
|
|
|
r = sd_bus_message_append(m, "asg", 2, "string #1", "string #2", "sba(tt)ss");
|
2013-03-19 20:03:16 +01:00
|
|
|
assert_se(r >= 0);
|
|
|
|
|
|
|
|
r = sd_bus_message_append(m, "sass", "foobar", 5, "foo", "bar", "waldo", "piep", "pap", "after");
|
|
|
|
assert_se(r >= 0);
|
|
|
|
|
|
|
|
r = sd_bus_message_append(m, "a{yv}", 2, 3, "s", "foo", 5, "s", "waldo");
|
|
|
|
assert_se(r >= 0);
|
|
|
|
|
2015-07-16 14:57:59 +02:00
|
|
|
r = sd_bus_message_append(m, "y(ty)y(yt)y", 8, 777ULL, 7, 9, 77, 7777ULL, 10);
|
sd-bus: fix gvariant structure encoding
In gvariant, all fixed-size objects need to be sized a multiple of their
alignment. If a structure has only fixed-size members, it is required to
be fixed size itself. If you imagine a structure like (ty), you have an
8-byte member followed by an 1-byte member. Hence, the overall inner-size
is 9. The alignment of the object is 8, though. Therefore, the specs
mandates final padding after fixed-size structures, to make sure it's
sized a multiple of its alignment (=> 16).
On the gvariant decoder side, we already account for this in
bus_gvariant_get_size(), as we apply overall padding to the size of the
structure. Therefore, our decoder correctly skips such final padding when
parsing fixed-size structure.
On the gvariant encoder side, however, we don't account for this final
padding. This patch fixes the structure and dict-entry encoders to
properly place such padding at the end of non-uniform fixed-size
structures.
The problem can be easily seen by running:
$ busctl --user monitor
and
$ busctl call --user org.freedesktop.systemd1 / org.foobar foobar "(ty)" 777 8
The monitor will fail to parse the message and print an error. With this
patch applied, everything works fine again.
This patch also adds a bunch of test-cases to force non-uniform
structures with non-pre-aligned positions.
Thanks to Jan Alexander Steffens <jan.steffens@gmail.com> for spotting
this and narrowing it down to non-uniform gvariant structures. Fixes #597.
2015-07-16 11:00:55 +02:00
|
|
|
assert_se(r >= 0);
|
|
|
|
|
2015-07-28 16:46:51 +02:00
|
|
|
r = sd_bus_message_append(m, "()");
|
|
|
|
assert_se(r >= 0);
|
|
|
|
|
2013-03-19 20:03:16 +01:00
|
|
|
r = sd_bus_message_append(m, "ba(ss)", 255, 3, "aaa", "1", "bbb", "2", "ccc", "3");
|
|
|
|
assert_se(r >= 0);
|
|
|
|
|
|
|
|
r = sd_bus_message_open_container(m, 'a', "s");
|
|
|
|
assert_se(r >= 0);
|
|
|
|
|
|
|
|
r = sd_bus_message_append_basic(m, 's', "foobar");
|
|
|
|
assert_se(r >= 0);
|
|
|
|
|
|
|
|
r = sd_bus_message_append_basic(m, 's', "waldo");
|
|
|
|
assert_se(r >= 0);
|
|
|
|
|
|
|
|
r = sd_bus_message_close_container(m);
|
|
|
|
assert_se(r >= 0);
|
|
|
|
|
2013-05-10 01:12:15 +02:00
|
|
|
r = sd_bus_message_append_string_space(m, 5, &s);
|
|
|
|
assert_se(r >= 0);
|
|
|
|
strcpy(s, "hallo");
|
|
|
|
|
2013-05-09 20:00:51 +02:00
|
|
|
r = sd_bus_message_append_array(m, 'i', integer_array, sizeof(integer_array));
|
|
|
|
assert_se(r >= 0);
|
|
|
|
|
2013-11-07 18:40:06 +01:00
|
|
|
r = sd_bus_message_append_array(m, 'u', NULL, 0);
|
|
|
|
assert_se(r >= 0);
|
|
|
|
|
2015-01-23 01:13:09 +01:00
|
|
|
r = sd_bus_message_append(m, "a(stdo)", 1, "foo", 815ULL, 47.0, "/");
|
|
|
|
assert_se(r >= 0);
|
|
|
|
|
2013-12-12 20:00:19 +01:00
|
|
|
r = bus_message_seal(m, 4711, 0);
|
2013-03-19 20:03:16 +01:00
|
|
|
assert_se(r >= 0);
|
|
|
|
|
2014-11-14 17:20:04 +01:00
|
|
|
bus_message_dump(m, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
|
2013-10-29 19:30:55 +01:00
|
|
|
|
|
|
|
ms = open_memstream(&first, &first_size);
|
2014-11-14 17:20:04 +01:00
|
|
|
bus_message_dump(m, ms, 0);
|
2013-10-29 19:30:55 +01:00
|
|
|
fflush(ms);
|
|
|
|
assert_se(!ferror(ms));
|
2013-03-19 20:03:16 +01:00
|
|
|
|
|
|
|
r = bus_message_get_blob(m, &buffer, &sz);
|
|
|
|
assert_se(r >= 0);
|
|
|
|
|
|
|
|
h = hexmem(buffer, sz);
|
|
|
|
assert_se(h);
|
|
|
|
|
2014-04-25 13:45:15 +02:00
|
|
|
log_info("message size = %zu, contents =\n%s", sz, h);
|
2013-03-19 20:03:16 +01:00
|
|
|
free(h);
|
|
|
|
|
2017-10-03 10:41:51 +02:00
|
|
|
#if HAVE_GLIB
|
2013-03-19 20:03:16 +01:00
|
|
|
{
|
|
|
|
GDBusMessage *g;
|
|
|
|
char *p;
|
|
|
|
|
2013-04-04 09:02:28 +02:00
|
|
|
#if !defined(GLIB_VERSION_2_36)
|
2013-03-19 20:03:16 +01:00
|
|
|
g_type_init();
|
2013-04-04 09:02:28 +02:00
|
|
|
#endif
|
2013-03-19 20:03:16 +01:00
|
|
|
|
|
|
|
g = g_dbus_message_new_from_blob(buffer, sz, 0, NULL);
|
|
|
|
p = g_dbus_message_print(g, 0);
|
|
|
|
log_info("%s", p);
|
|
|
|
g_free(p);
|
|
|
|
g_object_unref(g);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2017-10-03 10:41:51 +02:00
|
|
|
#if HAVE_DBUS
|
2013-03-19 20:03:16 +01:00
|
|
|
{
|
|
|
|
DBusMessage *w;
|
|
|
|
DBusError error;
|
|
|
|
|
|
|
|
dbus_error_init(&error);
|
|
|
|
|
|
|
|
w = dbus_message_demarshal(buffer, sz, &error);
|
2013-12-05 02:46:54 +01:00
|
|
|
if (!w)
|
2013-03-19 20:03:16 +01:00
|
|
|
log_error("%s", error.message);
|
2013-12-05 02:46:54 +01:00
|
|
|
else
|
2013-03-19 20:03:16 +01:00
|
|
|
dbus_message_unref(w);
|
2015-12-29 13:41:36 +01:00
|
|
|
|
|
|
|
dbus_error_free(&error);
|
2013-03-19 20:03:16 +01:00
|
|
|
}
|
2013-11-06 02:03:05 +01:00
|
|
|
#endif
|
2013-03-19 20:03:16 +01:00
|
|
|
|
2013-03-20 05:29:20 +01:00
|
|
|
m = sd_bus_message_unref(m);
|
|
|
|
|
2015-06-10 15:52:14 +02:00
|
|
|
r = bus_message_from_malloc(bus, buffer, sz, NULL, 0, NULL, &m);
|
2013-03-20 05:29:20 +01:00
|
|
|
assert_se(r >= 0);
|
|
|
|
|
2014-11-14 17:20:04 +01:00
|
|
|
bus_message_dump(m, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
|
2013-10-29 19:30:55 +01:00
|
|
|
|
|
|
|
fclose(ms);
|
|
|
|
ms = open_memstream(&second, &second_size);
|
2014-11-14 17:20:04 +01:00
|
|
|
bus_message_dump(m, ms, 0);
|
2013-10-29 19:30:55 +01:00
|
|
|
fflush(ms);
|
|
|
|
assert_se(!ferror(ms));
|
|
|
|
assert_se(first_size == second_size);
|
|
|
|
assert_se(memcmp(first, second, first_size) == 0);
|
2013-03-19 20:03:16 +01:00
|
|
|
|
2013-03-20 03:15:03 +01:00
|
|
|
assert_se(sd_bus_message_rewind(m, true) >= 0);
|
|
|
|
|
2014-01-12 12:15:29 +01:00
|
|
|
r = sd_bus_message_read(m, "ssasg", &x, &x2, 2, &y, &z, &a_signature);
|
2013-03-20 03:15:03 +01:00
|
|
|
assert_se(r > 0);
|
|
|
|
assert_se(streq(x, "a string"));
|
2013-11-07 16:44:33 +01:00
|
|
|
assert_se(streq(x2, ""));
|
2013-03-20 03:15:03 +01:00
|
|
|
assert_se(streq(y, "string #1"));
|
|
|
|
assert_se(streq(z, "string #2"));
|
2014-01-12 12:15:29 +01:00
|
|
|
assert_se(streq(a_signature, "sba(tt)ss"));
|
2013-03-20 03:15:03 +01:00
|
|
|
|
|
|
|
r = sd_bus_message_read(m, "sass", &x, 5, &y, &z, &a, &b, &c, &d);
|
|
|
|
assert_se(r > 0);
|
|
|
|
assert_se(streq(x, "foobar"));
|
|
|
|
assert_se(streq(y, "foo"));
|
|
|
|
assert_se(streq(z, "bar"));
|
|
|
|
assert_se(streq(a, "waldo"));
|
|
|
|
assert_se(streq(b, "piep"));
|
|
|
|
assert_se(streq(c, "pap"));
|
|
|
|
assert_se(streq(d, "after"));
|
|
|
|
|
|
|
|
r = sd_bus_message_read(m, "a{yv}", 2, &u, "s", &x, &v, "s", &y);
|
|
|
|
assert_se(r > 0);
|
|
|
|
assert_se(u == 3);
|
|
|
|
assert_se(streq(x, "foo"));
|
|
|
|
assert_se(v == 5);
|
|
|
|
assert_se(streq(y, "waldo"));
|
|
|
|
|
sd-bus: fix gvariant structure encoding
In gvariant, all fixed-size objects need to be sized a multiple of their
alignment. If a structure has only fixed-size members, it is required to
be fixed size itself. If you imagine a structure like (ty), you have an
8-byte member followed by an 1-byte member. Hence, the overall inner-size
is 9. The alignment of the object is 8, though. Therefore, the specs
mandates final padding after fixed-size structures, to make sure it's
sized a multiple of its alignment (=> 16).
On the gvariant decoder side, we already account for this in
bus_gvariant_get_size(), as we apply overall padding to the size of the
structure. Therefore, our decoder correctly skips such final padding when
parsing fixed-size structure.
On the gvariant encoder side, however, we don't account for this final
padding. This patch fixes the structure and dict-entry encoders to
properly place such padding at the end of non-uniform fixed-size
structures.
The problem can be easily seen by running:
$ busctl --user monitor
and
$ busctl call --user org.freedesktop.systemd1 / org.foobar foobar "(ty)" 777 8
The monitor will fail to parse the message and print an error. With this
patch applied, everything works fine again.
This patch also adds a bunch of test-cases to force non-uniform
structures with non-pre-aligned positions.
Thanks to Jan Alexander Steffens <jan.steffens@gmail.com> for spotting
this and narrowing it down to non-uniform gvariant structures. Fixes #597.
2015-07-16 11:00:55 +02:00
|
|
|
r = sd_bus_message_read(m, "y(ty)", &v, &u64, &u);
|
|
|
|
assert_se(r > 0);
|
|
|
|
assert_se(v == 8);
|
|
|
|
assert_se(u64 == 777);
|
|
|
|
assert_se(u == 7);
|
|
|
|
|
|
|
|
r = sd_bus_message_read(m, "y(yt)", &v, &u, &u64);
|
|
|
|
assert_se(r > 0);
|
|
|
|
assert_se(v == 9);
|
|
|
|
assert_se(u == 77);
|
|
|
|
assert_se(u64 == 7777);
|
|
|
|
|
|
|
|
r = sd_bus_message_read(m, "y", &v);
|
|
|
|
assert_se(r > 0);
|
|
|
|
assert_se(v == 10);
|
|
|
|
|
2015-07-28 16:46:51 +02:00
|
|
|
r = sd_bus_message_read(m, "()");
|
|
|
|
assert_se(r > 0);
|
|
|
|
|
2013-03-20 03:15:03 +01:00
|
|
|
r = sd_bus_message_read(m, "ba(ss)", &boolean, 3, &x, &y, &a, &b, &c, &d);
|
|
|
|
assert_se(r > 0);
|
|
|
|
assert_se(boolean);
|
|
|
|
assert_se(streq(x, "aaa"));
|
|
|
|
assert_se(streq(y, "1"));
|
|
|
|
assert_se(streq(a, "bbb"));
|
|
|
|
assert_se(streq(b, "2"));
|
|
|
|
assert_se(streq(c, "ccc"));
|
|
|
|
assert_se(streq(d, "3"));
|
|
|
|
|
2013-10-29 19:30:55 +01:00
|
|
|
assert_se(sd_bus_message_verify_type(m, 'a', "s") > 0);
|
|
|
|
|
2013-03-20 03:15:03 +01:00
|
|
|
r = sd_bus_message_read(m, "as", 2, &x, &y);
|
|
|
|
assert_se(r > 0);
|
|
|
|
assert_se(streq(x, "foobar"));
|
|
|
|
assert_se(streq(y, "waldo"));
|
|
|
|
|
2013-05-10 01:12:15 +02:00
|
|
|
r = sd_bus_message_read_basic(m, 's', &s);
|
|
|
|
assert_se(r > 0);
|
|
|
|
assert_se(streq(s, "hallo"));
|
|
|
|
|
2013-05-09 20:00:51 +02:00
|
|
|
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);
|
|
|
|
|
2013-11-07 18:40:06 +01:00
|
|
|
r = sd_bus_message_read_array(m, 'u', (const void**) &return_array, &sz);
|
|
|
|
assert_se(r > 0);
|
|
|
|
assert_se(sz == 0);
|
|
|
|
|
2015-01-23 01:13:09 +01:00
|
|
|
r = sd_bus_message_read(m, "a(stdo)", 1, &x, &u64, &dbl, &y);
|
|
|
|
assert_se(r > 0);
|
|
|
|
assert_se(streq(x, "foo"));
|
|
|
|
assert_se(u64 == 815ULL);
|
|
|
|
assert_se(fabs(dbl - 47.0) < 0.1);
|
|
|
|
assert_se(streq(y, "/"));
|
|
|
|
|
2013-03-20 03:15:03 +01:00
|
|
|
r = sd_bus_message_peek_type(m, NULL, NULL);
|
|
|
|
assert_se(r == 0);
|
2013-03-19 20:03:16 +01:00
|
|
|
|
2014-06-06 18:30:01 +02:00
|
|
|
r = sd_bus_message_new_method_call(bus, ©, "foobar.waldo", "/", "foobar.waldo", "Piep");
|
2013-10-29 19:30:55 +01:00
|
|
|
assert_se(r >= 0);
|
|
|
|
|
|
|
|
r = sd_bus_message_rewind(m, true);
|
|
|
|
assert_se(r >= 0);
|
|
|
|
|
|
|
|
r = sd_bus_message_copy(copy, m, true);
|
|
|
|
assert_se(r >= 0);
|
|
|
|
|
2013-12-12 20:00:19 +01:00
|
|
|
r = bus_message_seal(copy, 4712, 0);
|
2013-10-29 19:30:55 +01:00
|
|
|
assert_se(r >= 0);
|
|
|
|
|
|
|
|
fclose(ms);
|
|
|
|
ms = open_memstream(&third, &third_size);
|
2014-11-14 17:20:04 +01:00
|
|
|
bus_message_dump(copy, ms, 0);
|
2013-10-29 19:30:55 +01:00
|
|
|
fflush(ms);
|
|
|
|
assert_se(!ferror(ms));
|
|
|
|
|
2013-12-31 18:51:46 +01:00
|
|
|
printf("<%.*s>\n", (int) first_size, first);
|
|
|
|
printf("<%.*s>\n", (int) third_size, third);
|
2013-10-29 19:30:55 +01:00
|
|
|
|
|
|
|
assert_se(first_size == third_size);
|
|
|
|
assert_se(memcmp(first, third, third_size) == 0);
|
|
|
|
|
2013-11-05 02:25:24 +01:00
|
|
|
r = sd_bus_message_rewind(m, true);
|
|
|
|
assert_se(r >= 0);
|
|
|
|
|
|
|
|
assert_se(sd_bus_message_verify_type(m, 's', NULL) > 0);
|
|
|
|
|
2014-01-12 12:15:29 +01:00
|
|
|
r = sd_bus_message_skip(m, "ssasg");
|
2013-11-05 02:25:24 +01:00
|
|
|
assert_se(r > 0);
|
|
|
|
|
|
|
|
assert_se(sd_bus_message_verify_type(m, 's', NULL) > 0);
|
|
|
|
|
|
|
|
r = sd_bus_message_skip(m, "sass");
|
|
|
|
assert_se(r >= 0);
|
|
|
|
|
|
|
|
assert_se(sd_bus_message_verify_type(m, 'a', "{yv}") > 0);
|
|
|
|
|
2015-07-28 16:46:51 +02:00
|
|
|
r = sd_bus_message_skip(m, "a{yv}y(ty)y(yt)y()");
|
2013-11-05 02:25:24 +01:00
|
|
|
assert_se(r >= 0);
|
|
|
|
|
|
|
|
assert_se(sd_bus_message_verify_type(m, 'b', NULL) > 0);
|
|
|
|
|
2013-11-05 02:54:08 +01:00
|
|
|
r = sd_bus_message_read(m, "b", &boolean);
|
2013-11-05 02:25:24 +01:00
|
|
|
assert_se(r > 0);
|
|
|
|
assert_se(boolean);
|
2013-11-05 02:54:08 +01:00
|
|
|
|
|
|
|
r = sd_bus_message_enter_container(m, 0, NULL);
|
|
|
|
assert_se(r > 0);
|
|
|
|
|
|
|
|
r = sd_bus_message_read(m, "(ss)", &x, &y);
|
|
|
|
assert_se(r > 0);
|
|
|
|
|
|
|
|
r = sd_bus_message_read(m, "(ss)", &a, &b);
|
|
|
|
assert_se(r > 0);
|
|
|
|
|
|
|
|
r = sd_bus_message_read(m, "(ss)", &c, &d);
|
|
|
|
assert_se(r > 0);
|
|
|
|
|
|
|
|
r = sd_bus_message_read(m, "(ss)", &x, &y);
|
|
|
|
assert_se(r == 0);
|
|
|
|
|
|
|
|
r = sd_bus_message_exit_container(m);
|
|
|
|
assert_se(r >= 0);
|
|
|
|
|
2013-11-05 02:25:24 +01:00
|
|
|
assert_se(streq(x, "aaa"));
|
|
|
|
assert_se(streq(y, "1"));
|
|
|
|
assert_se(streq(a, "bbb"));
|
|
|
|
assert_se(streq(b, "2"));
|
|
|
|
assert_se(streq(c, "ccc"));
|
|
|
|
assert_se(streq(d, "3"));
|
|
|
|
|
2013-11-21 01:03:26 +01:00
|
|
|
test_bus_label_escape();
|
2014-03-11 19:03:50 +01:00
|
|
|
test_bus_path_encode();
|
bus: implement bus_path_{en,de}code_unique()
Whenever we provide a bus API that allows clients to create and manage
server-side objects, we need to provide a unique name for these objects.
There are two ways to provide them:
1) Let the server choose a name and return it as method reply.
2) Let the client pass its name of choice in the method arguments.
The first method is the easiest one to implement. However, it suffers from
a race condition: If a client creates an object asynchronously, it cannot
destroy that object until it received the method reply. It cannot know the
name of the new object, thus, it cannot destroy it. Furthermore, this
method enforces a round-trip. If the client _depends_ on the method call
to succeed (eg., it would close() the connection if it failed), the client
usually has no reason to wait for the method reply. Instead, the client
can immediately schedule further method calls on the newly created object
(in case the API guarantees in-order method-call handling).
The second method fixes both problems: The client passes an object name
with the method-call. The server uses it to create the object. Therefore,
the client can schedule object destruction even if the object-creation
hasn't finished, yet (again, requiring in-order method-call handling).
Furthermore, the client can schedule further method calls on the newly
created object, before the constructor returned.
There're two problems to solve, though:
1) Object names are usually defined via dbus object paths, which are
usually globally namespaced. Therefore, multiple clients must be able
to choose unique object names without interference.
2) If multiple libraries share the same bus connection, they must be
able to choose unique object names without interference.
The first problem is solved easily by prefixing a name with the
unique-bus-name of a connection. The server side must enforce this and
reject any other name.
The second problem is solved by providing unique suffixes from within
sd-bus. As long as sd-bus always returns a fresh new ID, if requested,
multiple libraries will never interfere. This implementation re-uses
bus->cookie as ID generator, which already provides unique IDs for each
bus connection.
This patch introduces two new helpers:
bus_path_encode_unique(sd_bus *bus,
const char *prefix,
const char *sender_id,
const char *external_id,
char **ret_path);
This creates a new object-path via the template
'/prefix/sender_id/external_id'. That is, it appends two new labels to
the given prefix. If 'sender_id' is NULL, it will use
bus->unique_name, if 'external_id' is NULL, it will allocate a fresh,
unique cookie from bus->cookie.
bus_path_decode_unique(const char *path,
const char *prefix,
char **ret_sender,
char **ret_external);
This reverses what bus_path_encode_unique() did. It parses 'path' from
the template '/prefix/sender/external' and returns both suffix-labels
in 'ret_sender' and 'ret_external'. In case the template does not
match, 0 is returned and both output arguments are set to NULL.
Otherwise, 1 is returned and the output arguments contain the decoded
labels.
Note: Client-side allocated IDs are inspired by the Wayland protocol
(which itself was inspired by X11). Wayland uses those IDs heavily
to avoid round-trips. Clients can create server-side objects and
send method calls without any round-trip and waiting for any object
IDs to be returned. But unlike Wayland, DBus uses gobally namespaced
object names. Therefore, we have to add the extra step by adding the
unique-name of the bus connection.
2015-04-10 17:44:30 +02:00
|
|
|
test_bus_path_encode_unique();
|
2015-09-25 19:05:23 +02:00
|
|
|
test_bus_path_encode_many();
|
2013-11-21 01:03:26 +01:00
|
|
|
|
2013-03-19 20:03:16 +01:00
|
|
|
return 0;
|
|
|
|
}
|