summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPavel Březina <pbrezina@redhat.com>2014-12-11 22:23:32 +0100
committerJakub Hrozek <jhrozek@redhat.com>2015-01-23 21:29:31 +0100
commit46ee931314e6a5517f5c6b6b14f759364be119cc (patch)
treeddd462856868f8e5aad32d940302640221dd8e46 /src
parent894f09f146f0c9cda9e0f7dfe1916519d73dde72 (diff)
downloadsssd-46ee931314e6a5517f5c6b6b14f759364be119cc.tar.gz
sssd-46ee931314e6a5517f5c6b6b14f759364be119cc.tar.xz
sssd-46ee931314e6a5517f5c6b6b14f759364be119cc.zip
sbus: support multiple interfaces on single path
This patch removes the old message handler which is replaced with a new one that supports multiple interfaces registered on single object path. A hash table is used to store registered object paths and their interfaces. When an entry or the table itself is destroyed, registered object path is unregistered through delete callback. It temporarily removes support of Introspect and Properties standard D-Bus interfaces and disables unit tests of those interfaces. The support is brought back by following patches. Resolves: https://fedorahosted.org/sssd/ticket/2339 Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
Diffstat (limited to 'src')
-rw-r--r--src/sbus/sssd_dbus.h9
-rw-r--r--src/sbus/sssd_dbus_connection.c197
-rw-r--r--src/sbus/sssd_dbus_interface.c526
-rw-r--r--src/sbus/sssd_dbus_private.h20
-rw-r--r--src/tests/sbus_codegen_tests.c2
-rw-r--r--src/tests/sbus_tests.c2
6 files changed, 455 insertions, 301 deletions
diff --git a/src/sbus/sssd_dbus.h b/src/sbus/sssd_dbus.h
index 7552fbcf1..c50b4e9b6 100644
--- a/src/sbus/sssd_dbus.h
+++ b/src/sbus/sssd_dbus.h
@@ -170,6 +170,9 @@ int sbus_conn_register_iface(struct sbus_connection *conn,
const char *object_path,
void *pvt);
+errno_t
+sbus_conn_reregister_paths(struct sbus_connection *conn);
+
bool sbus_conn_disconnecting(struct sbus_connection *conn);
/* max_retries < 0: retry forever
@@ -181,12 +184,6 @@ void sbus_reconnect_init(struct sbus_connection *conn,
sbus_conn_reconn_callback_fn callback,
void *pvt);
-/* Default message handler
- * Should be usable for most cases */
-DBusHandlerResult sbus_message_handler(DBusConnection *conn,
- DBusMessage *message,
- void *user_data);
-
/*
* Send a message across the SBUS
* If requested, the DBusPendingCall object will
diff --git a/src/sbus/sssd_dbus_connection.c b/src/sbus/sssd_dbus_connection.c
index d27fd2fad..8ff279c1b 100644
--- a/src/sbus/sssd_dbus_connection.c
+++ b/src/sbus/sssd_dbus_connection.c
@@ -161,6 +161,13 @@ int sbus_init_connection(TALLOC_CTX *ctx,
conn->dbus.conn = dbus_conn;
conn->connection_type = connection_type;
+ ret = sbus_opath_hash_init(conn, conn, &conn->managed_paths);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot create object paths hash table\n");
+ talloc_free(conn);
+ return EIO;
+ }
+
ret = sss_hash_create(conn, 32, &conn->clients);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE, "Cannot create clients hash table\n");
@@ -313,7 +320,7 @@ void sbus_disconnect(struct sbus_connection *conn)
conn->disconnect = 1;
/* Unregister object paths */
- sbus_unreg_object_paths(conn);
+ talloc_zfree(conn->managed_paths);
/* Disable watch functions */
dbus_connection_set_watch_functions(conn->dbus.conn,
@@ -342,185 +349,12 @@ void sbus_disconnect(struct sbus_connection *conn)
DEBUG(SSSDBG_TRACE_FUNC ,"Disconnected %p\n", conn->dbus.conn);
}
-static void sbus_handler_got_caller_id(struct tevent_req *req);
-
-/* messsage_handler
- * Receive messages and process them
- */
-DBusHandlerResult sbus_message_handler(DBusConnection *dbus_conn,
- DBusMessage *message,
- void *user_data)
-{
- struct sbus_interface_p *intf_p;
- const char *msg_method;
- const char *path;
- const char *msg_interface;
- const char *sender;
- struct sbus_request *dbus_req = NULL;
- struct tevent_req *req;
-
- if (!user_data) {
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
- }
- intf_p = talloc_get_type(user_data, struct sbus_interface_p);
-
- msg_method = dbus_message_get_member(message);
- DEBUG(SSSDBG_TRACE_ALL, "Received SBUS method [%s]\n", msg_method);
- path = dbus_message_get_path(message);
- msg_interface = dbus_message_get_interface(message);
- sender = dbus_message_get_sender(message);
-
- if (!msg_method || !path || !msg_interface) {
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
- }
-
- /* Validate the D-BUS path */
- if (!sbus_iface_handles_path(intf_p, path)) {
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
- }
-
- /* Validate the method interface */
- if (strcmp(msg_interface, intf_p->intf->vtable->meta->name) == 0 ||
- strcmp(msg_interface, DBUS_PROPERTIES_INTERFACE) == 0 ||
- (strcmp(msg_interface, DBUS_INTROSPECT_INTERFACE) == 0 &&
- strcmp(msg_method, DBUS_INTROSPECT_METHOD) == 0)) {
-
- /* OK, this message for us. Get the sender ID if applicable */
- dbus_req = sbus_new_request(intf_p->conn, intf_p->intf, message);
- if (dbus_req == NULL) {
- return DBUS_HANDLER_RESULT_NEED_MEMORY;
- }
-
- req = sbus_get_sender_id_send(dbus_req, dbus_req->conn->ev,
- dbus_req->conn, sender);
- if (req == NULL) {
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
- }
- tevent_req_set_callback(req, sbus_handler_got_caller_id, dbus_req);
- return DBUS_HANDLER_RESULT_HANDLED;
- }
-
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-}
-
-static void sbus_handler_got_caller_id(struct tevent_req *req)
-{
- struct sbus_request *dbus_req = \
- tevent_req_callback_data(req,
- struct sbus_request);
- errno_t ret;
- DBusError *dberr;
- DBusMessage *reply = NULL;
- const struct sbus_method_meta *method;
- const struct sbus_interface_meta *interface;
- const char *msg_method;
- const char *msg_interface;
- sbus_msg_handler_fn handler_fn = NULL;
- void *handler_data = NULL; /* Must be a talloc pointer! */
- struct sbus_introspect_ctx *ictx = NULL;
- const char *dbus_error = NULL;
-
- ret = sbus_get_sender_id_recv(req, &dbus_req->client);
- if (ret != EOK) {
- dberr = sbus_error_new(dbus_req,
- DBUS_ERROR_FAILED,
- "Failed to retrieve called ID: %s\n",
- sss_strerror(ret));
- sbus_request_fail_and_finish(dbus_req, dberr);
- return;
- }
-
- msg_method = dbus_message_get_member(dbus_req->message);
- msg_interface = dbus_message_get_interface(dbus_req->message);
- DEBUG(SSSDBG_TRACE_ALL, "Received SBUS method [%s]\n", msg_method);
-
- /* Prepare the handler */
- interface = dbus_req->intf->vtable->meta;
- if (strcmp(msg_interface, interface->name) == 0) {
- method = sbus_meta_find_method(interface, msg_method);
- if (method && method->vtable_offset)
- handler_fn = VTABLE_FUNC(dbus_req->intf->vtable,
- method->vtable_offset);
-
- if (!method) {
- /* Reply DBUS_ERROR_UNKNOWN_METHOD */
- DEBUG(SSSDBG_CRIT_FAILURE,
- "No matching method found for %s.\n", msg_method);
- dbus_error = DBUS_ERROR_UNKNOWN_METHOD;
- goto fail;
- } else if (!handler_fn) {
- /* Reply DBUS_ERROR_NOT_SUPPORTED */
- DEBUG(SSSDBG_CRIT_FAILURE,
- "No handler provided found for %s.\n", msg_method);
- dbus_error = DBUS_ERROR_NOT_SUPPORTED;
- goto fail;
- }
- } else if (strcmp(msg_interface, DBUS_INTROSPECT_INTERFACE) == 0 &&
- strcmp(msg_method, DBUS_INTROSPECT_METHOD) == 0) {
- DEBUG(SSSDBG_TRACE_LIBS, "Got introspection request\n");
- ictx = talloc(dbus_req->conn, struct sbus_introspect_ctx);
- if (ictx == NULL) {
- dbus_error = DBUS_ERROR_NO_MEMORY;
- goto fail;
- }
-
- handler_fn = sbus_introspect;
- ictx->iface = interface;
- handler_data = ictx;
- method = &introspect_method;
- } else if (strcmp(msg_interface, DBUS_PROPERTIES_INTERFACE) == 0) {
- ret = sbus_properties_dispatch(dbus_req);
- if (ret == ERR_SBUS_NOSUP) {
- /* No known method matched */
- dbus_error = DBUS_ERROR_NOT_SUPPORTED;
- goto fail;
- }
- /* sbus_properties_dispatch handles all other errors
- * or success internally
- */
- return;
- }
-
- if (handler_fn == NULL) {
- DEBUG(SSSDBG_MINOR_FAILURE, "No handler matched!\n");
- dbus_error = DBUS_ERROR_NOT_SUPPORTED;
- goto fail;
- }
-
- dbus_req->method = method;
- if (handler_data) {
- /* If the handler uses private instance data, make
- * sure they go away when the request does
- */
- talloc_steal(dbus_req, handler_data);
- } else {
- /* If no custom handler data is set, pass on the
- * interface data
- */
- handler_data = dbus_req->intf->instance_data;
- }
-
- sbus_request_invoke_or_finish(dbus_req,
- handler_fn,
- handler_data,
- method->invoker);
- return;
-
-fail:
- reply = dbus_message_new_error(dbus_req->message,
- dbus_error ? dbus_error : DBUS_ERROR_FAILED,
- NULL);
- sbus_request_finish(dbus_req, reply);
-}
-
static void sbus_reconnect(struct tevent_context *ev,
struct tevent_timer *te,
struct timeval tv, void *data)
{
struct sbus_connection *conn;
- struct sbus_interface_p *iter;
DBusError dbus_error;
- dbus_bool_t dbret;
int ret;
conn = talloc_get_type(data, struct sbus_connection);
@@ -539,20 +373,7 @@ static void sbus_reconnect(struct tevent_context *ev,
}
/* Re-register object paths */
- iter = conn->intf_list;
- while (iter) {
- dbret = dbus_connection_register_object_path(conn->dbus.conn,
- iter->intf->path,
- &dbus_object_path_vtable,
- iter);
- if (!dbret) {
- DEBUG(SSSDBG_FATAL_FAILURE,
- "Could not register object path.\n");
- dbus_connection_unref(conn->dbus.conn);
- goto failed;
- }
- iter = iter->next;
- }
+ sbus_conn_reregister_paths(conn);
/* Reset retries to 0 to resume dispatch processing */
conn->retries = 0;
diff --git a/src/sbus/sssd_dbus_interface.c b/src/sbus/sssd_dbus_interface.c
index acede4d32..9a26a26b6 100644
--- a/src/sbus/sssd_dbus_interface.c
+++ b/src/sbus/sssd_dbus_interface.c
@@ -20,43 +20,31 @@
#include <talloc.h>
#include <dbus/dbus.h>
+#include <dhash.h>
#include "util/util.h"
#include "sbus/sssd_dbus.h"
+#include "sbus/sssd_dbus_meta.h"
#include "sbus/sssd_dbus_private.h"
-DBusObjectPathVTable dbus_object_path_vtable =
- { NULL, sbus_message_handler, NULL, NULL, NULL, NULL };
+struct sbus_interface_list {
+ struct sbus_interface_list *prev, *next;
+ struct sbus_interface *interface;
+};
-static bool path_in_interface_list(struct sbus_interface_p *list,
- const char *path)
+static struct sbus_interface *
+sbus_iface_list_lookup(struct sbus_interface_list *list,
+ const char *iface)
{
- struct sbus_interface_p *iter;
+ struct sbus_interface_list *item;
- if (!list || !path) {
- return false;
- }
-
- iter = list;
- while (iter != NULL) {
- if (strcmp(iter->intf->path, path) == 0) {
- return true;
+ DLIST_FOR_EACH(item, list) {
+ if (strcmp(item->interface->vtable->meta->name, iface) == 0) {
+ return item->interface;
}
- iter = iter->next;
}
- return false;
-}
-
-void sbus_unreg_object_paths(struct sbus_connection *conn)
-{
- struct sbus_interface_p *iter = conn->intf_list;
-
- while (iter != NULL) {
- dbus_connection_unregister_object_path(conn->dbus.conn,
- iter->intf->path);
- iter = iter->next;
- }
+ return NULL;
}
/**
@@ -76,24 +64,6 @@ static bool sbus_opath_is_subtree(const char *path)
return path[len - 2] == '/' && path[len - 1] == '*';
}
-static bool sbus_opath_match_tree(const char *object_path,
- const char *tree_path)
-{
- if (object_path == NULL || tree_path == NULL || tree_path[0] == '\0') {
- return false;
- };
-
- /* first check if tree is a base path or a subtree path */
- if (!sbus_opath_is_subtree(tree_path)) {
- return strcmp(object_path, tree_path) == 0;
- }
-
- /* Compare without the asterisk, which is the last character.
- * Slash, that has to be present before the asterisk, will ensure that only
- * subtree object path matches. */
- return strncmp(object_path, tree_path, strlen(tree_path) - 1) == 0;
-}
-
/**
* If the path represents a subtree object path, this function will
* remove /~* from the end.
@@ -121,14 +91,226 @@ static char *sbus_opath_get_base_path(TALLOC_CTX *mem_ctx,
return tree_path;
}
-bool sbus_iface_handles_path(struct sbus_interface_p *intf_p,
- const char *path)
+static char *sbus_opath_parent_subtree(TALLOC_CTX *mem_ctx,
+ const char *path)
+{
+ char *subtree;
+ char *slash;
+
+ /* first remove /~* from the end, stop when we have reached the root i.e.
+ * subtree == "/" */
+ subtree = sbus_opath_get_base_path(mem_ctx, path);
+ if (subtree == NULL || subtree[1] == '\0') {
+ return NULL;
+ }
+
+ /* Find the first separator and replace the part with asterisk. */
+ slash = strrchr(subtree, '/');
+ if (slash == NULL) {
+ /* we cannot continue up */
+ talloc_free(subtree);
+ return NULL;
+ }
+
+ if (*(slash + 1) == '\0') {
+ /* this object path is invalid since it cannot end with slash */
+ DEBUG(SSSDBG_CRIT_FAILURE, "Invalid object path '%s'?\n", path);
+ talloc_free(subtree);
+ return NULL;
+ }
+
+ /* because object path cannot end with / there is enough space for
+ * asterisk and terminating zero */
+ *(slash + 1) = '*';
+ *(slash + 2) = '\0';
+
+ return subtree;
+}
+
+static void
+sbus_opath_hash_delete_cb(hash_entry_t *item,
+ hash_destroy_enum deltype,
+ void *pvt)
+{
+ struct sbus_connection *conn;
+ char *path;
+
+ conn = talloc_get_type(pvt, struct sbus_connection);
+ path = sbus_opath_get_base_path(NULL, item->key.str);
+
+ dbus_connection_unregister_object_path(conn->dbus.conn, path);
+}
+
+errno_t
+sbus_opath_hash_init(TALLOC_CTX *mem_ctx,
+ struct sbus_connection *conn,
+ hash_table_t **_table)
+{
+ return sss_hash_create_ex(mem_ctx, 10, _table, 0, 0, 0, 0,
+ sbus_opath_hash_delete_cb, conn);
+}
+
+static errno_t
+sbus_opath_hash_add_iface(hash_table_t *table,
+ const char *object_path,
+ struct sbus_interface *iface,
+ bool *_path_known)
+{
+ TALLOC_CTX *tmp_ctx = NULL;
+ struct sbus_interface_list *list = NULL;
+ struct sbus_interface_list *item = NULL;
+ const char *iface_name = iface->vtable->meta->name;
+ hash_key_t key;
+ hash_value_t value;
+ bool path_known;
+ errno_t ret;
+ int hret;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ DEBUG(SSSDBG_TRACE_FUNC, "Registering interface %s with path %s\n",
+ iface_name, object_path);
+
+ /* create new list item */
+
+ item = talloc_zero(tmp_ctx, struct sbus_interface_list);
+ if (item == NULL) {
+ return ENOMEM;
+ }
+
+ item->interface = iface;
+
+ /* first lookup existing list in hash table */
+
+ key.type = HASH_KEY_STRING;
+ key.str = talloc_strdup(tmp_ctx, object_path);
+ if (key.str == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ hret = hash_lookup(table, &key, &value);
+ if (hret == HASH_SUCCESS) {
+ /* This object path has already some interface registered. We will
+ * check for existence of the interface currently being added and
+ * add it if missing. */
+
+ path_known = true;
+
+ list = talloc_get_type(value.ptr, struct sbus_interface_list);
+ if (sbus_iface_list_lookup(list, iface_name) != NULL) {
+ DEBUG(SSSDBG_MINOR_FAILURE, "Trying to register the same interface"
+ " twice: iface=%s, opath=%s\n", iface_name, object_path);
+ ret = EEXIST;
+ goto done;
+ }
+
+ DLIST_ADD_END(list, item, struct sbus_interface_list *);
+ ret = EOK;
+ goto done;
+ } else if (hret != HASH_ERROR_KEY_NOT_FOUND) {
+ ret = EIO;
+ goto done;
+ }
+
+ /* otherwise create new hash entry and new list */
+
+ path_known = false;
+ list = item;
+
+ value.type = HASH_VALUE_PTR;
+ value.ptr = list;
+
+ hret = hash_enter(table, &key, &value);
+ if (hret != HASH_SUCCESS) {
+ ret = EIO;
+ goto done;
+ }
+
+ talloc_steal(table, key.str);
+ ret = EOK;
+
+done:
+ if (ret == EOK) {
+ talloc_steal(item, iface);
+ talloc_steal(table, item);
+ *_path_known = path_known;
+ } else {
+ talloc_free(item);
+ }
+
+ return ret;
+}
+
+static bool
+sbus_opath_hash_has_path(hash_table_t *table,
+ const char *object_path)
+{
+ hash_key_t key;
+
+ key.type = HASH_KEY_STRING;
+ key.str = discard_const(object_path);
+
+ return hash_has_key(table, &key);
+}
+
+/**
+ * First @object_path is looked up in @table, if it is not found it steps up
+ * in the path hierarchy and try to lookup the parent node. This continues
+ * until the root is reached.
+ */
+static struct sbus_interface *
+sbus_opath_hash_lookup_iface(hash_table_t *table,
+ const char *object_path,
+ const char *iface_name)
{
- if (sbus_opath_is_subtree(intf_p->intf->path)) {
- return sbus_opath_match_tree(path, intf_p->intf->path);
+ TALLOC_CTX *tmp_ctx = NULL;
+ struct sbus_interface_list *list = NULL;
+ struct sbus_interface *iface = NULL;
+ char *lookup_path = NULL;
+ hash_key_t key;
+ hash_value_t value;
+ int hret;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return NULL;
}
- return strcmp(path, intf_p->intf->path) == 0;
+ lookup_path = talloc_strdup(tmp_ctx, object_path);
+ if (lookup_path == NULL) {
+ goto done;
+ }
+
+ while (lookup_path != NULL) {
+ key.type = HASH_KEY_STRING;
+ key.str = lookup_path;
+
+ hret = hash_lookup(table, &key, &value);
+ if (hret == HASH_SUCCESS) {
+ list = talloc_get_type(value.ptr, struct sbus_interface_list);
+ iface = sbus_iface_list_lookup(list, iface_name);
+ if (iface != NULL) {
+ goto done;
+ }
+ } else if (hret != HASH_ERROR_KEY_NOT_FOUND) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Unable to search hash table: hret=%d\n", hret);
+ iface = NULL;
+ goto done;
+ }
+
+ /* we will not free lookup path since it is freed with tmp_ctx
+ * and the object paths are supposed to be small */
+ lookup_path = sbus_opath_parent_subtree(tmp_ctx, lookup_path);
+ }
+
+done:
+ talloc_free(tmp_ctx);
+ return iface;
}
static struct sbus_interface *
@@ -157,67 +339,227 @@ sbus_new_interface(TALLOC_CTX *mem_ctx,
return intf;
}
-int sbus_conn_register_iface(struct sbus_connection *conn,
- struct sbus_vtable *iface_vtable,
- const char *object_path,
- void *pvt)
+static DBusHandlerResult
+sbus_message_handler(DBusConnection *dbus_conn,
+ DBusMessage *message,
+ void *user_data);
+
+static errno_t
+sbus_conn_register_path(struct sbus_connection *conn,
+ const char *path)
{
- struct sbus_interface_p *intf_p;
- struct sbus_interface *intf;
+ static DBusObjectPathVTable vtable = {NULL, sbus_message_handler,
+ NULL, NULL, NULL, NULL};
+ DBusError error;
+ char *reg_path = NULL;
dbus_bool_t dbret;
- const char *path;
- bool fallback;
- intf = sbus_new_interface(conn, object_path, iface_vtable, pvt);
- if (intf == NULL) {
- return ENOMEM;
+ DEBUG(SSSDBG_TRACE_FUNC, "Registering object path %s with D-Bus "
+ "connection\n", path);
+
+ if (sbus_opath_is_subtree(path)) {
+ reg_path = sbus_opath_get_base_path(conn, path);
+ if (reg_path == NULL) {
+ return ENOMEM;
+ }
+
+ /* D-Bus does not allow to have both object path and fallback
+ * registered. Since we handle the real message handlers ourselves
+ * we will register fallback only in this case. */
+ if (sbus_opath_hash_has_path(conn->managed_paths, reg_path)) {
+ dbus_connection_unregister_object_path(conn->dbus.conn, reg_path);
+ }
+
+ dbret = dbus_connection_register_fallback(conn->dbus.conn, reg_path,
+ &vtable, conn);
+ talloc_free(reg_path);
+ } else {
+ dbus_error_init(&error);
+
+ dbret = dbus_connection_try_register_object_path(conn->dbus.conn, path,
+ &vtable, conn, &error);
+
+ if (dbus_error_is_set(&error) &&
+ strcmp(error.name, DBUS_ERROR_OBJECT_PATH_IN_USE) == 0) {
+ /* A fallback is probably already registered. Just return. */
+ dbus_error_free(&error);
+ return EOK;
+ }
}
- if (!conn || !intf->vtable || !intf->vtable->meta) {
- return EINVAL;
+ if (!dbret) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "Unable to register object path "
+ "%s with D-Bus connection.\n", path);
+ return ENOMEM;
}
- path = intf->path;
- fallback = sbus_opath_is_subtree(path);
+ return EOK;
+}
+
+errno_t
+sbus_conn_register_iface(struct sbus_connection *conn,
+ struct sbus_vtable *iface_vtable,
+ const char *object_path,
+ void *pvt)
+{
+ struct sbus_interface *iface = NULL;
+ bool path_known;
+ errno_t ret;
- if (path_in_interface_list(conn->intf_list, path)) {
- DEBUG(SSSDBG_FATAL_FAILURE,
- "Cannot add method context with identical path.\n");
+ if (conn == NULL || iface_vtable == NULL || object_path == NULL) {
return EINVAL;
}
- intf_p = talloc_zero(conn, struct sbus_interface_p);
- if (!intf_p) {
+ iface = sbus_new_interface(conn, object_path, iface_vtable, pvt);
+ if (iface == NULL) {
return ENOMEM;
}
- intf_p->conn = conn;
- intf_p->intf = intf;
- intf_p->reg_path = sbus_opath_get_base_path(intf_p, path);
- if (intf_p->reg_path == NULL) {
- return ENOMEM;
+
+ ret = sbus_opath_hash_add_iface(conn->managed_paths, object_path, iface,
+ &path_known);
+ if (ret != EOK) {
+ talloc_free(iface);
+ return ret;
}
- DLIST_ADD(conn->intf_list, intf_p);
+ if (path_known) {
+ /* this object path is already registered */
+ return EOK;
+ }
- DEBUG(SSSDBG_TRACE_LIBS, "Will register path %s with%s fallback\n",
- intf_p->reg_path, fallback ? "" : "out");
+ ret = sbus_conn_register_path(conn, object_path);
- if (fallback) {
- dbret = dbus_connection_register_fallback(conn->dbus.conn,
- intf_p->reg_path,
- &dbus_object_path_vtable,
- intf_p);
- } else {
- dbret = dbus_connection_register_object_path(conn->dbus.conn,
- intf_p->reg_path,
- &dbus_object_path_vtable,
- intf_p);
+ /* if ret != EOK we will still leave iface in the table, since
+ * we probably don't have enough memory to remove it correctly anyway */
+ return ret;
+}
+
+errno_t
+sbus_conn_reregister_paths(struct sbus_connection *conn)
+{
+ hash_key_t *keys = NULL;
+ unsigned long count;
+ unsigned long i;
+ errno_t ret;
+ int hret;
+
+ hret = hash_keys(conn->managed_paths, &count, &keys);
+ if (hret != HASH_SUCCESS) {
+ ret = ENOMEM;
+ goto done;
}
- if (!dbret) {
- DEBUG(SSSDBG_FATAL_FAILURE,
- "Could not register object path to the connection.\n");
- return ENOMEM;
+
+ for (i = 0; i < count; i++) {
+ ret = sbus_conn_register_path(conn, keys[i].str);
+ if (ret != EOK) {
+ goto done;
+ }
}
- return EOK;
+ ret = EOK;
+
+done:
+ talloc_free(keys);
+ return ret;
+}
+
+static void
+sbus_message_handler_got_caller_id(struct tevent_req *req);
+
+static DBusHandlerResult
+sbus_message_handler(DBusConnection *dbus_conn,
+ DBusMessage *message,
+ void *user_data)
+{
+ struct tevent_req *req;
+ struct sbus_connection *conn;
+ struct sbus_interface *iface;
+ struct sbus_request *sbus_req;
+ const struct sbus_method_meta *method;
+ const char *iface_name;
+ const char *method_name;
+ const char *path;
+ const char *sender;
+
+ conn = talloc_get_type(user_data, struct sbus_connection);
+
+ /* header information */
+ iface_name = dbus_message_get_interface(message);
+ method_name = dbus_message_get_member(message);
+ path = dbus_message_get_path(message);
+ sender = dbus_message_get_sender(message);
+
+ DEBUG(SSSDBG_TRACE_INTERNAL, "Received SBUS method %s.%s on path %s\n",
+ iface_name, method_name, path);
+
+ /* try to find the interface */
+ iface = sbus_opath_hash_lookup_iface(conn->managed_paths,
+ path, iface_name);
+ if (iface == NULL) {
+ goto fail;
+ }
+
+ method = sbus_meta_find_method(iface->vtable->meta, method_name);
+ if (method == NULL || method->vtable_offset == 0) {
+ goto fail;
+ }
+
+ /* we have a valid handler, create D-Bus request */
+ sbus_req = sbus_new_request(conn, iface, message);
+ if (sbus_req == NULL) {
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+ }
+
+ sbus_req->method = method;
+
+ /* now get the sender ID */
+ req = sbus_get_sender_id_send(sbus_req, conn->ev, conn, sender);
+ if (req == NULL) {
+ talloc_free(sbus_req);
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+ }
+ tevent_req_set_callback(req, sbus_message_handler_got_caller_id, sbus_req);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+
+fail: ;
+ DBusMessage *reply;
+
+ DEBUG(SSSDBG_CRIT_FAILURE, "No matching handler found for method %s.%s "
+ "on path %s\n", iface_name, method_name, path);
+
+ reply = dbus_message_new_error(message, DBUS_ERROR_UNKNOWN_METHOD, NULL);
+ sbus_conn_send_reply(conn, reply);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static void
+sbus_message_handler_got_caller_id(struct tevent_req *req)
+{
+ struct sbus_request *sbus_req;
+ const struct sbus_method_meta *method;
+ sbus_msg_handler_fn handler;
+ sbus_method_invoker_fn invoker;
+ void *pvt;
+ DBusError *error;
+ errno_t ret;
+
+ sbus_req = tevent_req_callback_data(req, struct sbus_request);
+ method = sbus_req->method;
+
+ ret = sbus_get_sender_id_recv(req, &sbus_req->client);
+ if (ret != EOK) {
+ error = sbus_error_new(sbus_req, DBUS_ERROR_FAILED, "Failed to "
+ "resolve caller's ID: %s\n", sss_strerror(ret));
+ sbus_request_fail_and_finish(sbus_req, error);
+ return;
+ }
+
+ handler = VTABLE_FUNC(sbus_req->intf->vtable, method->vtable_offset);
+ invoker = method->invoker;
+ pvt = sbus_req->intf->instance_data;
+
+ sbus_request_invoke_or_finish(sbus_req, handler, pvt, invoker);
+ return;
}
diff --git a/src/sbus/sssd_dbus_private.h b/src/sbus/sssd_dbus_private.h
index fc63405a1..23d2898f8 100644
--- a/src/sbus/sssd_dbus_private.h
+++ b/src/sbus/sssd_dbus_private.h
@@ -37,14 +37,6 @@ enum dbus_conn_type {
struct sbus_watch_ctx;
-struct sbus_interface_p {
- struct sbus_interface_p *prev, *next;
- struct sbus_connection *conn;
- struct sbus_interface *intf;
-
- const char *reg_path;
-};
-
struct sbus_connection {
struct tevent_context *ev;
@@ -55,8 +47,7 @@ struct sbus_connection {
int connection_type;
int disconnect;
- /* dbus tables and handlers */
- struct sbus_interface_p *intf_list;
+ hash_table_t *managed_paths;
/* reconnect settings */
int retries;
@@ -75,8 +66,6 @@ struct sbus_connection {
struct sbus_watch_ctx *watch_list;
};
-extern DBusObjectPathVTable dbus_object_path_vtable;
-
/* =Watches=============================================================== */
struct sbus_watch_ctx {
@@ -114,9 +103,10 @@ sbus_new_request(struct sbus_connection *conn, struct sbus_interface *intf,
/* =Interface=and=object=paths============================================ */
-void sbus_unreg_object_paths(struct sbus_connection *conn);
-bool sbus_iface_handles_path(struct sbus_interface_p *intf_p,
- const char *path);
+errno_t
+sbus_opath_hash_init(TALLOC_CTX *mem_ctx,
+ struct sbus_connection *conn,
+ hash_table_t **_table);
/* =Interface=introspection=============================================== */
extern const struct sbus_method_meta introspect_method;
diff --git a/src/tests/sbus_codegen_tests.c b/src/tests/sbus_codegen_tests.c
index dccb5e314..07c62c5ef 100644
--- a/src/tests/sbus_codegen_tests.c
+++ b/src/tests/sbus_codegen_tests.c
@@ -1353,9 +1353,11 @@ TCase *create_handler_tests(void)
TCase *tc = tcase_create("handler");
tcase_add_test(tc, test_marshal_basic_types);
+#if false
tcase_add_test(tc, test_get_basic_types);
tcase_add_test(tc, test_getall_basic_types);
tcase_add_test(tc, test_get_basic_array_types);
+#endif
return tc;
}
diff --git a/src/tests/sbus_tests.c b/src/tests/sbus_tests.c
index 486e39221..6086a42bf 100644
--- a/src/tests/sbus_tests.c
+++ b/src/tests/sbus_tests.c
@@ -372,7 +372,9 @@ TCase *create_sbus_tests(void)
tcase_add_test(tc, test_raw_handler);
tcase_add_test(tc, test_request_parse_ok);
tcase_add_test(tc, test_request_parse_bad_args);
+#if false
tcase_add_test(tc, test_introspection);
+#endif
tcase_add_test(tc, test_sbus_new_error);
return tc;