summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPavel Březina <pbrezina@redhat.com>2015-06-03 12:35:42 +0200
committerJakub Hrozek <jhrozek@redhat.com>2015-06-19 17:19:03 +0200
commitae7247551b78a05a5397d3c790afad7ef51b0d9d (patch)
treea4b35d2c670dc6f1fc044024338023ed2580fc40
parentf2bba721d18842a014ab170c207af8e8ecb6e890 (diff)
downloadsssd-ae7247551b78a05a5397d3c790afad7ef51b0d9d.tar.gz
sssd-ae7247551b78a05a5397d3c790afad7ef51b0d9d.tar.xz
sssd-ae7247551b78a05a5397d3c790afad7ef51b0d9d.zip
sbus: add support for incoming signals
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-rw-r--r--Makefile.am1
-rw-r--r--src/sbus/sssd_dbus.h20
-rw-r--r--src/sbus/sssd_dbus_connection.c18
-rw-r--r--src/sbus/sssd_dbus_private.h12
-rw-r--r--src/sbus/sssd_dbus_signals.c290
5 files changed, 341 insertions, 0 deletions
diff --git a/Makefile.am b/Makefile.am
index 73de2db94..5a2cc884f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -753,6 +753,7 @@ libsss_util_la_SOURCES = \
src/sbus/sssd_dbus_properties.c \
src/sbus/sssd_dbus_request.c \
src/sbus/sssd_dbus_server.c \
+ src/sbus/sssd_dbus_signals.c \
src/util/util.c \
src/util/memory.c \
src/util/safe-format-string.c \
diff --git a/src/sbus/sssd_dbus.h b/src/sbus/sssd_dbus.h
index 818070fa5..c1e27746e 100644
--- a/src/sbus/sssd_dbus.h
+++ b/src/sbus/sssd_dbus.h
@@ -404,4 +404,24 @@ bool sbus_request_parse_or_finish(struct sbus_request *request,
int first_arg_type,
...);
+struct sbus_incoming_signal {
+ struct sbus_connection *conn;
+ DBusMessage *message;
+ int64_t client;
+ const char *interface;
+ const char *signal;
+ const char *path;
+};
+
+typedef void
+(*sbus_incoming_signal_fn)(struct sbus_incoming_signal *sbus_signal,
+ void *handler_data);
+
+errno_t
+sbus_signal_listen(struct sbus_connection *conn,
+ const char *iface,
+ const char *signal,
+ sbus_incoming_signal_fn handler_fn,
+ void *handler_data);
+
#endif /* _SSSD_DBUS_H_*/
diff --git a/src/sbus/sssd_dbus_connection.c b/src/sbus/sssd_dbus_connection.c
index d0df95bb2..251ff95c5 100644
--- a/src/sbus/sssd_dbus_connection.c
+++ b/src/sbus/sssd_dbus_connection.c
@@ -151,6 +151,7 @@ int sbus_init_connection(TALLOC_CTX *ctx,
struct sbus_connection **_conn)
{
struct sbus_connection *conn;
+ dbus_bool_t dbret;
int ret;
DEBUG(SSSDBG_TRACE_FUNC,"Adding connection %p\n", dbus_conn);
@@ -175,6 +176,14 @@ int sbus_init_connection(TALLOC_CTX *ctx,
return EIO;
}
+ ret = sbus_incoming_signal_hash_init(conn, &conn->incoming_signals);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot create incoming singals "
+ "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");
@@ -188,6 +197,15 @@ int sbus_init_connection(TALLOC_CTX *ctx,
return ret;
}
+ /* Set up signal handler. */
+ dbret = dbus_connection_add_filter(dbus_conn, sbus_signal_handler, conn,
+ NULL);
+ if (dbret == false) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot register signal handler\n");
+ talloc_free(conn);
+ return EIO;
+ }
+
*_conn = conn;
return ret;
}
diff --git a/src/sbus/sssd_dbus_private.h b/src/sbus/sssd_dbus_private.h
index 0493e1536..c125f8b82 100644
--- a/src/sbus/sssd_dbus_private.h
+++ b/src/sbus/sssd_dbus_private.h
@@ -49,6 +49,7 @@ struct sbus_connection {
hash_table_t *managed_paths;
hash_table_t *nodes_fns;
+ hash_table_t *incoming_signals;
/* reconnect settings */
int retries;
@@ -169,4 +170,15 @@ int sbus_get_sender_id_recv(struct tevent_req *req, int64_t *_uid);
int sbus_properties_dispatch(struct sbus_request *dbus_req);
+/* =Signals=============================================================== */
+
+DBusHandlerResult
+sbus_signal_handler(DBusConnection *conn,
+ DBusMessage *message,
+ void *handler_data);
+
+errno_t
+sbus_incoming_signal_hash_init(TALLOC_CTX *mem_ctx,
+ hash_table_t **_table);
+
#endif /* _SSSD_DBUS_PRIVATE_H_ */
diff --git a/src/sbus/sssd_dbus_signals.c b/src/sbus/sssd_dbus_signals.c
new file mode 100644
index 000000000..5ecc9f1f6
--- /dev/null
+++ b/src/sbus/sssd_dbus_signals.c
@@ -0,0 +1,290 @@
+/*
+ Authors:
+ Pavel Březina <pbrezina@redhat.com>
+
+ Copyright (C) 2015 Red Hat
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <talloc.h>
+#include <dbus/dbus.h>
+#include <dhash.h>
+
+#include "util/util.h"
+#include "sbus/sssd_dbus.h"
+#include "sbus/sssd_dbus_private.h"
+
+static int sbus_incoming_signal_destructor(struct sbus_incoming_signal *signal)
+{
+ dbus_message_unref(signal->message);
+ return 0;
+}
+
+static struct sbus_incoming_signal *
+sbus_new_incoming_signal(struct sbus_connection *conn,
+ DBusMessage *message)
+{
+ struct sbus_incoming_signal *signal;
+
+ signal = talloc_zero(conn, struct sbus_incoming_signal);
+ if (signal == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory allocating D-Bus signal\n");
+ return NULL;
+ }
+
+ signal->conn = conn;
+ signal->message = dbus_message_ref(message);
+ signal->interface = dbus_message_get_interface(message);
+ signal->signal = dbus_message_get_member(message);
+ signal->path = dbus_message_get_path(message);
+
+ talloc_set_destructor(signal, sbus_incoming_signal_destructor);
+
+ return signal;
+}
+
+struct sbus_incoming_signal_data {
+ sbus_incoming_signal_fn handler_fn;
+ void *handler_data;
+};
+
+errno_t
+sbus_incoming_signal_hash_init(TALLOC_CTX *mem_ctx,
+ hash_table_t **_table)
+{
+ return sss_hash_create(mem_ctx, 10, _table);
+}
+
+static errno_t
+sbus_incoming_signal_hash_add(hash_table_t *table,
+ const char *iface,
+ const char *signal,
+ sbus_incoming_signal_fn handler_fn,
+ void *handler_data)
+{
+ TALLOC_CTX *tmp_ctx;
+ struct sbus_incoming_signal_data *data;
+ hash_key_t key;
+ hash_value_t value;
+ errno_t ret;
+ bool has_key;
+ int hret;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ key.type = HASH_KEY_STRING;
+ key.str = talloc_asprintf(tmp_ctx, "%s.%s", iface, signal);
+ if (key.str == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ has_key = hash_has_key(table, &key);
+ if (has_key) {
+ ret = EEXIST;
+ goto done;
+ }
+
+ data = talloc_zero(tmp_ctx, struct sbus_incoming_signal_data);
+ if (data == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ data->handler_data = handler_data;
+ data->handler_fn = handler_fn;
+
+ value.type = HASH_VALUE_PTR;
+ value.ptr = data;
+
+ hret = hash_enter(table, &key, &value);
+ if (hret != HASH_SUCCESS) {
+ ret = EIO;
+ goto done;
+ }
+
+ talloc_steal(table, key.str);
+ talloc_steal(table, data);
+
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+static struct sbus_incoming_signal_data *
+sbus_incoming_signal_hash_lookup(hash_table_t *table,
+ const char *iface,
+ const char *signal)
+{
+ struct sbus_incoming_signal_data *data;
+ hash_key_t key;
+ hash_value_t value;
+ int hret;
+
+ key.type = HASH_KEY_STRING;
+ key.str = talloc_asprintf(NULL, "%s.%s", iface, signal);
+ if (key.str == NULL) {
+ return NULL;
+ }
+
+ hret = hash_lookup(table, &key, &value);
+ if (hret == HASH_ERROR_KEY_NOT_FOUND) {
+ data = NULL;
+ goto done;
+ } else if (hret != HASH_SUCCESS) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Unable to search hash table: hret=%d\n", hret);
+ data = NULL;
+ goto done;
+ }
+
+ data = talloc_get_type(value.ptr, struct sbus_incoming_signal_data);
+
+done:
+ talloc_free(key.str);
+ return data;
+}
+
+errno_t
+sbus_signal_listen(struct sbus_connection *conn,
+ const char *iface,
+ const char *signal,
+ sbus_incoming_signal_fn handler_fn,
+ void *handler_data)
+{
+ TALLOC_CTX *tmp_ctx;
+ const char *rule;
+ DBusError error;
+ errno_t ret;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
+ return ENOMEM;
+ }
+
+ dbus_error_init(&error);
+
+ ret = sbus_incoming_signal_hash_add(conn->incoming_signals, iface,
+ signal, handler_fn, handler_data);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to register signal handler "
+ "[%d]: %s\n", ret, sss_strerror(ret));
+ goto done;
+ }
+
+ rule = talloc_asprintf(tmp_ctx, "type='signal',interface='%s',member='%s'",
+ iface, signal);
+ if (rule == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ dbus_bus_add_match(conn->dbus.conn, rule, &error);
+ if (dbus_error_is_set(&error)) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Cannot add D-Bus match rule, cause: %s\n", error.message);
+ ret = EIO;
+ goto done;
+ }
+
+ DEBUG(SSSDBG_TRACE_FUNC, "Listening to signal %s.%s\n", iface, signal);
+
+done:
+ dbus_error_free(&error);
+ talloc_free(tmp_ctx);
+
+ return ret;
+}
+
+static void
+sbus_signal_handler_got_caller_id(struct tevent_req *req);
+
+DBusHandlerResult
+sbus_signal_handler(DBusConnection *dbus_conn,
+ DBusMessage *message,
+ void *handler_data)
+{
+ struct tevent_req *req;
+ struct sbus_connection *conn;
+ struct sbus_incoming_signal *signal;
+ const char *sender;
+ int type;
+
+ type = dbus_message_get_type(message);
+ if (type != DBUS_MESSAGE_TYPE_SIGNAL) {
+ /* We ignore other types here. */
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ conn = talloc_get_type(handler_data, struct sbus_connection);
+ sender = dbus_message_get_sender(message);
+
+ /* we have a valid handler, create D-Bus request */
+ signal = sbus_new_incoming_signal(conn, message);
+ if (signal == NULL) {
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+ }
+
+ DEBUG(SSSDBG_TRACE_INTERNAL, "Received D-Bus signal %s.%s\n",
+ signal->interface, signal->signal);
+
+ /* now get the sender ID */
+ req = sbus_get_sender_id_send(signal, conn->ev, conn, sender);
+ if (req == NULL) {
+ talloc_free(signal);
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+ }
+ tevent_req_set_callback(req, sbus_signal_handler_got_caller_id, signal);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static void
+sbus_signal_handler_got_caller_id(struct tevent_req *req)
+{
+ struct sbus_incoming_signal_data *signal_data;
+ struct sbus_incoming_signal *signal;
+ errno_t ret;
+
+ signal = tevent_req_callback_data(req, struct sbus_incoming_signal);
+
+ ret = sbus_get_sender_id_recv(req, &signal->client);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Failed to resolve caller's ID: %s\n", sss_strerror(ret));
+ goto done;
+ }
+
+ signal_data = sbus_incoming_signal_hash_lookup(
+ signal->conn->incoming_signals,
+ signal->interface,
+ signal->signal);
+ if (signal_data == NULL) {
+ DEBUG(SSSDBG_MINOR_FAILURE, "Received signal %s.%s that we are "
+ "not listening to.\n", signal->interface, signal->signal);
+ goto done;
+ }
+
+ signal_data->handler_fn(signal, signal_data->handler_data);
+
+done:
+ talloc_free(signal);
+}