From 1e06a03915729f09c205c7cc3d290186a07e0a29 Mon Sep 17 00:00:00 2001 From: Krisztian Litkey Date: Mon, 4 Jun 2012 18:24:18 +0300 Subject: [PATCH] common: initial version of DBUS low-level and transport abstractions. --- configure.ac | 30 +- src/Makefile.am | 87 ++- src/common/dbus-transport.c | 1516 ++++++++++++++++++++++++++++++++++++++++++ src/common/dbus-transport.h | 26 + src/common/dbus.c | 1316 ++++++++++++++++++++++++++++++++++++ src/common/dbus.h | 141 ++++ src/common/tests/Makefile.am | 13 +- src/common/transport.c | 6 +- src/common/transport.h | 57 +- src/daemon/murphy.conf | 6 +- 10 files changed, 3144 insertions(+), 54 deletions(-) create mode 100644 src/common/dbus-transport.c create mode 100644 src/common/dbus-transport.h create mode 100644 src/common/dbus.c create mode 100644 src/common/dbus.h diff --git a/configure.ac b/configure.ac index 7801c37..5743f29 100644 --- a/configure.ac +++ b/configure.ac @@ -85,15 +85,6 @@ PKG_CHECK_MODULES(GLIB, glib-2.0) AC_SUBST(GLIB_CFLAGS) AC_SUBST(GLIB_LIBS) -# Check for low-level DBUS libs. -PKG_CHECK_MODULES(DBUS, dbus-1 >= 0.70) -AC_SUBST(DBUS_CFLAGS) -AC_SUBST(DBUS_LIBS) - -DBUS_SESSION_DIR="`pkg-config --variable session_bus_services_dir dbus-1`" -AC_SUBST(DBUS_SESSION_DIR) - - # Check and enable extra compiler warnings if they are supported. AC_ARG_ENABLE(extra-warnings, [ --enable-extra-warnings enable extra compiler warnings], @@ -113,6 +104,27 @@ fi AC_SUBST(WARNING_CFLAGS) +# Check if DBUS was enabled. +AC_ARG_ENABLE(dbus, + [ --enable-dbus enable D-BUS support], + [enable_dbus=$enableval], [enable_dbus=no]) + +if test "$enable_dbus" = "yes"; then + PKG_CHECK_MODULES(DBUS, dbus-1 >= 0.70) + + DBUS_SESSION_DIR="`pkg-config --variable session_bus_services_dir dbus-1`" + AC_SUBST(DBUS_SESSION_DIR) +else + AC_MSG_NOTICE([D-Bus support is disabled.]) +fi + +AM_CONDITIONAL(DBUS_ENABLED, [test "$enable_dbus" = "yes"]) +AC_SUBST(DBUS_ENABLED) +AC_SUBST(DBUS_CFLAGS) +AC_SUBST(DBUS_LIBS) + + + # Set up murphy CFLAGS and LIBS. MURPHY_CFLAGS="$GLIB_CFLAGS $DBUS_CFLAGS" MURPHY_LIBS="$GLIB_LIBS $DBUS_LIBS" diff --git a/src/Makefile.am b/src/Makefile.am index 5284e26..2119183 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -40,24 +40,23 @@ libmurphy_common_la_HEADERS = \ common/msg.h \ common/transport.h - -libmurphy_common_la_SOURCES = \ - common/log.c \ - common/mm.c \ - common/hashtbl.c \ - common/mainloop.c \ - common/utils.c \ - common/file-utils.c \ - common/msg.c \ - common/transport.c \ - common/stream-transport.c \ +libmurphy_common_la_SOURCES = \ + common/log.c \ + common/mm.c \ + common/hashtbl.c \ + common/mainloop.c \ + common/utils.c \ + common/file-utils.c \ + common/msg.c \ + common/transport.c \ + common/stream-transport.c \ common/dgram-transport.c libmurphy_common_la_CFLAGS = \ $(AM_CFLAGS) -libmurphy_common_la_LDFLAGS = \ - -Wl,-version-script=linker-script.common \ +libmurphy_common_la_LDFLAGS = \ + -Wl,-version-script=linker-script.common \ -version-info @MURPHY_VERSION_INFO@ libmurphy_common_la_LIBADD = \ @@ -110,7 +109,7 @@ libmurphy_core_la_LDFLAGS = \ -Wl,-version-script=linker-script.core \ -version-info @MURPHY_VERSION_INFO@ -libmurphy_core_la_LIBADD = \ +libmurphy_core_la_LIBADD = \ libmurphy-common.la -ldl libmurphy_core_la_DEPENDENCIES = linker-script.core @@ -123,6 +122,58 @@ clean-linker-script:: -rm -f linker-script.core ################################### +# murphy dbus library +# + +if DBUS_ENABLED +lib_LTLIBRARIES += libmurphy-dbus.la +EXTRA_DIST += common/murphy-dbus.pc +pkgconfig_DATA += common/murphy-dbus.pc + +libmurphy_dbush_ladir = \ + $(includedir)/murphy + +libmurphy_dbush_la_HEADERS = \ + common/dbus.h \ + common/dbus-transport.h + +libmurphy_dbus_ladir = \ + $(includedir)/murphy/common + +libmurphy_dbus_la_HEADERS = \ + common/dbus.h \ + common/dbus-transport.h + +libmurphy_dbus_la_SOURCES = \ + common/dbus.c \ + common/dbus-glue.c \ + common/dbus-transport.c + +libmurphy_dbus_la_CFLAGS = \ + $(AM_CFLAGS) \ + $(DBUS_CFLAGS) + +libmurphy_dbus_la_LDFLAGS = \ + -Wl,-version-script=linker-script.dbus \ + -version-info @MURPHY_VERSION_INFO@ + +libmurphy_dbus_la_LIBADD = \ + -lrt $(DBUS_LIBS) + +libmurphy_dbus_la_DEPENDENCIES = linker-script.dbus + +libdbusincludedir = $(includedir)/murphy/dbus +libdbusinclude_HEADERS = $(libmurphy_dbus_la_HEADERS) + +# linker script generation +linker-script.dbus: $(libmurphy_dbus_la_HEADERS) + $(QUIET_GEN)$(top_builddir)/build-aux/gen-linker-script -q -o $@ $^ + +clean-linker-script:: + -rm -f linker-script.dbus +endif + +################################### # murphy plugins # @@ -153,9 +204,10 @@ plugin_LTLIBRARIES += plugin-test.la endif # dbus plugin +if DBUS_ENABLED DBUS_PLUGIN_SOURCES = plugins/plugin-dbus.c DBUS_PLUGIN_CFLAGS = $(DBUS_CFLAGS) -DBUS_PLUGIN_LIBS = $(DBUS_LIBS) +DBUS_PLUGIN_LIBS = libmurphy-dbus.la if BUILTIN_PLUGIN_DBUS BUILTIN_PLUGINS += $(DBUS_PLUGIN_SOURCES) @@ -169,6 +221,7 @@ plugin_dbus_la_LIBADD = $(DBUS_PLUGIN_LIBS) plugin_LTLIBRARIES += plugin-dbus.la endif +endif # glib plugin GLIB_PLUGIN_SOURCES = plugins/plugin-glib.c @@ -247,6 +300,10 @@ murphy_console_LDADD = \ libmurphy-common.la \ $(BUILTIN_LIBS) +if DBUS_ENABLED +murphy_console_LDADD += libmurphy-dbus.la +endif + murphy_console_LDFLAGS = -rdynamic -lreadline #end diff --git a/src/common/dbus-transport.c b/src/common/dbus-transport.c new file mode 100644 index 0000000..c0c574e --- /dev/null +++ b/src/common/dbus-transport.c @@ -0,0 +1,1516 @@ +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#define DBUS "dbus" +#define DBUSL 4 + +#define TRANSPORT_PATH "/murphy/transport" +#define TRANSPORT_INTERFACE "Murphy.Transport" +#define TRANSPORT_MESSAGE "DeliverMessage" +#define TRANSPORT_CUSTOM "DeliverCustom" +#define TRANSPORT_RAW "DeliverRaw" +#define TRANSPORT_METHOD "DeliverMessage" + +#define ANY_ADDRESS "any" + +typedef struct { + MRP_TRANSPORT_PUBLIC_FIELDS; /* common transport fields */ + mrp_dbus_t *dbus; /* D-BUS connection */ + int bound : 1; /* whether bound to an address */ + mrp_dbusaddr_t local; /* address we're bound to */ + mrp_dbusaddr_t remote; /* address we're connected to */ +} dbus_t; + + +static uint32_t nauto; /* for autobinding */ + + +static int dbus_msg_cb(mrp_dbus_t *dbus, DBusMessage *msg, void *user_data); +static int dbus_data_cb(mrp_dbus_t *dbus, DBusMessage *msg, void *user_data); +static int dbus_raw_cb(mrp_dbus_t *dbus, DBusMessage *msg, void *user_data); + +#if 0 +static int dbus_recv_cb(mrp_dbus_t *dbus, DBusMessage *msg, void *user_data); +#endif + +static DBusMessage *msg_encode(const char *sender_id, mrp_msg_t *msg); +static mrp_msg_t *msg_decode(DBusMessage *m, const char **sender_id); + +static DBusMessage *data_encode(const char *sender_id, + void *data, uint16_t tag); +static void *data_decode(DBusMessage *m, uint16_t *tag, const char **sender_id); + + + + +static socklen_t parse_address(const char *str, mrp_dbusaddr_t *addr, + socklen_t size) +{ + const char *p, *e; + char *q; + size_t l, n; + + if (size < sizeof(*addr)) { + errno = EINVAL; + return FALSE; + } + + if (strncmp(str, DBUS":", DBUSL + 1)) + return 0; + else + str += DBUSL + 1; + + /* + * The format of the address is + * dbus:[bus-address]@address/path + * eg. + * dbus:[session]@:1.33/client1, or + * dbus:[unix:abstract=/tmp/dbus-Xx2Kpi...a572]@:1.33/client1 + */ + + p = str; + q = addr->db_fqa; + l = sizeof(addr->db_fqa); + + /* get bus address */ + if (*p != '[') { + errno = EINVAL; + return 0; + } + else + p++; + + e = strchr(p, ']'); + + if (e == NULL) { + errno = EINVAL; + return 0; + } + + n = e - p; + if (n >= l) { + errno = ENAMETOOLONG; + return 0; + } + + /* save bus address */ + strncpy(q, p, n); + q[n] = '\0'; + addr->db_bus = q; + + q += n + 1; + l -= n + 1; + p = e + 1; + + /* get (local or remote) address on bus */ + if (*p != '@') + addr->db_addr = ANY_ADDRESS; + else { + p++; + e = strchr(p, '/'); + + if (e == NULL) { + errno = EINVAL; + return 0; + } + + n = e - p; + if (n >= l) { + errno = ENAMETOOLONG; + return 0; + } + + /* save address on bus */ + strncpy(q, p, n); + q[n] = '\0'; + addr->db_addr = q; + + q += n + 1; + l -= n + 1; + p = e; + } + + /* get object path */ + if (*p != '/') { + errno = EINVAL; + return 0; + } + + n = snprintf(q, l, "%s%s", TRANSPORT_PATH, p); + if (n >= l) { + errno = ENAMETOOLONG; + return 0; + } + + addr->db_path = q; + addr->db_family = MRP_AF_DBUS; + + return sizeof(*addr); +} + + +static mrp_dbusaddr_t *copy_address(mrp_dbusaddr_t *dst, mrp_dbusaddr_t *src) +{ + char *p, *q; + size_t l, n; + + dst->db_family = src->db_family; + + /* copy bus address */ + p = src->db_bus; + q = dst->db_fqa; + l = sizeof(dst->db_fqa); + + n = strlen(p); + if (l < n + 1) { + errno = EOVERFLOW; + return NULL; + } + + dst->db_bus = q; + memcpy(q, p, n + 1); + q += n + 1; + l -= n + 1; + + /* copy address */ + p = src->db_addr; + n = strlen(p); + if (l < n + 1) { + errno = EOVERFLOW; + return NULL; + } + + dst->db_addr = q; + memcpy(q, p, n + 1); + q += n + 1; + l -= n + 1; + + /* copy path */ + p = src->db_path; + n = strlen(p); + if (l < n + 1) { + errno = EOVERFLOW; + return NULL; + } + + dst->db_path = q; + memcpy(q, p, n + 1); + q += n + 1; + l -= n + 1; + + return dst; +} + + +static inline int check_address(mrp_sockaddr_t *addr, socklen_t addrlen) +{ + mrp_dbusaddr_t *a = (mrp_dbusaddr_t *)addr; + + return (a->db_family = MRP_AF_DBUS && addrlen == sizeof(*a)); +} + + +static size_t peer_address(mrp_sockaddr_t *addrp, const char *sender, + const char *path) +{ + mrp_dbusaddr_t *addr = (mrp_dbusaddr_t *)addrp; + const char *p; + char *q; + int l, n; + + q = addr->db_fqa; + l = sizeof(addr->db_fqa); + p = ANY_ADDRESS; + n = 3; + + addr->db_bus = q; + memcpy(q, p, n + 1); + q += n + 1; + l -= n + 1; + + addr->db_addr = q; + p = sender; + n = strlen(sender); + + if (l < n + 1) + return 0; + + memcpy(q, p, n + 1); + q += n + 1; + l -= n + 1; + + addr->db_path = q; + p = path; + n = strlen(p); + + if (l < n + 1) + return 0; + + memcpy(q, p, n + 1); + + return sizeof(addrp); +} + + +static socklen_t dbus_resolve(const char *str, mrp_sockaddr_t *addr, + socklen_t size, const char **typep) +{ + socklen_t len; + + len = parse_address(str, (mrp_dbusaddr_t *)addr, size); + + if (len > 0) { + if (typep != NULL) + *typep = DBUS; + } + + return len; +} + + +static int dbus_open(mrp_transport_t *mt) +{ + MRP_UNUSED(mt); + + return TRUE; +} + + +static int dbus_createfrom(mrp_transport_t *mt, void *conn) +{ + dbus_t *t = (dbus_t *)mt; + mrp_dbus_t *dbus = (mrp_dbus_t *)conn; + + t->dbus = mrp_dbus_ref(dbus); + + if (t->dbus != NULL) + return TRUE; + else + return FALSE; +} + + +static int dbus_bind(mrp_transport_t *mt, mrp_sockaddr_t *addrp, + socklen_t addrlen) +{ + dbus_t *t = (dbus_t *)mt; + mrp_dbus_t *dbus = NULL; + mrp_dbusaddr_t *addr = (mrp_dbusaddr_t *)addrp; + int (*cb)(mrp_dbus_t *, DBusMessage *, void *); + const char *method; + + if (t->bound) { + errno = EINVAL; + goto fail; + } + + if (!check_address(addrp, addrlen)) { + errno = EINVAL; + goto fail; + } + + if (t->dbus == NULL) { + dbus = mrp_dbus_connect(t->ml, addr->db_bus, NULL); + + if (dbus == NULL) { + errno = ECONNRESET; + goto fail; + } + else { + t->dbus = dbus; + + if (addr->db_addr != NULL && strcmp(addr->db_addr, ANY_ADDRESS)) { + if (!mrp_dbus_acquire_name(t->dbus, addr->db_addr, NULL)) { + errno = EADDRINUSE; /* XXX TODO, should check error... */ + goto fail; + } + } + } + } + else { + /* XXX TODO: should check given address against address of the bus */ + } + + copy_address(&t->local, addr); + + if (t->flags & MRP_TRANSPORT_MODE_CUSTOM) { + method = TRANSPORT_CUSTOM; + cb = dbus_data_cb; + } + else if (t->flags & MRP_TRANSPORT_MODE_RAW) { + method = TRANSPORT_RAW; + cb = dbus_raw_cb; + } + else { + method = TRANSPORT_MESSAGE; + cb = dbus_msg_cb; + } + + if (!mrp_dbus_export_method(t->dbus, addr->db_path, TRANSPORT_INTERFACE, + method, cb, t)) { + errno = EIO; + goto fail; + } + else { + t->bound = TRUE; + return TRUE; + } + + fail: + if (dbus != NULL) { + mrp_dbus_unref(dbus); + t->dbus = NULL; + } + + return FALSE; +} + + +static int dbus_autobind(mrp_transport_t *mt, mrp_sockaddr_t *addrp) +{ + mrp_dbusaddr_t *a = (mrp_dbusaddr_t *)addrp; + char astr[MRP_SOCKADDR_SIZE]; + mrp_sockaddr_t addr; + socklen_t alen; + + snprintf(astr, sizeof(astr), "dbus:[%s]/auto/%u", a->db_bus, nauto++); + + alen = dbus_resolve(astr, &addr, sizeof(addr), NULL); + + if (alen > 0) + return dbus_bind(mt, &addr, alen); + else + return FALSE; +} + + +static void dbus_close(mrp_transport_t *mt) +{ + dbus_t *t = (dbus_t *)mt; + mrp_dbusaddr_t *addr; + const char *method; + int (*cb)(mrp_dbus_t *, DBusMessage *, void *); + + if (t->bound) { + if (t->flags & MRP_TRANSPORT_MODE_CUSTOM) { + method = TRANSPORT_CUSTOM; + cb = dbus_data_cb; + } + else if (t->flags & MRP_TRANSPORT_MODE_RAW) { + method = TRANSPORT_RAW; + cb = dbus_raw_cb; + } + else { + method = TRANSPORT_MESSAGE; + cb = dbus_msg_cb; + } + + addr = (mrp_dbusaddr_t *)&t->local; + mrp_dbus_remove_method(t->dbus, addr->db_path, TRANSPORT_INTERFACE, + method, cb, t); + } + + mrp_dbus_unref(t->dbus); + t->dbus = NULL; +} + + +static int dbus_msg_cb(mrp_dbus_t *dbus, DBusMessage *dmsg, void *user_data) +{ + mrp_transport_t *mt = (mrp_transport_t *)user_data; + mrp_sockaddr_t addr; + socklen_t alen; + const char *sender_path; + mrp_msg_t *msg; + + MRP_UNUSED(dbus); + + msg = msg_decode(dmsg, &sender_path); + + if (msg != NULL) { + if (mt->connected) { + MRP_TRANSPORT_BUSY(mt, { + mt->evt.recvmsg(mt, msg, mt->user_data); + }); + } + else { + peer_address(&addr, dbus_message_get_sender(dmsg), sender_path); + alen = sizeof(addr); + + MRP_TRANSPORT_BUSY(mt, { + mt->evt.recvmsgfrom(mt, msg, &addr, alen, + mt->user_data); + }); + } + + mrp_msg_unref(msg); + + mt->check_destroy(mt); + } + else { + mrp_log_error("Failed to decode message."); + } + + return TRUE; +} + + +static int dbus_data_cb(mrp_dbus_t *dbus, DBusMessage *dmsg, void *user_data) +{ + mrp_transport_t *mt = (mrp_transport_t *)user_data; + mrp_sockaddr_t addr; + socklen_t alen; + const char *sender_path; + uint16_t tag; + void *decoded; + + MRP_UNUSED(dbus); + + decoded = data_decode(dmsg, &tag, &sender_path); + + if (decoded != NULL) { + if (mt->connected) { + MRP_TRANSPORT_BUSY(mt, { + mt->evt.recvdata(mt, decoded, tag, mt->user_data); + }); + } + else { + peer_address(&addr, dbus_message_get_sender(dmsg), sender_path); + alen = sizeof(addr); + + MRP_TRANSPORT_BUSY(mt, { + mt->evt.recvdatafrom(mt, decoded, tag, &addr, alen, + mt->user_data); + }); + } + + mt->check_destroy(mt); + } + + return TRUE; +} + + +static int dbus_raw_cb(mrp_dbus_t *dbus, DBusMessage *dmsg, void *user_data) +{ + MRP_UNUSED(dbus); + MRP_UNUSED(dmsg); + MRP_UNUSED(user_data); + + return FALSE; +} + + +#if 0 +static int dbus_recv_cb(mrp_dbus_t *dbus, DBusMessage *dmsg, void *user_data) +{ + mrp_transport_t *mt = (mrp_transport_t *)user_data; + dbus_t *t = (dbus_t *)mt; + mrp_sockaddr_t addr; + socklen_t alen; + const char *sender_path; + uint16_t tag; + void *decoded; + mrp_msg_t *msg; + + MRP_UNUSED(dbus); + + if (t->flags & MRP_TRANSPORT_MODE_CUSTOM) { + decoded = data_decode(dmsg, &tag, &sender_path); + + if (decoded != NULL) { + if (mt->connected) { + MRP_TRANSPORT_BUSY(mt, { + mt->evt.recvdata(mt, decoded, tag, mt->user_data); + }); + } + else { + peer_address(&addr, dbus_message_get_sender(dmsg), sender_path); + alen = sizeof(addr); + + MRP_TRANSPORT_BUSY(mt, { + mt->evt.recvdatafrom(mt, decoded, tag, &addr, alen, + mt->user_data); + }); + } + + mt->check_destroy(mt); + } + } + else if (t->flags & MRP_TRANSPORT_MODE_RAW) { + mrp_log_error("%s(): XXX TODO: implement raw mode", __FUNCTION__); + } + else { + msg = msg_decode(dmsg, &sender_path); + + if (msg != NULL) { + if (mt->connected) { + MRP_TRANSPORT_BUSY(mt, { + mt->evt.recvmsg(mt, msg, mt->user_data); + }); + } + else { + peer_address(&addr, dbus_message_get_sender(dmsg), sender_path); + alen = sizeof(addr); + + MRP_TRANSPORT_BUSY(mt, { + mt->evt.recvmsgfrom(mt, msg, &addr, alen, + mt->user_data); + }); + } + + mrp_msg_unref(msg); + mt->check_destroy(mt); + } + else { + mrp_log_error("Failed to decode message."); + } + } + + return TRUE; +} +#endif + + +static int dbus_connect(mrp_transport_t *mt, mrp_sockaddr_t *addrp, + socklen_t addrlen) +{ + dbus_t *t = (dbus_t *)mt; + mrp_dbusaddr_t *addr = (mrp_dbusaddr_t *)addrp; + + if (!check_address(addrp, addrlen)) { + errno = EINVAL; + return FALSE; + } + + if (t->dbus == NULL) { + t->dbus = mrp_dbus_connect(t->ml, addr->db_bus, NULL); + + if (t->dbus == NULL) { + errno = ECONNRESET; + return FALSE; + } + } + else { + /* XXX TODO: check given address against address of the bus */ + } + + if (!t->bound) + if (!dbus_autobind(mt, addrp)) + return FALSE; + + copy_address(&t->remote, addr); + + return TRUE; +} + + +static int dbus_disconnect(mrp_transport_t *mt) +{ + dbus_t *t = (dbus_t *)mt; + + mrp_clear(&t->remote); + + return TRUE; +} + + +static int dbus_sendmsgto(mrp_transport_t *mt, mrp_msg_t *msg, + mrp_sockaddr_t *addrp, socklen_t addrlen) +{ + dbus_t *t = (dbus_t *)mt; + mrp_dbusaddr_t *addr = (mrp_dbusaddr_t *)addrp; + DBusMessage *m; + int success; + + if (check_address(addrp, addrlen)) { + if (t->dbus == NULL && !dbus_autobind(mt, addrp)) + return FALSE; + + m = msg_encode(t->local.db_path, msg); + + if (m != NULL) { + if (dbus_message_set_destination(m, addr->db_addr) && + dbus_message_set_path(m, addr->db_path) && + dbus_message_set_interface(m, TRANSPORT_INTERFACE) && + dbus_message_set_member(m, TRANSPORT_MESSAGE)) { + if (mrp_dbus_send_msg(t->dbus, m)) + success = TRUE; + else { + errno = EIO; + success = FALSE; + } + } + else { + errno = ECOMM; + success = FALSE; + } + + dbus_message_unref(m); + } + else + success = FALSE; + } + else { + errno = EINVAL; + success = FALSE; + } + + return success; +} + + +static int dbus_sendmsg(mrp_transport_t *mt, mrp_msg_t *msg) +{ + dbus_t *t = (dbus_t *)mt; + mrp_sockaddr_t *addr = (mrp_sockaddr_t *)&t->remote; + socklen_t alen = sizeof(t->remote); + + return dbus_sendmsgto(mt, msg, addr, alen); +} + + +static int dbus_sendrawto(mrp_transport_t *mt, void *data, size_t size, + mrp_sockaddr_t *addr, socklen_t addrlen) +{ + MRP_UNUSED(mt); + MRP_UNUSED(data); + MRP_UNUSED(size); + MRP_UNUSED(addr); + MRP_UNUSED(addrlen); + + return FALSE; +} + + +static int dbus_sendraw(mrp_transport_t *mt, void *data, size_t size) +{ + dbus_t *t = (dbus_t *)mt; + mrp_sockaddr_t *addr = (mrp_sockaddr_t *)&t->remote; + socklen_t alen = sizeof(t->remote); + + return dbus_sendrawto(mt, data, size, addr, alen); +} + + +static int dbus_senddatato(mrp_transport_t *mt, void *data, uint16_t tag, + mrp_sockaddr_t *addrp, socklen_t addrlen) +{ + dbus_t *t = (dbus_t *)mt; + mrp_dbusaddr_t *addr = (mrp_dbusaddr_t *)addrp; + DBusMessage *m; + int success; + + if (check_address(addrp, addrlen)) { + if (t->dbus == NULL && !dbus_autobind(mt, addrp)) + return FALSE; + + m = data_encode(t->local.db_path, data, tag); + + if (m != NULL) { + if (dbus_message_set_destination(m, addr->db_addr) && + dbus_message_set_path(m, addr->db_path) && + dbus_message_set_interface(m, TRANSPORT_INTERFACE) && + dbus_message_set_member(m, TRANSPORT_CUSTOM)) { + if (mrp_dbus_send_msg(t->dbus, m)) + success = TRUE; + else { + errno = EIO; + success = FALSE; + } + } + else { + errno = ECOMM; + success = FALSE; + } + + dbus_message_unref(m); + } + else + success = FALSE; + } + else { + errno = EINVAL; + success = FALSE; + } + + return success; +} + + +static int dbus_senddata(mrp_transport_t *mt, void *data, uint16_t tag) +{ + dbus_t *t = (dbus_t *)mt; + mrp_sockaddr_t *addr = (mrp_sockaddr_t *)&t->remote; + socklen_t alen = sizeof(t->remote); + + return dbus_senddatato(mt, data, tag, addr, alen); +} + + +static const char *get_array_signature(uint16_t type) +{ +#define MAP(from, to) \ + case MRP_MSG_FIELD_##from: \ + return DBUS_TYPE_##to##_AS_STRING; + + switch (type) { + MAP(STRING, STRING); + MAP(BOOL , BOOLEAN); + MAP(UINT8 , UINT16); + MAP(SINT8 , INT16); + MAP(UINT16, UINT16); + MAP(SINT16, INT16); + MAP(UINT32, UINT32); + MAP(SINT32, INT32); + MAP(UINT64, UINT64); + MAP(SINT64, INT64); + MAP(DOUBLE, DOUBLE); + default: + return NULL; + } +} + + +static DBusMessage *msg_encode(const char *sender_id, mrp_msg_t *msg) +{ + /* + * Notes: There is a type mismatch between our and DBUS types for + * 8-bit integers (D-BUS does not have a signed 8-bit type) + * and boolean types (D-BUS has uint32_t booleans, C99 fails + * to specify the type and gcc uses a signed char). The + * QUIRKY versions of the macros take care of these mismatches. + */ + +#define BASIC_SIMPLE(_i, _mtype, _dtype, _val) \ + case MRP_MSG_FIELD_##_mtype: \ + type = DBUS_TYPE_##_dtype; \ + vptr = &(_val); \ + \ + if (!dbus_message_iter_append_basic(_i, type, vptr)) \ + goto fail; \ + break + +#define BASIC_QUIRKY(_i, _mtype, _dtype, _mval, _dval) \ + case MRP_MSG_FIELD_##_mtype: \ + type = DBUS_TYPE_##_dtype; \ + _dval = _mval; \ + vptr = &_dval; \ + \ + if (!dbus_message_iter_append_basic(_i, type, vptr)) \ + goto fail; \ + break + +#define ARRAY_SIMPLE(_i, _mtype, _dtype, _val) \ + case MRP_MSG_FIELD_##_mtype: \ + type = DBUS_TYPE_##_dtype; \ + vptr = &_val; \ + \ + if (!dbus_message_iter_append_basic(_i, type, vptr)) \ + goto fail; \ + break + +#define ARRAY_QUIRKY(_i, _mtype, _dtype, _mvar, _dvar) \ + case MRP_MSG_FIELD_##_mtype: \ + type = DBUS_TYPE_##_dtype; \ + _dvar = _mvar; \ + vptr = &_dvar; \ + \ + if (!dbus_message_iter_append_basic(_i, type, vptr)) \ + goto fail; \ + break + + DBusMessage *m; + mrp_list_hook_t *p, *n; + mrp_msg_field_t *f; + uint16_t base; + uint32_t asize, i; + DBusMessageIter im, ia; + int type; + void *vptr; + dbus_bool_t bln; + uint16_t u16; + int16_t s16; + + m = dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_CALL); + + if (m == NULL) + return NULL; + + dbus_message_iter_init_append(m, &im); + + if (!dbus_message_iter_append_basic(&im, DBUS_TYPE_OBJECT_PATH, &sender_id)) + goto fail; + + if (!dbus_message_iter_append_basic(&im, DBUS_TYPE_UINT16, &msg->nfield)) + goto fail; + + mrp_list_foreach(&msg->fields, p, n) { + f = mrp_list_entry(p, typeof(*f), hook); + + if (!dbus_message_iter_append_basic(&im, DBUS_TYPE_UINT16, &f->tag) || + !dbus_message_iter_append_basic(&im, DBUS_TYPE_UINT16, &f->type)) + goto fail; + + switch (f->type) { + BASIC_SIMPLE(&im, STRING, STRING , f->str); + BASIC_QUIRKY(&im, BOOL , BOOLEAN, f->bln, bln); + BASIC_QUIRKY(&im, UINT8 , UINT16 , f->u8 , u16); + BASIC_QUIRKY(&im, SINT8 , INT16 , f->s8 , s16); + BASIC_SIMPLE(&im, UINT16, UINT16 , f->u16); + BASIC_SIMPLE(&im, SINT16, INT16 , f->s16); + BASIC_SIMPLE(&im, UINT32, UINT32 , f->u32); + BASIC_SIMPLE(&im, SINT32, INT32 , f->s32); + BASIC_SIMPLE(&im, UINT64, UINT64 , f->u64); + BASIC_SIMPLE(&im, SINT64, INT64 , f->s64); + BASIC_SIMPLE(&im, DOUBLE, DOUBLE , f->dbl); + + case MRP_MSG_FIELD_BLOB: + mrp_log_error("%s(): XXX TODO: implement blob encoding...", + __FUNCTION__); + goto fail; + + default: + if (f->type & MRP_MSG_FIELD_ARRAY) { + base = f->type & ~(MRP_MSG_FIELD_ARRAY); + asize = f->size[0]; + + if (!dbus_message_iter_append_basic(&im, + DBUS_TYPE_UINT32, &asize)) + goto fail; + + if (!dbus_message_iter_open_container(&im, DBUS_TYPE_ARRAY, + get_array_signature(base), + &ia)) + goto fail; + + for (i = 0; i < asize; i++) { + switch (base) { + ARRAY_SIMPLE(&ia, STRING, STRING , f->astr[i]); + ARRAY_QUIRKY(&ia, BOOL , BOOLEAN, f->abln[i], bln); + ARRAY_QUIRKY(&ia, UINT8 , UINT16 , f->au8[i] , u16); + ARRAY_QUIRKY(&ia, SINT8 , INT16 , f->as8[i] , s16); + ARRAY_SIMPLE(&ia, UINT16, UINT16 , f->au16[i]); + ARRAY_SIMPLE(&ia, SINT16, INT16 , f->as16[i]); + ARRAY_SIMPLE(&ia, UINT32, UINT32 , f->au32[i]); + ARRAY_SIMPLE(&ia, SINT32, INT32 , f->as32[i]); + ARRAY_SIMPLE(&ia, UINT64, UINT64 , f->au64[i]); + ARRAY_SIMPLE(&ia, DOUBLE, DOUBLE , f->adbl[i]); + + case MRP_MSG_FIELD_BLOB: + goto fail; + + default: + goto fail; + } + } + + if (!dbus_message_iter_close_container(&im, &ia)) + goto fail; + } + else + goto fail; + } + } + + return m; + + fail: + if (m != NULL) + dbus_message_unref(m); + + errno = ECOMM; + + return FALSE; + +#undef BASIC_SIMPLE +#undef BASIC_QUIRKY +#undef ARRAY_SIMPLE +#undef ARRAY_QUIRKY +} + + +static mrp_msg_t *msg_decode(DBusMessage *m, const char **sender_id) +{ +#define BASIC_SIMPLE(_i, _mtype, _dtype, _var) \ + case MRP_MSG_FIELD_##_mtype: \ + if (dbus_message_iter_get_arg_type(_i) != DBUS_TYPE_##_dtype) \ + goto fail; \ + dbus_message_iter_get_basic(_i, &(_var)); \ + dbus_message_iter_next(_i); \ + \ + if (!mrp_msg_append(msg, tag, type, (_var))) \ + goto fail; \ + break + +#define BASIC_QUIRKY(_i, _mtype, _dtype, _mvar, _dvar) \ + case MRP_MSG_FIELD_##_mtype: \ + if (dbus_message_iter_get_arg_type(_i) != DBUS_TYPE_##_dtype) \ + goto fail; \ + dbus_message_iter_get_basic(_i, &(_dvar)); \ + dbus_message_iter_next(_i); \ + \ + _mvar = _dvar; \ + if (!mrp_msg_append(msg, tag, type, (_mvar))) \ + goto fail; \ + break + +#define ARRAY_SIMPLE(_i, _mtype, _dtype, _var) \ + case MRP_MSG_FIELD_##_mtype: \ + if (dbus_message_iter_get_arg_type(_i) != DBUS_TYPE_##_dtype) \ + goto fail; \ + dbus_message_iter_get_basic(_i, &(_var)); \ + dbus_message_iter_next(_i); \ + break + +#define ARRAY_QUIRKY(_i, _mtype, _dtype, _mvar, _dvar) \ + case MRP_MSG_FIELD_##_mtype: \ + if (dbus_message_iter_get_arg_type(_i) != DBUS_TYPE_##_dtype) \ + goto fail; \ + dbus_message_iter_get_basic(_i, &(_dvar)); \ + dbus_message_iter_next(_i); \ + \ + _mvar = _dvar; \ + break + +#define APPEND_ARRAY(_type, _var) \ + case MRP_MSG_FIELD_##_type: \ + if (!mrp_msg_append(msg, tag, \ + MRP_MSG_FIELD_ARRAY | \ + MRP_MSG_FIELD_##_type, \ + n, _var)) \ + goto fail; \ + break + + mrp_msg_t *msg; + mrp_msg_value_t v; + uint16_t u16; + int16_t s16; + uint32_t u32; + DBusMessageIter im, ia; + uint16_t nfield, tag, type, base, i; + uint32_t n, j; + const char *sender; + + if (!dbus_message_iter_init(m, &im)) + goto fail; + + if (dbus_message_iter_get_arg_type(&im) != DBUS_TYPE_OBJECT_PATH) + goto fail; + + dbus_message_iter_get_basic(&im, &sender); + dbus_message_iter_next(&im); + + if (dbus_message_iter_get_arg_type(&im) != DBUS_TYPE_UINT16) + goto fail; + + dbus_message_iter_get_basic(&im, &nfield); + dbus_message_iter_next(&im); + + msg = mrp_msg_create_empty(); + + if (msg == NULL) + goto fail; + + for (i = 0; i < nfield; i++) { + if (dbus_message_iter_get_arg_type(&im) != DBUS_TYPE_UINT16) + goto fail; + + dbus_message_iter_get_basic(&im, &tag); + dbus_message_iter_next(&im); + + if (dbus_message_iter_get_arg_type(&im) != DBUS_TYPE_UINT16) + goto fail; + + dbus_message_iter_get_basic(&im, &type); + dbus_message_iter_next(&im); + + switch (type) { + BASIC_SIMPLE(&im, STRING, STRING , v.str); + BASIC_QUIRKY(&im, BOOL , BOOLEAN, v.bln, u32); + BASIC_QUIRKY(&im, UINT8 , UINT16 , v.u8 , u16); + BASIC_QUIRKY(&im, SINT8 , INT16 , v.s8 , s16); + BASIC_SIMPLE(&im, UINT16, UINT16 , v.u16); + BASIC_SIMPLE(&im, SINT16, INT16 , v.s16); + BASIC_SIMPLE(&im, UINT32, UINT32 , v.u32); + BASIC_SIMPLE(&im, SINT32, INT32 , v.s32); + BASIC_SIMPLE(&im, UINT64, UINT64 , v.u64); + BASIC_SIMPLE(&im, SINT64, INT64 , v.s64); + BASIC_SIMPLE(&im, DOUBLE, DOUBLE , v.dbl); + + case MRP_MSG_FIELD_BLOB: + mrp_log_error("%s(): XXX TODO: implement blob decoding...", + __FUNCTION__); + goto fail; + + default: + if (!(type & MRP_MSG_FIELD_ARRAY)) + goto fail; + + base = type & ~(MRP_MSG_FIELD_ARRAY); + + if (dbus_message_iter_get_arg_type(&im) != DBUS_TYPE_UINT32) + goto fail; + + dbus_message_iter_get_basic(&im, &n); + dbus_message_iter_next(&im); + + if (dbus_message_iter_get_arg_type(&im) != DBUS_TYPE_ARRAY) + goto fail; + dbus_message_iter_recurse(&im, &ia); + dbus_message_iter_next(&im); + + { + char *astr[n]; + uint32_t dbln[n]; + bool abln[n]; + uint8_t au8 [n]; + int8_t as8 [n]; + uint16_t au16[n]; + int16_t as16[n]; + uint32_t au32[n]; + int32_t as32[n]; + uint64_t au64[n]; + int64_t as64[n]; + double adbl[n]; + + for (j = 0; j < n; j++) { + switch (base) { + ARRAY_SIMPLE(&ia, STRING, STRING , astr[j]); + ARRAY_QUIRKY(&ia, BOOL , BOOLEAN, abln[j], dbln[j]); + ARRAY_QUIRKY(&ia, UINT8 , UINT16 , au8[j] , au16[j]); + ARRAY_QUIRKY(&ia, SINT8 , INT16 , as8[j] , as16[j]); + ARRAY_SIMPLE(&ia, UINT16, UINT16 , au16[j]); + ARRAY_SIMPLE(&ia, SINT16, INT16 , as16[j]); + ARRAY_SIMPLE(&ia, UINT32, UINT32 , au32[j]); + ARRAY_SIMPLE(&ia, SINT32, INT32 , as32[j]); + ARRAY_SIMPLE(&ia, UINT64, UINT64 , au64[j]); + ARRAY_SIMPLE(&ia, SINT64, INT64 , as64[j]); + ARRAY_SIMPLE(&ia, DOUBLE, DOUBLE , adbl[j]); + default: + goto fail; + } + } + + switch (base) { + APPEND_ARRAY(STRING, astr); + APPEND_ARRAY(BOOL , abln); + APPEND_ARRAY(UINT8 , au8 ); + APPEND_ARRAY(SINT8 , as8 ); + APPEND_ARRAY(UINT16, au16); + APPEND_ARRAY(SINT16, as16); + APPEND_ARRAY(UINT32, au32); + APPEND_ARRAY(SINT32, as32); + APPEND_ARRAY(UINT64, au64); + APPEND_ARRAY(SINT64, as64); + APPEND_ARRAY(DOUBLE, adbl); + default: + goto fail; + } + } + } + } + + if (sender_id != NULL) + *sender_id = sender; + + return msg; + + fail: + mrp_msg_unref(msg); + errno = EBADMSG; + + return NULL; + +#undef BASIC_SIMPLE +#undef BASIC_QUIRKY +#undef ARRAY_SIMPLE +#undef ARRAY_QUIRKY +#undef APPEND_ARRAY +} + + +static DBusMessage *data_encode(const char *sender_id, void *data, uint16_t tag) +{ +#define BASIC_SIMPLE(_mtype, _dtype, _val) \ + case MRP_MSG_FIELD_##_mtype: \ + type = DBUS_TYPE_##_dtype; \ + vptr = &(_val); \ + \ + if (!dbus_message_iter_append_basic(&im, type, vptr)) \ + goto fail; \ + break + +#define BASIC_QUIRKY(_mtype, _dtype, _mval, _dval) \ + case MRP_MSG_FIELD_##_mtype: \ + type = DBUS_TYPE_##_dtype; \ + _dval = _mval; \ + vptr = &_dval; \ + \ + if (!dbus_message_iter_append_basic(&im, type, vptr)) \ + goto fail; \ + break + +#define ARRAY_SIMPLE(_mtype, _dtype, _val) \ + case MRP_MSG_FIELD_##_mtype: \ + type = DBUS_TYPE_##_dtype; \ + vptr = &_val; \ + \ + if (!dbus_message_iter_append_basic(&ia, type, vptr)) \ + goto fail; \ + break + +#define ARRAY_QUIRKY(_mtype, _dtype, _mvar, _dvar) \ + case MRP_MSG_FIELD_##_mtype: \ + type = DBUS_TYPE_##_dtype; \ + _dvar = _mvar; \ + vptr = &_dvar; \ + \ + if (!dbus_message_iter_append_basic(&ia, type, vptr)) \ + goto fail; \ + break + + DBusMessage *m; + mrp_data_descr_t *descr; + mrp_data_member_t *fields, *f; + int nfield; + uint16_t type, base; + mrp_msg_value_t *v; + void *vptr; + uint32_t n, j; + int i; + DBusMessageIter im, ia; + uint16_t u16; + int16_t s16; + uint32_t bln; + + m = dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_CALL); + + if (m == NULL) + return NULL; + + descr = mrp_msg_find_type(tag); + + if (descr == NULL) + goto fail; + + fields = descr->fields; + nfield = descr->nfield; + + dbus_message_iter_init_append(m, &im); + + if (!dbus_message_iter_append_basic(&im, + DBUS_TYPE_OBJECT_PATH, &sender_id)) + goto fail; + + if (!dbus_message_iter_append_basic(&im, DBUS_TYPE_UINT16, &tag)) + goto fail; + + if (!dbus_message_iter_append_basic(&im, DBUS_TYPE_UINT16, &nfield)) + goto fail; + + for (i = 0, f = fields; i < nfield; i++, f++) { + if (!dbus_message_iter_append_basic(&im, DBUS_TYPE_UINT16, &f->tag) || + !dbus_message_iter_append_basic(&im, DBUS_TYPE_UINT16, &f->type)) + goto fail; + + v = (mrp_msg_value_t *)(data + f->offs); + + switch (f->type) { + BASIC_SIMPLE(STRING, STRING , v->str); + BASIC_QUIRKY(BOOL , BOOLEAN, v->bln, bln); + BASIC_QUIRKY(UINT8 , UINT16 , v->u8 , u16); + BASIC_QUIRKY(SINT8 , INT16 , v->s8 , s16); + BASIC_SIMPLE(UINT16, UINT16 , v->u16); + BASIC_SIMPLE(SINT16, INT16 , v->s16); + BASIC_SIMPLE(UINT32, UINT32 , v->u32); + BASIC_SIMPLE(SINT32, INT32 , v->s32); + BASIC_SIMPLE(UINT64, UINT64 , v->u64); + BASIC_SIMPLE(SINT64, INT64 , v->s64); + BASIC_SIMPLE(DOUBLE, DOUBLE , v->dbl); + + default: + if (!(f->type & MRP_MSG_FIELD_ARRAY)) + goto fail; + + base = f->type & ~(MRP_MSG_FIELD_ARRAY); + n = mrp_data_get_array_size(data, descr, i); + + if (!dbus_message_iter_append_basic(&im, DBUS_TYPE_UINT32, &n)) + goto fail; + + if (!dbus_message_iter_open_container(&im, DBUS_TYPE_ARRAY, + get_array_signature(base), + &ia)) + goto fail; + + for (j = 0; j < n; j++) { + switch (base) { + ARRAY_SIMPLE(STRING, STRING , v->astr[j]); + ARRAY_QUIRKY(BOOL , BOOLEAN, v->abln[j], bln); + ARRAY_QUIRKY(UINT8 , UINT16 , v->au8[j] , u16); + ARRAY_QUIRKY(SINT8 , INT16 , v->as8[j] , s16); + ARRAY_SIMPLE(UINT16, UINT16 , v->au16[j]); + ARRAY_SIMPLE(SINT16, INT16 , v->as16[j]); + ARRAY_SIMPLE(UINT32, UINT32 , v->au32[j]); + ARRAY_SIMPLE(SINT32, INT32 , v->as32[j]); + ARRAY_SIMPLE(UINT64, UINT64 , v->au64[j]); + ARRAY_SIMPLE(DOUBLE, DOUBLE , v->adbl[j]); + + case MRP_MSG_FIELD_BLOB: + goto fail; + + default: + goto fail; + } + } + + if (!dbus_message_iter_close_container(&im, &ia)) + goto fail; + } + } + + return m; + + fail: + if (m != NULL) + dbus_message_unref(m); + + errno = ECOMM; + + return NULL; + +#undef BASIC_SIMPLE +#undef BASIC_QUIRKY +#undef ARRAY_SIMPLE +#undef ARRAY_QUIRKY +} + + +static mrp_data_member_t *member_type(mrp_data_member_t *fields, int nfield, + uint16_t tag) +{ + mrp_data_member_t *f; + int i; + + for (i = 0, f = fields; i < nfield; i++, f++) + if (f->tag == tag) + return f; + + return NULL; +} + + +static void *data_decode(DBusMessage *m, uint16_t *tagp, const char **sender_id) +{ +#define HANDLE_SIMPLE(_i, _mtype, _dtype, _var) \ + case MRP_MSG_FIELD_##_mtype: \ + if (dbus_message_iter_get_arg_type(_i) != DBUS_TYPE_##_dtype) \ + goto fail; \ + dbus_message_iter_get_basic(_i, &(_var)); \ + dbus_message_iter_next(_i); \ + break + +#define HANDLE_QUIRKY(_i, _mtype, _dtype, _mvar, _dvar) \ + case MRP_MSG_FIELD_##_mtype: \ + if (dbus_message_iter_get_arg_type(_i) != DBUS_TYPE_##_dtype) \ + goto fail; \ + dbus_message_iter_get_basic(_i, &(_dvar)); \ + dbus_message_iter_next(_i); \ + \ + _mvar = _dvar; \ + break + + void *data; + mrp_data_descr_t *descr; + mrp_data_member_t *fields, *f; + int nfield; + uint16_t tag, type, base; + mrp_msg_value_t *v; + uint32_t n, j, size; + int i; + DBusMessageIter im, ia; + const char *sender; + uint32_t u32; + uint16_t u16; + int16_t s16; + + data = NULL; + + if (!dbus_message_iter_init(m, &im)) + goto fail; + + if (dbus_message_iter_get_arg_type(&im) != DBUS_TYPE_OBJECT_PATH) + goto fail; + + dbus_message_iter_get_basic(&im, &sender); + dbus_message_iter_next(&im); + + if (dbus_message_iter_get_arg_type(&im) != DBUS_TYPE_UINT16) + goto fail; + + dbus_message_iter_get_basic(&im, &tag); + dbus_message_iter_next(&im); + + descr = mrp_msg_find_type(tag); + + if (descr == NULL) + goto fail; + + *tagp = tag; + + if (dbus_message_iter_get_arg_type(&im) != DBUS_TYPE_UINT16) + goto fail; + + dbus_message_iter_get_basic(&im, &nfield); + dbus_message_iter_next(&im); + + if (nfield != descr->nfield) + goto fail; + + fields = descr->fields; + data = mrp_allocz(descr->size); + + if (MRP_UNLIKELY(data == NULL)) + goto fail; + + for (i = 0; i < nfield; i++) { + if (dbus_message_iter_get_arg_type(&im) != DBUS_TYPE_UINT16) + goto fail; + + dbus_message_iter_get_basic(&im, &tag); + dbus_message_iter_next(&im); + + if (dbus_message_iter_get_arg_type(&im) != DBUS_TYPE_UINT16) + goto fail; + + dbus_message_iter_get_basic(&im, &type); + dbus_message_iter_next(&im); + + f = member_type(fields, nfield, tag); + + if (MRP_UNLIKELY(f == NULL)) + goto fail; + + v = (mrp_msg_value_t *)(data + f->offs); + + switch (type) { + HANDLE_SIMPLE(&im, STRING, STRING , v->str); + HANDLE_QUIRKY(&im, BOOL , BOOLEAN, v->bln, u32); + HANDLE_QUIRKY(&im, UINT8 , UINT16 , v->u8 , u16); + HANDLE_QUIRKY(&im, SINT8 , INT16 , v->s8 , s16); + HANDLE_SIMPLE(&im, UINT16, UINT16 , v->u16); + HANDLE_SIMPLE(&im, SINT16, INT16 , v->s16); + HANDLE_SIMPLE(&im, UINT32, UINT32 , v->u32); + HANDLE_SIMPLE(&im, SINT32, INT32 , v->s32); + HANDLE_SIMPLE(&im, UINT64, UINT64 , v->u64); + HANDLE_SIMPLE(&im, SINT64, INT64 , v->s64); + HANDLE_SIMPLE(&im, DOUBLE, DOUBLE , v->dbl); + + default: + if (!(f->type & MRP_MSG_FIELD_ARRAY)) + goto fail; + + base = type & ~(MRP_MSG_FIELD_ARRAY); + + if (dbus_message_iter_get_arg_type(&im) != DBUS_TYPE_UINT32) + goto fail; + + dbus_message_iter_get_basic(&im, &n); + dbus_message_iter_next(&im); + + if (dbus_message_iter_get_arg_type(&im) != DBUS_TYPE_ARRAY) + goto fail; + + dbus_message_iter_recurse(&im, &ia); + dbus_message_iter_next(&im); + + size = n; + + switch (base) { + case MRP_MSG_FIELD_STRING: size *= sizeof(*v->astr); break; + case MRP_MSG_FIELD_BOOL: size *= sizeof(*v->abln); break; + case MRP_MSG_FIELD_UINT8: size *= sizeof(*v->au8); break; + case MRP_MSG_FIELD_SINT8: size *= sizeof(*v->as8); break; + case MRP_MSG_FIELD_UINT16: size *= sizeof(*v->au16); break; + case MRP_MSG_FIELD_SINT16: size *= sizeof(*v->as16); break; + case MRP_MSG_FIELD_UINT32: size *= sizeof(*v->au32); break; + case MRP_MSG_FIELD_SINT32: size *= sizeof(*v->as32); break; + case MRP_MSG_FIELD_UINT64: size *= sizeof(*v->au64); break; + case MRP_MSG_FIELD_SINT64: size *= sizeof(*v->as64); break; + case MRP_MSG_FIELD_DOUBLE: size *= sizeof(*v->adbl); break; + default: + goto fail; + } + + v->aany = mrp_allocz(size); + if (v->aany == NULL) + goto fail; + + for (j = 0; j < n; j++) { + uint32_t dbln[n]; + uint16_t au16[n]; + int16_t as16[n]; + + switch (base) { + HANDLE_SIMPLE(&ia, STRING, STRING , v->astr[j]); + HANDLE_QUIRKY(&ia, BOOL , BOOLEAN, v->abln[j], dbln[j]); + HANDLE_QUIRKY(&ia, UINT8 , UINT16 , v->au8[j] , au16[j]); + HANDLE_QUIRKY(&ia, SINT8 , INT16 , v->as8[j] , as16[j]); + HANDLE_SIMPLE(&ia, UINT16, UINT16 , v->au16[j]); + HANDLE_SIMPLE(&ia, SINT16, INT16 , v->as16[j]); + HANDLE_SIMPLE(&ia, UINT32, UINT32 , v->au32[j]); + HANDLE_SIMPLE(&ia, SINT32, INT32 , v->as32[j]); + HANDLE_SIMPLE(&ia, UINT64, UINT64 , v->au64[j]); + HANDLE_SIMPLE(&ia, SINT64, INT64 , v->as64[j]); + HANDLE_SIMPLE(&ia, DOUBLE, DOUBLE , v->adbl[j]); + } + + if (base == MRP_MSG_FIELD_STRING) { + v->astr[j] = mrp_strdup(v->astr[j]); + if (v->astr[j] == NULL) + goto fail; + } + } + } + + if (f->type == MRP_MSG_FIELD_STRING) { + v->str = mrp_strdup(v->str); + if (v->str == NULL) + goto fail; + } + } + + if (sender_id != NULL) + *sender_id = sender; + + return data; + + fail: + mrp_data_free(data, tag); + errno = EBADMSG; + + return NULL; +} + + + + +MRP_REGISTER_TRANSPORT(dbus, DBUS, dbus_t, dbus_resolve, + dbus_open, dbus_createfrom, dbus_close, + dbus_bind, NULL, NULL, + dbus_connect, dbus_disconnect, + dbus_sendmsg, dbus_sendmsgto, + dbus_sendraw, dbus_sendrawto, + dbus_senddata, dbus_senddatato); + diff --git a/src/common/dbus-transport.h b/src/common/dbus-transport.h new file mode 100644 index 0000000..95ebd06 --- /dev/null +++ b/src/common/dbus-transport.h @@ -0,0 +1,26 @@ +#ifndef __MURPHY_DBUS_TRANSPORT_H__ +#define __MURPHY_DBUS_TRANSPORT_H__ + +#include + +#define MRP_AF_DBUS 0xDB + +#define MRP_DBUSADDR_BASE \ + __SOCKADDR_COMMON(db_); \ + char *db_bus; /* D-BUS bus address */ \ + char *db_addr; /* address on bus */ \ + char *db_path /* instance path */ \ + +typedef struct { + MRP_DBUSADDR_BASE; +} _mrp_dbusaddr_base_t; + + +typedef struct { + MRP_DBUSADDR_BASE; + char db_fqa[MRP_SOCKADDR_SIZE - sizeof(_mrp_dbusaddr_base_t)]; +} mrp_dbusaddr_t; + + + +#endif /* __MURPHY_DBUS_TRANSPORT_H__ */ diff --git a/src/common/dbus.c b/src/common/dbus.c new file mode 100644 index 0000000..ecc5389 --- /dev/null +++ b/src/common/dbus.c @@ -0,0 +1,1316 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define DBUS_ADMIN_SERVICE "org.freedesktop.DBus" +#define DBUS_ADMIN_INTERFACE "org.freedesktop.DBus" +#define DBUS_ADMIN_PATH "/org/freedesktop/DBus" +#define DBUS_NAME_CHANGED "NameOwnerChanged" + + +struct mrp_dbus_s { + DBusConnection *conn; /* actual D-BUS connection */ + mrp_mainloop_t *ml; /* murphy mainloop */ + mrp_htbl_t *methods; /* method handler table */ + mrp_htbl_t *signals; /* signal handler table */ + mrp_list_hook_t name_trackers; /* peer (name) watchers */ + mrp_list_hook_t calls; /* pending calls */ + uint32_t call_id; /* next call id */ + const char *unique_name; /* our unique D-BUS address */ + int priv; /* whether a private connection */ + mrp_refcnt_t refcnt; /* reference count */ +}; + + +/* + * Notes: + * + * At the moment we administer DBUS method and signal handlers + * in a very primitive way (subject to be changed later). For + * every bus instance we maintain two hash tables, one for methods + * and another for signals. Each method and signal handler is + * hashed in only by it's method/signal name to a linked list of + * method or signal handlers. + * + * When dispatching a method, we look up the chain with a matching + * method name, or the chain for "" in case a matching chain is + * not found, and invoke the handler which best matches the + * received message (by looking at the path, interface and name). + * Only one such handler is invoked at most. + * + * For signals we look up both the chain with a matching name and + * the chain for "" and invoke all signal handlers that match the + * received message (regardless of their return value). + */ + +typedef struct { + char *member; + mrp_list_hook_t handlers; +} handler_list_t; + +typedef struct { + mrp_list_hook_t hook; + char *sender; + char *path; + char *interface; + char *member; + mrp_dbus_handler_t handler; + void *user_data; +} handler_t; + +#define method_t handler_t +#define signal_t handler_t + + +typedef struct { + mrp_list_hook_t hook; /* hook to name tracker list */ + char *name; /* name to track */ + mrp_dbus_name_cb_t cb; /* status change callback */ + void *user_data; /* opaque callback user data */ + int32_t qid; /* initial query ID */ +} name_tracker_t; + + +typedef struct { + mrp_dbus_t *dbus; /* DBUS connection */ + int32_t id; /* call id */ + mrp_dbus_reply_cb_t cb; /* completion notification callback */ + void *user_data; /* opaque callback data */ + DBusPendingCall *pend; /* pending DBUS call */ + mrp_list_hook_t hook; /* hook to list of pending calls */ +} call_t; + + +static DBusHandlerResult dispatch_signal(DBusConnection *c, + DBusMessage *msg, void *data); +static DBusHandlerResult dispatch_method(DBusConnection *c, + DBusMessage *msg, void *data); +static void purge_name_trackers(mrp_dbus_t *dbus); +static void purge_calls(mrp_dbus_t *dbus); +static void handler_list_free_cb(void *key, void *entry); +static void handler_free(handler_t *h); +static int name_owner_change_cb(mrp_dbus_t *dbus, DBusMessage *msg, void *data); +static void call_free(call_t *call); + + +static int purge_filters(void *key, void *entry, void *user_data) +{ + mrp_dbus_t *dbus = (mrp_dbus_t *)user_data; + handler_list_t *l = (handler_list_t *)entry; + mrp_list_hook_t *p, *n; + handler_t *h; + + (void)key; + + mrp_list_foreach(&l->handlers, p, n) { + h = mrp_list_entry(p, handler_t, hook); + mrp_dbus_remove_filter(dbus, + h->sender, h->path, h->interface, + h->member, NULL); + } + + return MRP_HTBL_ITER_MORE; +} + + +void dbus_disconnect(mrp_dbus_t *dbus) +{ + if (dbus) { + if (dbus->signals) { + mrp_htbl_foreach(dbus->signals, purge_filters, dbus); + mrp_htbl_destroy(dbus->signals, TRUE); + } + if (dbus->methods) + mrp_htbl_destroy(dbus->methods, TRUE); + + if (dbus->conn != NULL) { + dbus_connection_remove_filter(dbus->conn, dispatch_signal, dbus); + dbus_connection_unregister_object_path(dbus->conn, "/"); + if (dbus->priv) + dbus_connection_close(dbus->conn); + dbus_connection_unref(dbus->conn); + } + + purge_name_trackers(dbus); + purge_calls(dbus); + + dbus->conn = NULL; + dbus->ml = NULL; + + mrp_free(dbus); + } +} + + +mrp_dbus_t *mrp_dbus_connect(mrp_mainloop_t *ml, const char *address, + DBusError *errp) +{ + static struct DBusObjectPathVTable vtable = { + .message_function = dispatch_method + }; + + mrp_htbl_config_t hcfg; + mrp_dbus_t *dbus; + + if ((dbus = mrp_allocz(sizeof(*dbus))) == NULL) + return NULL; + + mrp_list_init(&dbus->calls); + mrp_list_init(&dbus->name_trackers); + mrp_refcnt_init(&dbus->refcnt); + + dbus->ml = ml; + + + mrp_dbus_error_init(errp); + + /* + * connect to the bus + */ + + if (!strcmp(address, "system")) + dbus->conn = dbus_bus_get(DBUS_BUS_SYSTEM, errp); + else if (!strcmp(address, "session")) + dbus->conn = dbus_bus_get(DBUS_BUS_SESSION, errp); + else { + dbus->conn = dbus_connection_open_private(address, errp); + dbus->priv = TRUE; + + if (dbus->conn == NULL || !dbus_bus_register(dbus->conn, errp)) + goto fail; + } + + if (dbus->conn == NULL) + goto fail; + + dbus->unique_name = dbus_bus_get_unique_name(dbus->conn); + + /* + * set up with mainloop + */ + + if (!mrp_dbus_setup_connection(ml, dbus->conn)) + goto fail; + + /* + * set up our message dispatchers and take our name on the bus + */ + + if (!dbus_connection_add_filter(dbus->conn, dispatch_signal, dbus, NULL)) { + dbus_set_error(errp, DBUS_ERROR_FAILED, + "Failed to set up signal dispatching."); + goto fail; + } + + if (!dbus_connection_register_fallback(dbus->conn, "/", &vtable, dbus)) { + dbus_set_error(errp, DBUS_ERROR_FAILED, + "Failed to set up method dispatching."); + goto fail; + } + + mrp_clear(&hcfg); + hcfg.comp = mrp_string_comp; + hcfg.hash = mrp_string_hash; + hcfg.free = handler_list_free_cb; + + if ((dbus->methods = mrp_htbl_create(&hcfg)) == NULL) { + dbus_set_error(errp, DBUS_ERROR_FAILED, + "Failed to create DBUS method table."); + goto fail; + } + + if ((dbus->signals = mrp_htbl_create(&hcfg)) == NULL) { + dbus_set_error(errp, DBUS_ERROR_FAILED, + "Failed to create DBUS signal table."); + goto fail; + } + + + /* + * install handler for NameOwnerChanged for tracking clients/peers + */ + + if (!mrp_dbus_add_signal_handler(dbus, DBUS_ADMIN_SERVICE, DBUS_ADMIN_PATH, + DBUS_ADMIN_SERVICE, DBUS_NAME_CHANGED, + name_owner_change_cb, NULL)) { + dbus_set_error(errp, DBUS_ERROR_FAILED, + "Failed to install NameOwnerChanged handler."); + goto fail; + } + + /* install a 'safe' filter to avoid receiving all name change signals */ + mrp_dbus_install_filter(dbus, + DBUS_ADMIN_SERVICE, DBUS_ADMIN_PATH, + DBUS_ADMIN_SERVICE, DBUS_NAME_CHANGED, + DBUS_ADMIN_SERVICE, NULL); + + mrp_list_init(&dbus->name_trackers); + dbus->call_id = 1; + + return dbus; + + fail: + dbus_disconnect(dbus); + return NULL; +} + + +mrp_dbus_t *mrp_dbus_ref(mrp_dbus_t *dbus) +{ + return mrp_ref_obj(dbus, refcnt); +} + + +int mrp_dbus_unref(mrp_dbus_t *dbus) +{ + if (mrp_unref_obj(dbus, refcnt)) { + dbus_disconnect(dbus); + + return TRUE; + } + else + return FALSE; +} + + +int mrp_dbus_acquire_name(mrp_dbus_t *dbus, const char *name, DBusError *error) +{ + int flags, status; + + mrp_dbus_error_init(error); + + flags = DBUS_NAME_FLAG_REPLACE_EXISTING | DBUS_NAME_FLAG_DO_NOT_QUEUE; + status = dbus_bus_request_name(dbus->conn, name, flags, error); + + if (status == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) + return TRUE; + else { + if (status == DBUS_REQUEST_NAME_REPLY_EXISTS) { + dbus_error_free(error); + dbus_set_error(error, DBUS_ERROR_FAILED, "name already taken"); + } + return FALSE; + } +} + + +int mrp_dbus_release_name(mrp_dbus_t *dbus, const char *name, DBusError *error) +{ + mrp_dbus_error_init(error); + + if (dbus_bus_release_name(dbus->conn, name, error) != -1) + return TRUE; + else + return FALSE; +} + + +const char *mrp_dbus_get_unique_name(mrp_dbus_t *dbus) +{ + return dbus->unique_name; +} + +static void name_owner_query_cb(mrp_dbus_t *dbus, DBusMessage *msg, void *data) +{ + name_tracker_t *t = (name_tracker_t *)data; + int state; + + if (t->cb != NULL) { /* tracker still active */ + t->qid = 0; + state = dbus_message_get_type(msg) == DBUS_MESSAGE_TYPE_METHOD_RETURN; + t->cb(dbus, t->name, state, t->user_data); + } + else /* already requested to delete */ + mrp_free(t); +} + + +static int name_owner_change_cb(mrp_dbus_t *dbus, DBusMessage *msg, void *data) +{ + const char *name, *prev, *next; + mrp_list_hook_t *p, *n; + name_tracker_t *t; + + (void)data; + + if (dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_SIGNAL) + return FALSE; + + if (!dbus_message_get_args(msg, NULL, + DBUS_TYPE_STRING, &name, + DBUS_TYPE_STRING, &prev, + DBUS_TYPE_STRING, &next, + DBUS_TYPE_INVALID)) + return FALSE; + + /* + * Notes: XXX TODO + * In principle t->cb could call mrp_dbus_forget for some other D-BUS + * address than name. If that happened to be n (== p->hook.next) this + * would result in a crash or memory corruption in the next iteration + * of this loop (when handling n). We can easily get around this + * problem by + * + * 1) adminstering in mrp_dbus_t that we're handing a NameOwnerChange + * 2) checking for this in mrp_dbus_forget_name and if it is the case + * only marking the affected entry for deletion + * 3) removing entries marked for deletion in this loop (or just + * ignoring them and making another pass in the end removing any + * such entry). + */ + + mrp_list_foreach(&dbus->name_trackers, p, n) { + t = mrp_list_entry(p, name_tracker_t, hook); + + if (!strcmp(name, t->name)) + t->cb(dbus, name, next && *next, t->user_data); + } + + return TRUE; +} + + +int mrp_dbus_follow_name(mrp_dbus_t *dbus, const char *name, + mrp_dbus_name_cb_t cb, void *user_data) +{ + name_tracker_t *t; + + if ((t = mrp_allocz(sizeof(*t))) != NULL) { + if ((t->name = mrp_strdup(name)) != NULL) { + t->cb = cb; + t->user_data = user_data; + + if (mrp_dbus_install_filter(dbus, + DBUS_ADMIN_SERVICE, DBUS_ADMIN_PATH, + DBUS_ADMIN_SERVICE, DBUS_NAME_CHANGED, + name, NULL)) { + mrp_list_append(&dbus->name_trackers, &t->hook); + + t->qid = mrp_dbus_call(dbus, + DBUS_ADMIN_SERVICE, DBUS_ADMIN_PATH, + DBUS_ADMIN_SERVICE, "GetNameOwner", 5000, + name_owner_query_cb, t, + DBUS_TYPE_STRING, &t->name, + DBUS_TYPE_INVALID); + return TRUE; + } + else { + mrp_free(t->name); + mrp_free(t); + } + } + } + + return FALSE; +} + + +int mrp_dbus_forget_name(mrp_dbus_t *dbus, const char *name, + mrp_dbus_name_cb_t cb, void *user_data) +{ + mrp_list_hook_t *p, *n; + name_tracker_t *t; + + mrp_dbus_remove_filter(dbus, + DBUS_ADMIN_SERVICE, DBUS_ADMIN_PATH, + DBUS_ADMIN_SERVICE, DBUS_NAME_CHANGED, + name, NULL); + + mrp_list_foreach(&dbus->name_trackers, p, n) { + t = mrp_list_entry(p, name_tracker_t, hook); + + if (t->cb == cb && t->user_data == user_data && !strcmp(t->name,name)) { + mrp_list_delete(&t->hook); + mrp_free(t->name); + + if (!t->qid) + mrp_free(t); + else { + t->cb = NULL; + t->user_data = NULL; + t->name = NULL; + } + + return TRUE; + } + } + + return FALSE; +} + + +static void purge_name_trackers(mrp_dbus_t *dbus) +{ + mrp_list_hook_t *p, *n; + name_tracker_t *t; + + mrp_list_foreach(&dbus->name_trackers, p, n) { + t = mrp_list_entry(p, name_tracker_t, hook); + + mrp_list_delete(p); + mrp_dbus_remove_filter(dbus, DBUS_ADMIN_SERVICE, DBUS_ADMIN_PATH, + DBUS_ADMIN_SERVICE, DBUS_NAME_CHANGED, + t->name, NULL); + mrp_free(t->name); + mrp_free(t); + } +} + + +static handler_t *handler_alloc(const char *sender, const char *path, + const char *interface, const char *member, + mrp_dbus_handler_t handler, void *user_data) +{ + handler_t *h; + + if ((h = mrp_allocz(sizeof(*h))) != NULL) { + h->sender = mrp_strdup(sender); + h->path = mrp_strdup(path); + h->interface = mrp_strdup(interface); + h->member = mrp_strdup(member); + + if (!h->path || !h->interface || !h->member) { + handler_free(h); + return NULL; + } + + h->handler = handler; + h->user_data = user_data; + + return h; + } + + return NULL; +} + + +static void handler_free(handler_t *h) +{ + if (h != NULL) { + mrp_free(h->sender); + mrp_free(h->path); + mrp_free(h->interface); + mrp_free(h->member); + + mrp_free(h); + } +} + + +static handler_list_t *handler_list_alloc(const char *member) +{ + handler_list_t *l; + + if ((l = mrp_allocz(sizeof(*l))) != NULL) { + if ((l->member = mrp_strdup(member)) != NULL) + mrp_list_init(&l->handlers); + else { + mrp_free(l); + l = NULL; + } + } + + return l; +} + + +static inline void handler_list_free(handler_list_t *l) +{ + mrp_list_hook_t *p, *n; + handler_t *h; + + mrp_list_foreach(&l->handlers, p, n) { + h = mrp_list_entry(p, handler_t, hook); + mrp_list_delete(p); + handler_free(h); + } + + mrp_free(l->member); + mrp_free(l); +} + + +static void handler_list_free_cb(void *key, void *entry) +{ + (void)key; + + handler_list_free((handler_list_t *)entry); +} + + +static inline int handler_specificity(handler_t *h) +{ + int score = 0; + + if (h->path && *h->path) + score |= 0x4; + if (h->interface && *h->interface) + score |= 0x2; + if (h->member && *h->member) + score |= 0x1; + + return score; +} + + +static void handler_list_insert(handler_list_t *l, handler_t *handler) +{ + mrp_list_hook_t *p, *n; + handler_t *h; + int score; + + score = handler_specificity(handler); + + mrp_list_foreach(&l->handlers, p, n) { + h = mrp_list_entry(p, handler_t, hook); + + if (score >= handler_specificity(h)) { + mrp_list_append(h->hook.prev, &handler->hook); /* add before h */ + return; + } + } + + mrp_list_append(&l->handlers, &handler->hook); +} + + +static handler_t *handler_list_lookup(handler_list_t *l, const char *path, + const char *interface, const char *member, + mrp_dbus_handler_t handler, + void *user_data) +{ + mrp_list_hook_t *p, *n; + handler_t *h; + + mrp_list_foreach(&l->handlers, p, n) { + h = mrp_list_entry(p, handler_t, hook); + + if (h->handler == handler && user_data == h->user_data && + path && !strcmp(path, h->path) && + interface && !strcmp(interface, h->interface) && + member && !strcmp(member, h->member)) + return h; + } + + return NULL; +} + + +static handler_t *handler_list_find(handler_list_t *l, const char *path, + const char *interface, const char *member) +{ +#define MATCHES(h, field) (!*field || !*h->field || !strcmp(field, h->field)) + mrp_list_hook_t *p, *n; + handler_t *h; + + mrp_list_foreach(&l->handlers, p, n) { + h = mrp_list_entry(p, handler_t, hook); + + if (MATCHES(h, path) && MATCHES(h, interface) && MATCHES(h, member)) + return h; + } + + return NULL; +#undef MATCHES +} + + +int mrp_dbus_export_method(mrp_dbus_t *dbus, const char *path, + const char *interface, const char *member, + mrp_dbus_handler_t handler, void *user_data) +{ + handler_list_t *methods; + handler_t *m; + + if ((methods = mrp_htbl_lookup(dbus->methods, (void *)member)) == NULL) { + if ((methods = handler_list_alloc(member)) == NULL) + return FALSE; + + mrp_htbl_insert(dbus->methods, methods->member, methods); + } + + m = handler_alloc(NULL, path, interface, member, handler, user_data); + if (m != NULL) { + handler_list_insert(methods, m); + return TRUE; + } + else + return FALSE; +} + + +int mrp_dbus_remove_method(mrp_dbus_t *dbus, const char *path, + const char *interface, const char *member, + mrp_dbus_handler_t handler, void *user_data) +{ + handler_list_t *methods; + handler_t *m; + + if ((methods = mrp_htbl_lookup(dbus->methods, (void *)member)) == NULL) + return FALSE; + + m = handler_list_lookup(methods, path, interface, member, + handler, user_data); + if (m != NULL) { + mrp_list_delete(&m->hook); + handler_free(m); + + return TRUE; + } + else + return FALSE; +} + + +int mrp_dbus_add_signal_handler(mrp_dbus_t *dbus, const char *sender, + const char *path, const char *interface, + const char *member, mrp_dbus_handler_t handler, + void *user_data) +{ + handler_list_t *signals; + handler_t *s; + + if ((signals = mrp_htbl_lookup(dbus->signals, (void *)member)) == NULL) { + if ((signals = handler_list_alloc(member)) == NULL) + return FALSE; + + if (!mrp_htbl_insert(dbus->signals, signals->member, signals)) { + handler_list_free(signals); + return FALSE; + } + } + + s = handler_alloc(sender, path, interface, member, handler, user_data); + if (s != NULL) { + handler_list_insert(signals, s); + return TRUE; + } + else { + handler_free(s); + if (mrp_list_empty(&signals->handlers)) + mrp_htbl_remove(dbus->signals, signals->member, TRUE); + return FALSE; + } +} + + + +int mrp_dbus_del_signal_handler(mrp_dbus_t *dbus, const char *sender, + const char *path, const char *interface, + const char *member, mrp_dbus_handler_t handler, + void *user_data) +{ + handler_list_t *signals; + handler_t *s; + + (void)sender; + + if ((signals = mrp_htbl_lookup(dbus->signals, (void *)member)) == NULL) + return FALSE; + + s = handler_list_lookup(signals, path, interface, member, + handler, user_data); + if (s != NULL) { + mrp_list_delete(&s->hook); + handler_free(s); + + if (mrp_list_empty(&signals->handlers)) + mrp_htbl_remove(dbus->signals, (void *)member, TRUE); + + return TRUE; + } + else + return FALSE; +} + + + +int mrp_dbus_subscribe_signal(mrp_dbus_t *dbus, + mrp_dbus_handler_t handler, void *user_data, + const char *sender, const char *path, + const char *interface, const char *member, ...) +{ + va_list ap; + int success; + + + if (mrp_dbus_add_signal_handler(dbus, sender, path, interface, member, + handler, user_data)) { + va_start(ap, member); + success = mrp_dbus_install_filterv(dbus, + sender, path, interface, member, ap); + va_end(ap); + + if (success) + return TRUE; + else + mrp_dbus_del_signal_handler(dbus, sender, path, interface, member, + handler, user_data); + } + + return FALSE; +} + + +int mrp_dbus_unsubscribe_signal(mrp_dbus_t *dbus, + mrp_dbus_handler_t handler, void *user_data, + const char *sender, const char *path, + const char *interface, const char *member, ...) +{ + va_list ap; + int status; + + status = mrp_dbus_del_signal_handler(dbus, sender, path, interface, member, + handler, user_data); + va_start(ap, member); + status &= mrp_dbus_remove_filterv(dbus, + sender, path, interface, member, ap); + va_end(ap); + + return status; +} + + +int mrp_dbus_install_filterv(mrp_dbus_t *dbus, const char *sender, + const char *path, const char *interface, + const char *member, va_list args) +{ +#define ADD_TAG(tag, value) do { \ + if (value != NULL) { \ + l = snprintf(p, n, "%s%s='%s'", p == filter ? "" : ",", \ + tag, value); \ + if (l >= n) \ + return FALSE; \ + n -= l; \ + p += l; \ + } \ + } while (0) + + va_list ap; + DBusError error; + char filter[1024], *p, argn[16], *val; + int n, l, i; + + p = filter; + n = sizeof(filter); + + ADD_TAG("type" , "signal"); + ADD_TAG("sender" , sender); + ADD_TAG("path" , path); + ADD_TAG("interface", interface); + ADD_TAG("member" , member); + + va_copy(ap, args); + i = 0; + while ((val = va_arg(ap, char *)) != NULL) { + snprintf(argn, sizeof(argn), "arg%d", i); + ADD_TAG(argn, val); + i++; + } + va_end(ap); + + dbus_error_init(&error); + dbus_bus_add_match(dbus->conn, filter, &error); + + if (dbus_error_is_set(&error)) { + mrp_log_error("Failed to install filter '%s' (error: %s).", filter, + mrp_dbus_errmsg(&error)); + dbus_error_free(&error); + + return FALSE; + } + else + return TRUE; + +} + + +int mrp_dbus_install_filter(mrp_dbus_t *dbus, const char *sender, + const char *path, const char *interface, + const char *member, ...) +{ + va_list ap; + int status; + + va_start(ap, member); + status = mrp_dbus_install_filterv(dbus, + sender, path, interface, member, ap); + va_end(ap); + + return status; +} + + +int mrp_dbus_remove_filterv(mrp_dbus_t *dbus, const char *sender, + const char *path, const char *interface, + const char *member, va_list args) +{ + va_list ap; + char filter[1024], *p, argn[16], *val; + int n, l, i; + + p = filter; + n = sizeof(filter); + + ADD_TAG("type" , "signal"); + ADD_TAG("sender" , sender); + ADD_TAG("path" , path); + ADD_TAG("interface", interface); + ADD_TAG("member" , member); + + va_copy(ap, args); + i = 0; + while ((val = va_arg(ap, char *)) != NULL) { + snprintf(argn, sizeof(argn), "arg%d", i); + ADD_TAG(argn, val); + i++; + } + va_end(ap); + + dbus_bus_remove_match(dbus->conn, filter, NULL); + return TRUE; +#undef ADD_TAG +} + + +int mrp_dbus_remove_filter(mrp_dbus_t *dbus, const char *sender, + const char *path, const char *interface, + const char *member, ...) +{ + va_list ap; + int status; + + va_start(ap, member); + status = mrp_dbus_remove_filterv(dbus, sender, path, interface, member, ap); + va_end(ap); + + return status; +} + + + +static DBusHandlerResult dispatch_method(DBusConnection *c, + DBusMessage *msg, void *data) +{ +#define SAFESTR(str) (str ? str : "") + const char *path = dbus_message_get_path(msg); + const char *interface = dbus_message_get_interface(msg); + const char *member = dbus_message_get_member(msg); + + mrp_dbus_t *dbus = (mrp_dbus_t *)data; + handler_list_t *l; + handler_t *h; + + (void)c; + + if (dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_METHOD_CALL || !member) + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + +#if 0 + mrp_debug("path='%s', interface='%s', member='%s')..." + SAFESTR(path), SAFESTR(interface), SAFESTR(member)); +#endif + + if ((l = mrp_htbl_lookup(dbus->methods, (void *)member)) != NULL) { + retry: + if ((h = handler_list_find(l, path, interface, member)) != NULL) { + if (h->handler(dbus, msg, h->user_data)) + return DBUS_HANDLER_RESULT_HANDLED; + else + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } + } + else { + if ((l = mrp_htbl_lookup(dbus->methods, "")) != NULL) + goto retry; + } + + mrp_log_info("Unhandled method path=%s, %s.%s.", SAFESTR(path), + SAFESTR(interface), SAFESTR(member)); + + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + + +static DBusHandlerResult dispatch_signal(DBusConnection *c, + DBusMessage *msg, void *data) +{ +#define MATCHES(h, field) (!*field || !*h->field || !strcmp(field, h->field)) + const char *path = dbus_message_get_path(msg); + const char *interface = dbus_message_get_interface(msg); + const char *member = dbus_message_get_member(msg); + + mrp_dbus_t *dbus = (mrp_dbus_t *)data; + mrp_list_hook_t *p, *n; + handler_list_t *l; + handler_t *h; + int retried = FALSE; + int handled = FALSE; + + (void)c; + + if (dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_SIGNAL || !member) + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + +#if 0 + mrp_log_info("%s(path='%s', interface='%s', member='%s')...", + __FUNCTION__, + SAFESTR(path), SAFESTR(interface), SAFESTR(member)); +#endif + + if ((l = mrp_htbl_lookup(dbus->signals, (void *)member)) != NULL) { + retry: + mrp_list_foreach(&l->handlers, p, n) { + h = mrp_list_entry(p, handler_t, hook); + + if (MATCHES(h,path) && MATCHES(h,interface) && MATCHES(h,member)) { + h->handler(dbus, msg, h->user_data); + handled = TRUE; + } + } + } + + if (!retried) { + if ((l = mrp_htbl_lookup(dbus->signals, "")) != NULL) { + retried = TRUE; + goto retry; + } + } + + if (!handled) + mrp_log_info("Unhandled signal path=%s, %s.%s.", SAFESTR(path), + SAFESTR(interface), SAFESTR(member)); + + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +#undef MATCHES +#undef SAFESTR +} + + +static void call_reply_cb(DBusPendingCall *pend, void *user_data) +{ + call_t *call = (call_t *)user_data; + DBusMessage *reply; + + reply = dbus_pending_call_steal_reply(pend); + + call->pend = NULL; + mrp_list_delete(&call->hook); + + call->cb(call->dbus, reply, call->user_data); + + dbus_message_unref(reply); + dbus_pending_call_unref(pend); + + call_free(call); +} + + +int32_t mrp_dbus_call(mrp_dbus_t *dbus, const char *dest, const char *path, + const char *interface, const char *member, int timeout, + mrp_dbus_reply_cb_t cb, void *user_data, int type, ...) +{ + va_list ap; + int32_t id; + call_t *call; + DBusMessage *msg; + DBusPendingCall *pend; + int success; + + call = NULL; + pend = NULL; + + msg = dbus_message_new_method_call(dest, path, interface, member); + + if (msg == NULL) + return 0; + + if (cb != NULL) { + if ((call = mrp_allocz(sizeof(*call))) != NULL) { + mrp_list_init(&call->hook); + + call->dbus = dbus; + call->id = dbus->call_id++; + call->cb = cb; + call->user_data = user_data; + + id = call->id; + } + else + goto fail; + } + else + id = dbus->call_id++; + + if (type == DBUS_TYPE_INVALID) + success = TRUE; + else { + va_start(ap, type); + success = dbus_message_append_args_valist(msg, type, ap); + va_end(ap); + } + + if (!success) + goto fail; + + if (cb == NULL) { + dbus_message_set_no_reply(msg, TRUE); + if (!dbus_connection_send(dbus->conn, msg, NULL)) + goto fail; + } + else { + if (!dbus_connection_send_with_reply(dbus->conn, msg, &pend, timeout)) + goto fail; + + if (!dbus_pending_call_set_notify(pend, call_reply_cb, call, NULL)) + goto fail; + } + + if (cb != NULL) { + mrp_list_append(&dbus->calls, &call->hook); + call->pend = pend; + } + + dbus_message_unref(msg); + + return id; + + fail: + if (pend != NULL) + dbus_pending_call_unref(pend); + + if(msg != NULL) + dbus_message_unref(msg); + + call_free(call); + + return 0; +} + + +int32_t mrp_dbus_send(mrp_dbus_t *dbus, const char *dest, const char *path, + const char *interface, const char *member, int timeout, + mrp_dbus_reply_cb_t cb, void *user_data, DBusMessage *msg) +{ + int32_t id; + call_t *call; + DBusPendingCall *pend; + int method; + + call = NULL; + pend = NULL; + + if (dbus_message_get_type(msg) == DBUS_MESSAGE_TYPE_SIGNAL) { + if (cb != NULL) + goto fail; + else + method = FALSE; + } + else + method = TRUE; + + if (cb != NULL) { + if ((call = mrp_allocz(sizeof(*call))) != NULL) { + mrp_list_init(&call->hook); + + call->dbus = dbus; + call->id = dbus->call_id++; + call->cb = cb; + call->user_data = user_data; + + id = call->id; + } + else + goto fail; + } + else + id = dbus->call_id++; + + if (!dbus_message_set_destination(msg, dest)) + goto fail; + if (!dbus_message_set_path(msg, path)) + goto fail; + if (!dbus_message_set_interface(msg, interface)) + goto fail; + if (!dbus_message_set_member(msg, member)) + goto fail; + + if (cb == NULL) { + if (method) + dbus_message_set_no_reply(msg, TRUE); + if (!dbus_connection_send(dbus->conn, msg, NULL)) + goto fail; + } + else { + if (!dbus_connection_send_with_reply(dbus->conn, msg, &pend, timeout)) + goto fail; + + if (!dbus_pending_call_set_notify(pend, call_reply_cb, call, NULL)) + goto fail; + } + + if (cb != NULL) { + mrp_list_append(&dbus->calls, &call->hook); + call->pend = pend; + } + + dbus_message_unref(msg); + + return id; + + fail: + if (pend != NULL) + dbus_pending_call_unref(pend); + + if(msg != NULL) + dbus_message_unref(msg); + + call_free(call); + + return 0; +} + + +int mrp_dbus_send_msg(mrp_dbus_t *dbus, DBusMessage *msg) +{ + return dbus_connection_send(dbus->conn, msg, NULL); +} + + +int mrp_dbus_call_cancel(mrp_dbus_t *dbus, int32_t id) +{ + mrp_list_hook_t *p, *n; + call_t *call; + + mrp_list_foreach(&dbus->calls, p, n) { + call = mrp_list_entry(p, call_t, hook); + + if (call->id == id) { + mrp_list_delete(p); + + dbus_pending_call_cancel(call->pend); + dbus_pending_call_unref(call->pend); + call->pend = NULL; + + call_free(call); + return TRUE; + } + } + + return FALSE; +} + + +int mrp_dbus_reply(mrp_dbus_t *dbus, DBusMessage *msg, int type, ...) +{ + va_list ap; + DBusMessage *rpl; + int success; + + rpl = dbus_message_new_method_return(msg); + + if (rpl == NULL) + return FALSE; + + if (type == DBUS_TYPE_INVALID) + success = TRUE; + else { + va_start(ap, type); + success = dbus_message_append_args_valist(rpl, type, ap); + va_end(ap); + } + + if (!success) + goto fail; + + if (!dbus_connection_send(dbus->conn, rpl, NULL)) + goto fail; + + dbus_message_unref(rpl); + + return TRUE; + + fail: + if(rpl != NULL) + dbus_message_unref(rpl); + + return FALSE; +} + + +static void call_free(call_t *call) +{ + if (call != NULL) + mrp_free(call); +} + + +static void purge_calls(mrp_dbus_t *dbus) +{ + mrp_list_hook_t *p, *n; + call_t *call; + + mrp_list_foreach(&dbus->calls, p, n) { + call = mrp_list_entry(p, call_t, hook); + + mrp_list_delete(&call->hook); + + if (call->pend != NULL) + dbus_pending_call_unref(call->pend); + + mrp_free(call); + } +} + + +int mrp_dbus_signal(mrp_dbus_t *dbus, const char *dest, const char *path, + const char *interface, const char *member, int type, ...) +{ + va_list ap; + DBusMessage *msg; + int success; + + msg = dbus_message_new_signal(path, interface, member); + + if (msg == NULL) + return 0; + + if (type == DBUS_TYPE_INVALID) + success = TRUE; + else { + va_start(ap, type); + success = dbus_message_append_args_valist(msg, type, ap); + va_end(ap); + } + + if (!success) + goto fail; + + if (dest && *dest && !dbus_message_set_destination(msg, dest)) + goto fail; + + if (!dbus_connection_send(dbus->conn, msg, NULL)) + goto fail; + + dbus_message_unref(msg); + + return TRUE; + + fail: + /* + * XXX TODO: Hmm... IIRC, libdbus unrefs messages upon failure. If it + * was really so, this would corrupt/crash. Check this from + * libdbus code. + */ + if(msg != NULL) + dbus_message_unref(msg); + + return 0; +} diff --git a/src/common/dbus.h b/src/common/dbus.h new file mode 100644 index 0000000..92ce917 --- /dev/null +++ b/src/common/dbus.h @@ -0,0 +1,141 @@ +#ifndef __MURPHY_DBUS_H__ +#define __MURPHY_DBUS_H__ + +#include + +#define MRP_AF_DBUS 0xDB + +/** Our D-BUS (connection) abstraction. */ +struct mrp_dbus_s; +typedef struct mrp_dbus_s mrp_dbus_t; + +/** D-BUS method or signal callback type. */ +typedef int (*mrp_dbus_handler_t)(mrp_dbus_t *, DBusMessage *, void *); + +/** Create a new connection to the given bus. */ +mrp_dbus_t *mrp_dbus_connect(mrp_mainloop_t *ml, const char *address, + DBusError *errp); + +/** Set up a DBusConnection with a mainloop. */ +int mrp_dbus_setup_connection(mrp_mainloop_t *ml, DBusConnection *conn); + +/** Increase the reference count of the given DBus (connection). */ +mrp_dbus_t *mrp_dbus_ref(mrp_dbus_t *dbus); + +/** Decrease the reference count of the given DBus (connection). */ +int mrp_dbus_unref(mrp_dbus_t *dbus); + +/** Acquire the given name on the given bus (connection). */ +int mrp_dbus_acquire_name(mrp_dbus_t *dbus, const char *name, DBusError *error); + +/** Release the given name on the given bus (connection). */ +int mrp_dbus_release_name(mrp_dbus_t *dbus, const char *name, DBusError *error); + +typedef void (*mrp_dbus_name_cb_t)(mrp_dbus_t *, const char *, int, void *); +int mrp_dbus_follow_name(mrp_dbus_t *dbus, const char *name, + mrp_dbus_name_cb_t cb, void *user_data); +int mrp_dbus_forget_name(mrp_dbus_t *dbus, const char *name, + mrp_dbus_name_cb_t cb, void *user_data); + +int mrp_dbus_export_method(mrp_dbus_t *dbus, const char *path, + const char *interface, const char *member, + mrp_dbus_handler_t handler, void *user_data); + +int mrp_dbus_remove_method(mrp_dbus_t *dbus, const char *path, + const char *interface, const char *member, + mrp_dbus_handler_t handler, void *user_data); + +MRP_NULLTERM int mrp_dbus_subscribe_signal(mrp_dbus_t *dbus, + mrp_dbus_handler_t handler, + void *user_data, + const char *sender, + const char *path, + const char *interface, + const char *member, ...); + +MRP_NULLTERM int mrp_dbus_unsubscribe_signal(mrp_dbus_t *dbus, + mrp_dbus_handler_t handler, + void *user_data, + const char *sender, + const char *path, + const char *interface, + const char *member, ...); + +MRP_NULLTERM int mrp_dbus_install_filter(mrp_dbus_t *dbus, + const char *sender, + const char *path, + const char *interface, + const char *member, ...); +int mrp_dbus_install_filterv(mrp_dbus_t *dbus, + const char *sender, + const char *path, + const char *interface, + const char *member, + va_list ap); + +MRP_NULLTERM int mrp_dbus_remove_filter(mrp_dbus_t *dbus, + const char *sender, + const char *path, + const char *interface, + const char *member, ...); + +int mrp_dbus_remove_filterv(mrp_dbus_t *dbus, + const char *sender, + const char *path, + const char *interface, + const char *member, + va_list ap); + +int mrp_dbus_add_signal_handler(mrp_dbus_t *dbus, const char *sender, + const char *path, const char *interface, + const char *member, mrp_dbus_handler_t handler, + void *user_data); +int mrp_dbus_del_signal_handler(mrp_dbus_t *dbus, const char *sender, + const char *path, const char *interface, + const char *member, mrp_dbus_handler_t handler, + void *user_data); + +typedef void (*mrp_dbus_reply_cb_t)(mrp_dbus_t *dbus, DBusMessage *reply, + void *user_data); + +int32_t mrp_dbus_call(mrp_dbus_t *dbus, const char *dest, + const char *path, const char *interface, + const char *member, int timeout, + mrp_dbus_reply_cb_t cb, void *user_data, + int dbus_type, ...); +int mrp_dbus_call_cancel(mrp_dbus_t *dbus, int32_t id); + +int mrp_dbus_reply(mrp_dbus_t *dbus, DBusMessage *msg, int type, ...); + +int mrp_dbus_signal(mrp_dbus_t *dbus, const char *dest, const char *path, + const char *interface, const char *member, int type, ...); + +int32_t mrp_dbus_send(mrp_dbus_t *dbus, const char *dest, const char *path, + const char *interface, const char *member, int timeout, + mrp_dbus_reply_cb_t cb, void *user_data, + DBusMessage *msg); + +int mrp_dbus_send_msg(mrp_dbus_t *dbus, DBusMessage *msg); + +const char *mrp_dbus_get_unique_name(mrp_dbus_t *dbus); + +static inline void mrp_dbus_error_init(DBusError *error) +{ + /* + * Prevent libdbus error messages for NULL DBusError's... + */ + if (error != NULL) + dbus_error_init(error); +} + + +static inline const char *mrp_dbus_errmsg(DBusError *err) +{ + if (err && dbus_error_is_set(err)) + return err->message; + else + return "unknown DBUS error"; +} + + +#endif /* __MURPHY_DBUS_H__ */ diff --git a/src/common/tests/Makefile.am b/src/common/tests/Makefile.am index 702d299..378d177 100644 --- a/src/common/tests/Makefile.am +++ b/src/common/tests/Makefile.am @@ -1,6 +1,9 @@ AM_CFLAGS = $(WARNING_CFLAGS) -I$(top_builddir) -noinst_PROGRAMS = mm-test hash-test mainloop-test msg-test transport-test +noinst_PROGRAMS = mm-test hash-test msg-test transport-test +if DBUS_ENABLED +noinst_PROGRAMS += mainloop-test dbus-test +endif # memory management test mm_test_SOURCES = mm-test.c @@ -27,3 +30,11 @@ transport_test_SOURCES = transport-test.c transport_test_CFLAGS = $(AM_CFLAGS) transport_test_LDADD = ../../libmurphy-common.la +if DBUS_ENABLED +transport_test_LDADD += ../../libmurphy-dbus.la + +# DBUS test +dbus_test_SOURCES = dbus-test.c +dbus_test_CFLAGS = $(AM_CFLAGS) $(DBUS_CFLAGS) +dbus_test_LDADD = ../../libmurphy-dbus.la ../../libmurphy-common.la +endif diff --git a/src/common/transport.c b/src/common/transport.c index eb87a6d..f598c4b 100644 --- a/src/common/transport.c +++ b/src/common/transport.c @@ -262,7 +262,7 @@ mrp_transport_t *mrp_transport_accept(mrp_transport_t *lt, t = NULL; } else { - + t->connected = TRUE; } }); } @@ -328,8 +328,10 @@ int mrp_transport_connect(mrp_transport_t *t, mrp_sockaddr_t *addr, purge_destroyed(t); } - else + else { + errno = EISCONN; result = FALSE; + } return result; } diff --git a/src/common/transport.h b/src/common/transport.h index 0dc0a69..5628c3c 100644 --- a/src/common/transport.h +++ b/src/common/transport.h @@ -59,11 +59,14 @@ typedef struct mrp_transport_s mrp_transport_t; * transport socket address */ +#define MRP_SOCKADDR_SIZE 256 + typedef union { struct sockaddr any; struct sockaddr_in ipv4; struct sockaddr_in6 ipv6; struct sockaddr_un unx; + char data[MRP_SOCKADDR_SIZE]; } mrp_sockaddr_t; @@ -261,31 +264,35 @@ struct mrp_transport_s { #ifndef __MRP_TRANSPORT_DISABLE_CODE_CHECK__ -# define __TRANSPORT_CHK_BLOCK(...) do { \ - static int __warned = 0; \ - \ - if (MRP_UNLIKELY(__warned == 0 && \ - strstr(#__VA_ARGS__, "return") != NULL)) { \ - mrp_log_error("********************* WARNING *********************"); \ - mrp_log_error("* You seem to directly do a return from a block *"); \ - mrp_log_error("* of code protected by MRP_TRANSPORT_BUSY. Are *"); \ - mrp_log_error("* you absolutely sure you know what you are doing *"); \ - mrp_log_error("* and that you are also doing it correctly ? *"); \ - mrp_log_error("***************************************************"); \ - mrp_log_error("The suspicious code block is located at: "); \ - mrp_log_error(" %s@%s:%d", __FUNCTION__, __FILE__, __LINE__); \ - mrp_log_error("and it looks like this:"); \ - mrp_log_error("---------------------------------------------"); \ - mrp_log_error("%s", #__VA_ARGS__); \ - mrp_log_error("---------------------------------------------"); \ - mrp_log_error("If you understand what MRP_TRANSPORT_BUSY does and"); \ - mrp_log_error("how, and you are sure about the corretness of your"); \ - mrp_log_error("code you can disable this error message by"); \ - mrp_log_error("#defining __MRP_TRANSPORT_DISABLE_CODE_CHECK__"); \ - mrp_log_error("when compiling %s.", __FILE__); \ - __warned = 1; \ - } \ - } while (0) +# define W mrp_log_error +# define __TRANSPORT_CHK_BLOCK(...) do { \ + static int __checked = FALSE, __warned = FALSE; \ + \ + if (MRP_UNLIKELY(!__checked)) { \ + __checked = TRUE; \ + if (MRP_UNLIKELY(!__warned && \ + strstr(#__VA_ARGS__, "return") != NULL)) { \ + W("*********************** WARNING ********************"); \ + W("* You seem to directly do a return from a block of *"); \ + W("* code protected by MRP_TRANSPORT_BUSY. Are you *"); \ + W("* absolutely sure you know what you are doing and *"); \ + W("* that you are also doing it correctly ? *"); \ + W("****************************************************"); \ + W("The suspicious code block is located at: "); \ + W(" %s@%s:%d", __FUNCTION__, __FILE__, __LINE__); \ + W("and it looks like this:"); \ + W("---------------------------------------------"); \ + W("%s", #__VA_ARGS__); \ + W("---------------------------------------------"); \ + W("If you understand what MRP_TRANSPORT_BUSY does and"); \ + W("how, and you are sure about the corretness of your"); \ + W("code you can disable this error message by"); \ + W("#defining __MRP_TRANSPORT_DISABLE_CODE_CHECK__"); \ + W("when compiling %s.", __FILE__); \ + __warned = TRUE; \ + } \ + } \ + } while (0) #else # define __TRANSPORT_CHK_BLOCK(...) do { } while (0) #endif diff --git a/src/daemon/murphy.conf b/src/daemon/murphy.conf index 738c52d..9193663 100644 --- a/src/daemon/murphy.conf +++ b/src/daemon/murphy.conf @@ -1,6 +1,8 @@ -try-load-plugin console # address="tcp4:127.0.0.1:3000" +# try-load-plugin dbus +try-load-plugin console # address="tcp4:127.0.0.1:3000" # address="udp4:127.0.0.1:3000" - # address="unxstrm:@/murphyd" + # address="unxs:@/murphyd" + # address="dbus:[session]@murphy.org/console # load two instances of the test plugin if plugin-exists test -- 2.7.4