Browse Source
This adds a lightweight scheme how to define interfaces in static fixed arrays which then can be easily registered on a bus connection. This makes it much easier to write bus services. This automatically handles implementation of the Properties, ObjectManager, and Introspection bus interfaces.keep-around/ba91431154ad7bac82ddf0a540ec1b40db62d782

18 changed files with 3322 additions and 582 deletions
@ -0,0 +1,200 @@ |
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ |
|||
|
|||
/***
|
|||
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/>.
|
|||
***/ |
|||
|
|||
#include "util.h" |
|||
#include "sd-bus-protocol.h" |
|||
#include "bus-introspect.h" |
|||
#include "bus-signature.h" |
|||
#include "bus-internal.h" |
|||
|
|||
int introspect_begin(struct introspect *i) { |
|||
assert(i); |
|||
|
|||
zero(*i); |
|||
|
|||
i->f = open_memstream(&i->introspection, &i->size); |
|||
if (!i->f) |
|||
return -ENOMEM; |
|||
|
|||
fputs(SD_BUS_INTROSPECT_DOCTYPE |
|||
"<node>\n", i->f); |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
int introspect_write_default_interfaces(struct introspect *i, bool object_manager) { |
|||
assert(i); |
|||
|
|||
fputs(SD_BUS_INTROSPECT_INTERFACE_PEER |
|||
SD_BUS_INTROSPECT_INTERFACE_INTROSPECTABLE |
|||
SD_BUS_INTROSPECT_INTERFACE_PROPERTIES, i->f); |
|||
|
|||
if (object_manager) |
|||
fputs(SD_BUS_INTROSPECT_INTERFACE_OBJECT_MANAGER, i->f); |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
int introspect_write_child_nodes(struct introspect *i, Set *s, const char *prefix) { |
|||
char *node; |
|||
|
|||
assert(i); |
|||
assert(prefix); |
|||
|
|||
while ((node = set_steal_first(s))) { |
|||
const char *e; |
|||
|
|||
e = object_path_startswith(node, prefix); |
|||
if (e) |
|||
fprintf(i->f, " <node name=\"%s\"/>\n", e); |
|||
|
|||
free(node); |
|||
} |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
static void introspect_write_flags(struct introspect *i, int type, int flags) { |
|||
if (flags & SD_BUS_VTABLE_DEPRECATED) |
|||
fputs(" <annotation name=\"org.freedesktop.DBus.Deprecated\" value=\"true\"/>\n", i->f); |
|||
|
|||
if (type == _SD_BUS_VTABLE_METHOD && flags & SD_BUS_VTABLE_METHOD_NO_REPLY) |
|||
fputs(" <annotation name=\"org.freedesktop.DBus.Method.NoReply\" value=\"true\"/>\n", i->f); |
|||
|
|||
if (type == _SD_BUS_VTABLE_PROPERTY || type == _SD_BUS_VTABLE_WRITABLE_PROPERTY) { |
|||
if (!(flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE)) |
|||
fputs(" <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"false\"/>\n", i->f); |
|||
else if (flags & SD_BUS_VTABLE_PROPERTY_INVALIDATE_ONLY) |
|||
fputs(" <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"invalidates\"/>\n", i->f); |
|||
} |
|||
} |
|||
|
|||
static int introspect_write_arguments(struct introspect *i, const char *signature, const char *direction) { |
|||
int r; |
|||
|
|||
for (;;) { |
|||
size_t l; |
|||
|
|||
if (!*signature) |
|||
return 0; |
|||
|
|||
r = signature_element_length(signature, &l); |
|||
if (r < 0) |
|||
return r; |
|||
|
|||
fprintf(i->f, " <arg type=\"%.*s\"", (int) l, signature); |
|||
|
|||
if (direction) |
|||
fprintf(i->f, " direction=\"%s\">\n", direction); |
|||
else |
|||
fputs(">\n", i->f); |
|||
|
|||
signature += l; |
|||
} |
|||
} |
|||
|
|||
int introspect_write_interface(struct introspect *i, const char *interface, const sd_bus_vtable *v) { |
|||
assert(i); |
|||
assert(interface); |
|||
assert(v); |
|||
|
|||
fprintf(i->f, " <interface name=\"%s\">\n", interface); |
|||
|
|||
for (; v->type != _SD_BUS_VTABLE_END; v++) { |
|||
|
|||
switch (v->type) { |
|||
|
|||
case _SD_BUS_VTABLE_START: |
|||
if (v->flags & SD_BUS_VTABLE_DEPRECATED) |
|||
fputs(" <annotation name=\"org.freedesktop.DBus.Deprecated\" value=\"true\"/>\n", i->f); |
|||
break; |
|||
|
|||
case _SD_BUS_VTABLE_METHOD: |
|||
fprintf(i->f, " <method name=\"%s\">\n", v->method.member); |
|||
introspect_write_arguments(i, v->method.signature, "in"); |
|||
introspect_write_arguments(i, v->method.result, "out"); |
|||
introspect_write_flags(i, v->type, v->flags); |
|||
fputs(" </method>\n", i->f); |
|||
break; |
|||
|
|||
case _SD_BUS_VTABLE_PROPERTY: |
|||
case _SD_BUS_VTABLE_WRITABLE_PROPERTY: |
|||
fprintf(i->f, " <property name=\"%s\" type=\"%s\" access=\"%s\">\n", |
|||
v->property.member, |
|||
v->property.signature, |
|||
v->type == _SD_BUS_VTABLE_WRITABLE_PROPERTY ? "readwrite" : "read"); |
|||
introspect_write_flags(i, v->type, v->flags); |
|||
fputs(" </property>\n", i->f); |
|||
break; |
|||
|
|||
case _SD_BUS_VTABLE_SIGNAL: |
|||
fprintf(i->f, " <signal name=\"%s\">\n", v->signal.member); |
|||
introspect_write_arguments(i, v->signal.signature, NULL); |
|||
introspect_write_flags(i, v->type, v->flags); |
|||
fputs(" </signal>\n", i->f); |
|||
break; |
|||
} |
|||
|
|||
} |
|||
|
|||
fputs(" </interface>\n", i->f); |
|||
return 0; |
|||
} |
|||
|
|||
int introspect_finish(struct introspect *i, sd_bus *bus, sd_bus_message *m, sd_bus_message **reply) { |
|||
sd_bus_message *q; |
|||
int r; |
|||
|
|||
assert(i); |
|||
assert(m); |
|||
assert(reply); |
|||
|
|||
fputs("</node>\n", i->f); |
|||
fflush(i->f); |
|||
|
|||
if (ferror(i->f)) |
|||
return -ENOMEM; |
|||
|
|||
r = sd_bus_message_new_method_return(bus, m, &q); |
|||
if (r < 0) |
|||
return r; |
|||
|
|||
r = sd_bus_message_append(q, "s", i->introspection); |
|||
if (r < 0) { |
|||
sd_bus_message_unref(q); |
|||
return r; |
|||
} |
|||
|
|||
*reply = q; |
|||
return 0; |
|||
} |
|||
|
|||
void introspect_free(struct introspect *i) { |
|||
assert(i); |
|||
|
|||
if (i->f) |
|||
fclose(i->f); |
|||
|
|||
if (i->introspection) |
|||
free(i->introspection); |
|||
|
|||
zero(*i); |
|||
} |
@ -0,0 +1,41 @@ |
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ |
|||
|
|||
#pragma once |
|||
|
|||
/***
|
|||
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/>.
|
|||
***/ |
|||
|
|||
#include <sys/types.h> |
|||
#include <stdio.h> |
|||
|
|||
#include "sd-bus.h" |
|||
#include "set.h" |
|||
|
|||
struct introspect { |
|||
FILE *f; |
|||
char *introspection; |
|||
size_t size; |
|||
}; |
|||
|
|||
int introspect_begin(struct introspect *i); |
|||
int introspect_write_default_interfaces(struct introspect *i, bool object_manager); |
|||
int introspect_write_child_nodes(struct introspect *i, Set *s, const char *prefix); |
|||
int introspect_write_interface(struct introspect *i, const char *interface, const sd_bus_vtable *v); |
|||
int introspect_finish(struct introspect *i, sd_bus *bus, sd_bus_message *m, sd_bus_message **reply); |
|||
void introspect_free(struct introspect *i); |
File diff suppressed because it is too large
@ -0,0 +1,63 @@ |
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ |
|||
|
|||
/***
|
|||
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/>.
|
|||
***/ |
|||
|
|||
#include "util.h" |
|||
#include "log.h" |
|||
#include "bus-introspect.h" |
|||
|
|||
static int prop_get(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, sd_bus_error *error, void *userdata) { |
|||
return -EINVAL; |
|||
} |
|||
|
|||
static int prop_set(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, sd_bus_error *error, void *userdata) { |
|||
return -EINVAL; |
|||
} |
|||
|
|||
static const sd_bus_vtable vtable[] = { |
|||
SD_BUS_VTABLE_START(0), |
|||
SD_BUS_METHOD("Hello", "ssas", "a(uu)", 0, NULL), |
|||
SD_BUS_METHOD("DeprecatedHello", "", "", SD_BUS_VTABLE_DEPRECATED, NULL), |
|||
SD_BUS_METHOD("DeprecatedHelloNoReply", "", "", SD_BUS_VTABLE_DEPRECATED|SD_BUS_VTABLE_METHOD_NO_REPLY, NULL), |
|||
SD_BUS_SIGNAL("Wowza", "sss", 0), |
|||
SD_BUS_SIGNAL("DeprecatedWowza", "ut", SD_BUS_VTABLE_DEPRECATED), |
|||
SD_BUS_WRITABLE_PROPERTY("AProperty", "s", prop_get, prop_set, 0, 0), |
|||
SD_BUS_PROPERTY("AReadOnlyDeprecatedProperty", "(ut)", prop_get, 0, SD_BUS_VTABLE_DEPRECATED), |
|||
SD_BUS_PROPERTY("ChangingProperty", "t", prop_get, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), |
|||
SD_BUS_PROPERTY("Invalidating", "t", prop_get, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE|SD_BUS_VTABLE_PROPERTY_INVALIDATE_ONLY), |
|||
SD_BUS_VTABLE_END |
|||
}; |
|||
|
|||
int main(int argc, char *argv[]) { |
|||
struct introspect intro; |
|||
|
|||
log_set_max_level(LOG_DEBUG); |
|||
|
|||
assert_se(introspect_begin(&intro) >= 0); |
|||
|
|||
assert_se(introspect_write_interface(&intro, "org.foo", vtable) >= 0); |
|||
|
|||
fflush(intro.f); |
|||
fputs(intro.introspection, stdout); |
|||
|
|||
introspect_free(&intro); |
|||
|
|||
return 0; |
|||
} |
@ -0,0 +1,374 @@ |
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ |
|||
|
|||
/***
|
|||
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/>.
|
|||
***/ |
|||
|
|||
#include <assert.h> |
|||
#include <stdlib.h> |
|||
#include <pthread.h> |
|||
#include <unistd.h> |
|||
#include <fcntl.h> |
|||
|
|||
#include "log.h" |
|||
#include "util.h" |
|||
#include "macro.h" |
|||
#include "strv.h" |
|||
|
|||
#include "sd-bus.h" |
|||
#include "bus-internal.h" |
|||
#include "bus-message.h" |
|||
|
|||
/* Test:
|
|||
* |
|||
* sd_bus_add_object_manager() |
|||
* sd_bus_emit_properties_changed() |
|||
* |
|||
* Add in: |
|||
* |
|||
* automatic properties |
|||
* node hierarchy updates during dispatching |
|||
* emit_interfaces_added/emit_interfaces_removed |
|||
* |
|||
*/ |
|||
|
|||
struct context { |
|||
int fds[2]; |
|||
bool quit; |
|||
char *something; |
|||
}; |
|||
|
|||
static int something_handler(sd_bus *bus, sd_bus_message *m, void *userdata) { |
|||
struct context *c = userdata; |
|||
const char *s; |
|||
char *n = NULL; |
|||
int r; |
|||
|
|||
r = sd_bus_message_read(m, "s", &s); |
|||
assert_se(r > 0); |
|||
|
|||
n = strjoin("<<<", s, ">>>", NULL); |
|||
assert_se(n); |
|||
|
|||
free(c->something); |
|||
c->something = n; |
|||
|
|||
log_info("AlterSomething() called, got %s, returning %s", s, n); |
|||
|
|||
r = sd_bus_reply_method_return(bus, m, "s", n); |
|||
assert_se(r >= 0); |
|||
|
|||
return 1; |
|||
} |
|||
|
|||
static int exit_handler(sd_bus *bus, sd_bus_message *m, void *userdata) { |
|||
struct context *c = userdata; |
|||
int r; |
|||
|
|||
c->quit = true; |
|||
|
|||
log_info("Exit called"); |
|||
|
|||
r = sd_bus_reply_method_return(bus, m, ""); |
|||
assert_se(r >= 0); |
|||
|
|||
return 1; |
|||
} |
|||
|
|||
static int get_handler(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, sd_bus_error *error, void *userdata) { |
|||
struct context *c = userdata; |
|||
int r; |
|||
|
|||
log_info("property get for %s called", property); |
|||
|
|||
r = sd_bus_message_append(reply, "s", c->something); |
|||
assert_se(r >= 0); |
|||
|
|||
return 1; |
|||
} |
|||
|
|||
static int set_handler(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *value, sd_bus_error *error, void *userdata) { |
|||
struct context *c = userdata; |
|||
const char *s; |
|||
char *n; |
|||
int r; |
|||
|
|||
log_info("property set for %s called", property); |
|||
|
|||
r = sd_bus_message_read(value, "s", &s); |
|||
assert_se(r >= 0); |
|||
|
|||
n = strdup(s); |
|||
assert_se(n); |
|||
|
|||
free(c->something); |
|||
c->something = n; |
|||
|
|||
return 1; |
|||
} |
|||
|
|||
static int value_handler(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, sd_bus_error *error, void *userdata) { |
|||
_cleanup_free_ char *s = NULL; |
|||
const char *x; |
|||
int r; |
|||
|
|||
assert_se(asprintf(&s, "object %p, path %s", userdata, path) >= 0); |
|||
r = sd_bus_message_append(reply, "s", s); |
|||
assert_se(r >= 0); |
|||
|
|||
assert_se(x = startswith(path, "/value/")); |
|||
|
|||
assert_se(PTR_TO_UINT(userdata) == 30); |
|||
|
|||
|
|||
return 1; |
|||
} |
|||
|
|||
static const sd_bus_vtable vtable[] = { |
|||
SD_BUS_VTABLE_START(0), |
|||
SD_BUS_METHOD("AlterSomething", "s", "s", 0, something_handler), |
|||
SD_BUS_METHOD("Exit", "", "", 0, exit_handler), |
|||
SD_BUS_WRITABLE_PROPERTY("Something", "s", get_handler, set_handler, 0, 0), |
|||
SD_BUS_VTABLE_END |
|||
}; |
|||
|
|||
static const sd_bus_vtable vtable2[] = { |
|||
SD_BUS_VTABLE_START(0), |
|||
SD_BUS_PROPERTY("Value", "s", value_handler, 10, 0), |
|||
SD_BUS_VTABLE_END |
|||
}; |
|||
|
|||
static int enumerator_callback(sd_bus *b, const char *path, char ***nodes, void *userdata) { |
|||
|
|||
if (object_path_startswith("/value", path)) |
|||
assert_se(*nodes = strv_new("/value/a", "/value/b", "/value/c", NULL)); |
|||
|
|||
return 1; |
|||
} |
|||
|
|||
static void *server(void *p) { |
|||
struct context *c = p; |
|||
sd_bus *bus = NULL; |
|||
sd_id128_t id; |
|||
int r; |
|||
|
|||
c->quit = false; |
|||
|
|||
assert_se(sd_id128_randomize(&id) >= 0); |
|||
|
|||
assert_se(sd_bus_new(&bus) >= 0); |
|||
assert_se(sd_bus_set_fd(bus, c->fds[0], c->fds[0]) >= 0); |
|||
assert_se(sd_bus_set_server(bus, 1, id) >= 0); |
|||
|
|||
assert_se(sd_bus_add_object_vtable(bus, "/foo", "org.freedesktop.systemd.test", vtable, c) >= 0); |
|||
assert_se(sd_bus_add_object_vtable(bus, "/foo", "org.freedesktop.systemd.test2", vtable, c) >= 0); |
|||
assert_se(sd_bus_add_fallback_vtable(bus, "/value", "org.freedesktop.systemd.ValueTest", vtable2, NULL, UINT_TO_PTR(20)) >= 0); |
|||
assert_se(sd_bus_add_node_enumerator(bus, "/value", enumerator_callback, NULL) >= 0); |
|||
|
|||
assert_se(sd_bus_start(bus) >= 0); |
|||
|
|||
log_error("Entering event loop on server"); |
|||
|
|||
while (!c->quit) { |
|||
log_error("Loop!"); |
|||
|
|||
r = sd_bus_process(bus, NULL); |
|||
if (r < 0) { |
|||
log_error("Failed to process requests: %s", strerror(-r)); |
|||
goto fail; |
|||
} |
|||
|
|||
if (r == 0) { |
|||
r = sd_bus_wait(bus, (uint64_t) -1); |
|||
if (r < 0) { |
|||
log_error("Failed to wait: %s", strerror(-r)); |
|||
goto fail; |
|||
} |
|||
|
|||
continue; |
|||
} |
|||
} |
|||
|
|||
r = 0; |
|||
|
|||
fail: |
|||
if (bus) { |
|||
sd_bus_flush(bus); |
|||
sd_bus_unref(bus); |
|||
} |
|||
|
|||
return INT_TO_PTR(r); |
|||
} |
|||
|
|||
static int client(struct context *c) { |
|||
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL; |
|||
_cleanup_bus_unref_ sd_bus *bus = NULL; |
|||
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; |
|||
const char *s; |
|||
int r; |
|||
|
|||
assert_se(sd_bus_new(&bus) >= 0); |
|||
assert_se(sd_bus_set_fd(bus, c->fds[1], c->fds[1]) >= 0); |
|||
assert_se(sd_bus_start(bus) >= 0); |
|||
|
|||
r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AlterSomething", &error, &reply, "s", "hallo"); |
|||
assert_se(r >= 0); |
|||
|
|||
r = sd_bus_message_read(reply, "s", &s); |
|||
assert_se(r >= 0); |
|||
assert_se(streq(s, "<<<hallo>>>")); |
|||
|
|||
sd_bus_message_unref(reply); |
|||
reply = NULL; |
|||
|
|||
r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Doesntexist", &error, &reply, ""); |
|||
assert_se(r < 0); |
|||
assert_se(sd_bus_error_has_name(&error, "org.freedesktop.DBus.Error.UnknownMethod")); |
|||
|
|||
sd_bus_error_free(&error); |
|||
|
|||
r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AlterSomething", &error, &reply, "as", 1, "hallo"); |
|||
assert_se(r < 0); |
|||
assert_se(sd_bus_error_has_name(&error, "org.freedesktop.DBus.Error.InvalidArgs")); |
|||
|
|||
sd_bus_error_free(&error); |
|||
|
|||
r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, &reply, "s"); |
|||
assert_se(r >= 0); |
|||
|
|||
r = sd_bus_message_read(reply, "s", &s); |
|||
assert_se(r >= 0); |
|||
assert_se(streq(s, "<<<hallo>>>")); |
|||
|
|||
sd_bus_message_unref(reply); |
|||
reply = NULL; |
|||
|
|||
r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, "s", "test"); |
|||
assert_se(r >= 0); |
|||
|
|||
r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, &reply, "s"); |
|||
assert_se(r >= 0); |
|||
|
|||
r = sd_bus_message_read(reply, "s", &s); |
|||
assert_se(r >= 0); |
|||
assert_se(streq(s, "test")); |
|||
|
|||
sd_bus_message_unref(reply); |
|||
reply = NULL; |
|||
|
|||
r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, ""); |
|||
assert_se(r <= 0); |
|||
|
|||
r = sd_bus_message_read(reply, "s", &s); |
|||
assert_se(r >= 0); |
|||
fputs(s, stdout); |
|||
|
|||
sd_bus_message_unref(reply); |
|||
reply = NULL; |
|||
|
|||
r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/value/xuzz", "org.freedesktop.systemd.ValueTest", "Value", &error, &reply, "s"); |
|||
assert_se(r >= 0); |
|||
|
|||
r = sd_bus_message_read(reply, "s", &s); |
|||
assert_se(r >= 0); |
|||
log_info("read %s", s); |
|||
|
|||
sd_bus_message_unref(reply); |
|||
reply = NULL; |
|||
|
|||
r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, ""); |
|||
assert_se(r <= 0); |
|||
|
|||
r = sd_bus_message_read(reply, "s", &s); |
|||
assert_se(r >= 0); |
|||
fputs(s, stdout); |
|||
|
|||
sd_bus_message_unref(reply); |
|||
reply = NULL; |
|||
|
|||
r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, ""); |
|||
assert_se(r <= 0); |
|||
|
|||
r = sd_bus_message_read(reply, "s", &s); |
|||
assert_se(r >= 0); |
|||
fputs(s, stdout); |
|||
|
|||
sd_bus_message_unref(reply); |
|||
reply = NULL; |
|||
|
|||
r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, ""); |
|||
assert_se(r <= 0); |
|||
|
|||
r = sd_bus_message_read(reply, "s", &s); |
|||
assert_se(r >= 0); |
|||
fputs(s, stdout); |
|||
|
|||
sd_bus_message_unref(reply); |
|||
reply = NULL; |
|||
|
|||
r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", ""); |
|||
assert_se(r <= 0); |
|||
|
|||
bus_message_dump(reply); |
|||
|
|||
sd_bus_message_unref(reply); |
|||
reply = NULL; |
|||
|
|||
r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", "org.freedesktop.systemd.ValueTest2"); |
|||
assert_se(r < 0); |
|||
assert_se(sd_bus_error_has_name(&error, "org.freedesktop.DBus.Error.UnknownInterface")); |
|||
sd_bus_error_free(&error); |
|||
|
|||
r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Exit", &error, NULL, ""); |
|||
assert_se(r >= 0); |
|||
|
|||
sd_bus_flush(bus); |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
int main(int argc, char *argv[]) { |
|||
struct context c; |
|||
pthread_t s; |
|||
void *p; |
|||
int r, q; |
|||
|
|||
zero(c); |
|||
|
|||
assert_se(socketpair(AF_UNIX, SOCK_STREAM, 0, c.fds) >= 0); |
|||
|
|||
r = pthread_create(&s, NULL, server, &c); |
|||
if (r != 0) |
|||
return -r; |
|||
|
|||
r = client(&c); |
|||
|
|||
q = pthread_join(s, &p); |
|||
if (q != 0) |
|||
return -q; |
|||
|
|||
if (r < 0) |
|||
return r; |
|||
|
|||
if (PTR_TO_INT(p) < 0) |
|||
return PTR_TO_INT(p); |
|||
|
|||
free(c.something); |
|||
|
|||
return EXIT_SUCCESS; |
|||
} |
@ -0,0 +1,127 @@ |
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ |
|||
|
|||
#ifndef foosdbusvtablehfoo |
|||
#define foosdbusvtablehfoo |
|||
|
|||
/***
|
|||
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/>.
|
|||
***/ |
|||
|
|||
typedef struct sd_bus_vtable sd_bus_vtable; |
|||
|
|||
#include "sd-bus.h" |
|||
|
|||
enum { |
|||
_SD_BUS_VTABLE_START = '<', |
|||
_SD_BUS_VTABLE_END = '>', |
|||
_SD_BUS_VTABLE_METHOD = 'M', |
|||
_SD_BUS_VTABLE_SIGNAL = 'S', |
|||
_SD_BUS_VTABLE_PROPERTY = 'P', |
|||
_SD_BUS_VTABLE_WRITABLE_PROPERTY = 'W', |
|||
_SD_BUS_VTABLE_CHILDREN = 'C' |
|||
}; |
|||
|
|||
enum { |
|||
SD_BUS_VTABLE_DEPRECATED = 1, |
|||
SD_BUS_VTABLE_METHOD_NO_REPLY = 2, |
|||
SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE = 4, |
|||
SD_BUS_VTABLE_PROPERTY_INVALIDATE_ONLY = 8, |
|||
}; |
|||
|
|||
struct sd_bus_vtable { |
|||
/* Please do not initialize this structure directly, use the
|
|||
* macros below instead */ |
|||
|
|||
int type; |
|||
int flags; |
|||
union { |
|||
struct { |
|||
size_t element_size; |
|||
} start; |
|||
struct { |
|||
const char *member; |
|||
const char *signature; |
|||
const char *result; |
|||
sd_bus_message_handler_t handler; |
|||
} method; |
|||
struct { |
|||
const char *member; |
|||
const char *signature; |
|||
} signal; |
|||
struct { |
|||
const char *member; |
|||
const char *signature; |
|||
sd_bus_property_get_t get; |
|||
sd_bus_property_set_t set; |
|||
size_t offset; |
|||
} property; |
|||
}; |
|||
}; |
|||
|
|||
#define SD_BUS_VTABLE_START(_flags) \ |
|||
{ \ |
|||
.type = _SD_BUS_VTABLE_START, \ |
|||
.flags = _flags, \ |
|||
.start.element_size = sizeof(sd_bus_vtable), \ |
|||
} |
|||
|
|||
#define SD_BUS_METHOD(_member, _signature, _result, _flags, _handler) \ |
|||
{ \ |
|||
.type = _SD_BUS_VTABLE_METHOD, \ |
|||
.flags = _flags, \ |
|||
.method.member = _member, \ |
|||
.method.signature = _signature, \ |
|||
.method.result = _result, \ |
|||
.method.handler = _handler, \ |
|||
} |
|||
|
|||
#define SD_BUS_SIGNAL(_member, _signature, _flags) \ |
|||
{ \ |
|||
.type = _SD_BUS_VTABLE_SIGNAL, \ |
|||
.flags = _flags, \ |
|||
.signal.member = _member, \ |
|||
.signal.signature = _signature, \ |
|||
} |
|||
|
|||
#define SD_BUS_PROPERTY(_member, _signature, _get, _offset, _flags) \ |
|||
{ \ |
|||
.type = _SD_BUS_VTABLE_PROPERTY, \ |
|||
.flags = _flags, \ |
|||
.property.member = _member, \ |
|||
.property.signature = _signature, \ |
|||
.property.get = _get, \ |
|||
.property.offset = _offset, \ |
|||
} |
|||
|
|||
#define SD_BUS_WRITABLE_PROPERTY(_member, _signature, _get, _set, _offset, _flags) \ |
|||
{ \ |
|||
.type = _SD_BUS_VTABLE_WRITABLE_PROPERTY, \ |
|||
.flags = _flags, \ |
|||
.property.member = _member, \ |
|||
.property.signature = _signature, \ |
|||
.property.get = _get, \ |
|||
.property.set = _set, \ |
|||
.property.offset = _offset, \ |
|||
} |
|||
|
|||
#define SD_BUS_VTABLE_END \ |
|||
{ \ |
|||
.type = _SD_BUS_VTABLE_END, \ |
|||
} |
|||
|
|||
#endif |