From 73f7183c9d244e7cdbe5c7ec91677b64a5f08e8e Mon Sep 17 00:00:00 2001 From: Stephen Gallagher Date: Mon, 3 Nov 2008 09:50:19 -0500 Subject: Renaming sssd/server/dbus to sssd/server/sbus. Making necessary changes to header includes and makefiles. --- server/dbus/sssd_dbus.h | 86 ------ server/dbus/sssd_dbus_common.c | 45 --- server/dbus/sssd_dbus_connection.c | 576 ------------------------------------- server/dbus/sssd_dbus_private.h | 14 - server/dbus/sssd_dbus_server.c | 316 -------------------- server/dbus/tests/test_client.c | 223 -------------- server/monitor.c | 2 +- server/sbus/sssd_dbus.h | 86 ++++++ server/sbus/sssd_dbus_common.c | 45 +++ server/sbus/sssd_dbus_connection.c | 576 +++++++++++++++++++++++++++++++++++++ server/sbus/sssd_dbus_private.h | 14 + server/sbus/sssd_dbus_server.c | 316 ++++++++++++++++++++ server/sbus/tests/test_client.c | 223 ++++++++++++++ server/server.mk | 12 +- 14 files changed, 1267 insertions(+), 1267 deletions(-) delete mode 100644 server/dbus/sssd_dbus.h delete mode 100644 server/dbus/sssd_dbus_common.c delete mode 100644 server/dbus/sssd_dbus_connection.c delete mode 100644 server/dbus/sssd_dbus_private.h delete mode 100644 server/dbus/sssd_dbus_server.c delete mode 100644 server/dbus/tests/test_client.c create mode 100644 server/sbus/sssd_dbus.h create mode 100644 server/sbus/sssd_dbus_common.c create mode 100644 server/sbus/sssd_dbus_connection.c create mode 100644 server/sbus/sssd_dbus_private.h create mode 100644 server/sbus/sssd_dbus_server.c create mode 100644 server/sbus/tests/test_client.c diff --git a/server/dbus/sssd_dbus.h b/server/dbus/sssd_dbus.h deleted file mode 100644 index 1bd062d42..000000000 --- a/server/dbus/sssd_dbus.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - SSSD - - SSSD - D-BUS interface - - Copyright (C) Stephen Gallagher 2008 - - 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 . -*/ - -#ifndef _SSSD_DBUS_H_ -#define _SSSD_DBUS_H_ -struct sbus_conn_ctx; -typedef int (*sbus_msg_handler_fn)(DBusMessage *msg, void *data, - DBusMessage **reply); - -/* - * sbus_conn_destructor_fn - * Function to be called when a connection is finalized - */ -typedef int (*sbus_conn_destructor_fn)( - void *ctx); - -/* - * sbus_server_conn_init_fn - * Set up function for connection-specific activities - * This function should define the sbus_conn_destructor_fn - * for this connection at a minimum - */ -typedef int (*sbus_server_conn_init_fn)( - struct sbus_conn_ctx *dct_ctx); - -enum { - SBUS_CONN_TYPE_PRIVATE = 1, - SBUS_CONN_TYPE_SHARED -}; - -struct sbus_method { - const char *method; - sbus_msg_handler_fn fn; -}; - -struct sbus_method_ctx { - struct sbus_method_ctx *prev, *next; - /*struct event_context *ev;*/ - char *interface; - char *path; - - /* If a non-default message_handler is desired, set it in this - * object before calling sbus_conn_add_method_ctx() - * Otherwise it will default to message_handler() in - * sssd_dbus_connection.c - */ - DBusObjectPathMessageFunction message_handler; - struct sbus_method *methods; -}; - -/* Server Functions */ -int sbus_new_server(struct event_context *ev, struct sbus_method_ctx *ctx, const char *address, sbus_server_conn_init_fn init_fn); - -/* Connection Functions */ -int sbus_new_connection(TALLOC_CTX *ctx, struct event_context *ev, const char *address, - struct sbus_conn_ctx **dct_ctx, - sbus_conn_destructor_fn destructor); - -void sbus_conn_set_destructor(struct sbus_conn_ctx *dct_ctx, - sbus_conn_destructor_fn destructor); -int sbus_default_connection_destructor(void *ctx); - -DBusConnection *sbus_get_connection(struct sbus_conn_ctx *dct_ctx); -void sbus_disconnect (struct sbus_conn_ctx *dct_ctx); -void sbus_conn_set_private_data(struct sbus_conn_ctx *dct_ctx, void *private); -int sbus_conn_add_method_ctx(struct sbus_conn_ctx *dct_ctx, struct sbus_method_ctx *method_ctx); - -#endif /* _SSSD_DBUS_H_*/ diff --git a/server/dbus/sssd_dbus_common.c b/server/dbus/sssd_dbus_common.c deleted file mode 100644 index 0ea66ccb3..000000000 --- a/server/dbus/sssd_dbus_common.c +++ /dev/null @@ -1,45 +0,0 @@ -#include -#include "events.h" -#include "dbus/dbus.h" -#include "util/util.h" - -struct timeval _dbus_timeout_get_interval_tv(int interval) { - struct timeval tv; - struct timeval rightnow; - - gettimeofday(&rightnow,NULL); - - tv.tv_sec = interval / 1000 + rightnow.tv_sec; - tv.tv_usec = (interval % 1000) * 1000 + rightnow.tv_usec; - return tv; -} - -/* - * sbus_remove_watch - * Hook for D-BUS to remove file descriptor-based events - * from the libevents mainloop - */ -void sbus_remove_watch(DBusWatch *watch, void *data) { - struct fd_event *fde; - - DEBUG(2, ("%lX\n", watch)); - fde = talloc_get_type(dbus_watch_get_data(watch), struct fd_event); - - /* Freeing the event object will remove it from the event loop */ - talloc_free(fde); - dbus_watch_set_data(watch, NULL, NULL); -} - - -/* - * sbus_remove_timeout - * Hook for D-BUS to remove time-based events from the mainloop - */ -void sbus_remove_timeout(DBusTimeout *timeout, void *data) { - struct timed_event *te; - te = talloc_get_type(dbus_timeout_get_data(timeout), struct timed_event); - - /* Freeing the event object will remove it from the event loop */ - talloc_free(te); - dbus_timeout_set_data(timeout, NULL, NULL); -} diff --git a/server/dbus/sssd_dbus_connection.c b/server/dbus/sssd_dbus_connection.c deleted file mode 100644 index 3a169f794..000000000 --- a/server/dbus/sssd_dbus_connection.c +++ /dev/null @@ -1,576 +0,0 @@ -#include -#include "events.h" -#include "util/util.h" -#include "dbus/dbus.h" -#include "dbus/sssd_dbus.h" -#include "dbus/sssd_dbus_private.h" - -/* Types */ -struct dbus_ctx_list; - -struct sbus_conn_ctx { - DBusConnection *conn; - struct event_context *ev; - int connection_type; - int disconnect; - struct sbus_method_ctx *method_ctx_list; - sbus_conn_destructor_fn destructor; - void *private; /* Private data for this connection */ -}; - -struct sbus_conn_watch_ctx { - DBusWatch *watch; - int fd; - struct fd_event *fde; - struct sbus_conn_ctx *top; -}; - -struct sbus_conn_timeout_ctx { - DBusTimeout *timeout; - struct timed_event *te; - struct sbus_conn_ctx *top; -}; - -static int _method_list_contains_path(struct sbus_method_ctx *list, struct sbus_method_ctx *method); -static void sbus_unreg_object_paths(struct sbus_conn_ctx *dct_ctx); - -static void sbus_dispatch(struct event_context *ev, - struct timed_event *te, - struct timeval tv, void *data) -{ - struct timed_event *new_event; - struct sbus_conn_ctx *dct_ctx; - DBusConnection *conn; - int ret; - - if (data == NULL) { - return; - } - - dct_ctx = talloc_get_type(data, struct sbus_conn_ctx); - - conn = dct_ctx->conn; - DEBUG(3, ("conn: %lX\n", conn)); - - if((dct_ctx->disconnect) || (!dbus_connection_get_is_connected(conn))) { - DEBUG(0,("Connection is not open for dispatching.\n")); - /* - * Free the connection object. - * This will invoke the destructor for the connection - */ - talloc_free(dct_ctx); - dct_ctx = NULL; - return; - } - - /* Dispatch only once each time through the mainloop to avoid - * starving other features - */ - ret = dbus_connection_get_dispatch_status(conn); - if (ret != DBUS_DISPATCH_COMPLETE) { - DEBUG(2,("Dispatching.\n")); - dbus_connection_dispatch(conn); - } - - /* If other dispatches are waiting, queue up the do_dispatch function - * for the next loop. - */ - ret = dbus_connection_get_dispatch_status(conn); - if (ret != DBUS_DISPATCH_COMPLETE) { - new_event = event_add_timed(ev, dct_ctx, tv, sbus_dispatch, dct_ctx); - if (new_event == NULL) { - DEBUG(0,("Could not add dispatch event!\n")); - - /* TODO: Calling exit here is bad */ - exit(1); - } - } -} - -/* - * dbus_connection_read_write_handler - * Callback for D-BUS to handle messages on a file-descriptor - */ -static void sbus_conn_read_write_handler(struct event_context *ev, - struct fd_event *fde, - uint16_t flags, void *data) -{ - struct sbus_conn_watch_ctx *conn_w_ctx; - conn_w_ctx = talloc_get_type(data, struct sbus_conn_watch_ctx); - - DEBUG(0,("Connection is open for read/write.\n")); - dbus_connection_ref(conn_w_ctx->top->conn); - if (flags & EVENT_FD_READ) { - dbus_watch_handle(conn_w_ctx->watch, DBUS_WATCH_READABLE); - } - if (flags & EVENT_FD_WRITE) { - dbus_watch_handle(conn_w_ctx->watch, DBUS_WATCH_WRITABLE); - } - dbus_connection_unref(conn_w_ctx->top->conn); -} - -/* - * add_connection_watch - * Set up hooks into the libevents mainloop for - * D-BUS to add file descriptor-based events - */ -static dbus_bool_t sbus_add_conn_watch(DBusWatch *watch, void *data) -{ - unsigned int flags; - unsigned int event_flags; - struct sbus_conn_ctx *dt_ctx; - struct sbus_conn_watch_ctx *conn_w_ctx; - - if (!dbus_watch_get_enabled(watch)) { - return TRUE; - } - - dt_ctx = talloc_get_type(data, struct sbus_conn_ctx); - - conn_w_ctx = talloc_zero(dt_ctx, struct sbus_conn_watch_ctx); - conn_w_ctx->top = dt_ctx; - conn_w_ctx->watch = watch; - - flags = dbus_watch_get_flags(watch); - conn_w_ctx->fd = dbus_watch_get_unix_fd(watch); - - event_flags = 0; - - if (flags & DBUS_WATCH_READABLE) - event_flags |= EVENT_FD_READ; - - if (flags & DBUS_WATCH_WRITABLE) - event_flags |= EVENT_FD_WRITE; - - if (event_flags == 0) - return FALSE; - - DEBUG(2,("%lX: %d, %d=%s\n", watch, conn_w_ctx->fd, event_flags, event_flags==EVENT_FD_READ?"READ":"WRITE")); - - /* Add the file descriptor to the event loop */ - conn_w_ctx->fde = event_add_fd(conn_w_ctx->top->ev, conn_w_ctx, - conn_w_ctx->fd, event_flags, - sbus_conn_read_write_handler, - conn_w_ctx); - - /* Save the event to the watch object so it can be removed later */ - dbus_watch_set_data(conn_w_ctx->watch,conn_w_ctx->fde,NULL); - - return TRUE; -} - -/* - * toggle_connection_watch - * Hook for D-BUS to toggle the enabled/disabled state of - * an event in the mainloop - */ -static void sbus_toggle_conn_watch(DBusWatch *watch, void *data) -{ - if (dbus_watch_get_enabled(watch)) { - sbus_add_conn_watch(watch, data); - } else { - sbus_remove_watch(watch, data); - } -} - -/* - * dbus_connection_timeout_handler - * Callback for D-BUS to handle timed events - */ -static void sbus_conn_timeout_handler(struct event_context *ev, - struct timed_event *te, - struct timeval t, void *data) -{ - struct sbus_conn_timeout_ctx *conn_t_ctx; - conn_t_ctx = talloc_get_type(data, struct sbus_conn_timeout_ctx); - - dbus_timeout_handle(conn_t_ctx->timeout); -} - - -/* - * add_connection_timeout - * Hook for D-BUS to add time-based events to the mainloop - */ -static dbus_bool_t sbus_add_conn_timeout(DBusTimeout *timeout, void *data) -{ - struct sbus_conn_ctx *dt_ctx; - struct sbus_conn_timeout_ctx *conn_t_ctx; - struct timeval tv; - - if (!dbus_timeout_get_enabled(timeout)) - return TRUE; - - dt_ctx = talloc_get_type(data, struct sbus_conn_ctx); - - conn_t_ctx = talloc_zero(dt_ctx,struct sbus_conn_timeout_ctx); - conn_t_ctx->top = dt_ctx; - conn_t_ctx->timeout = timeout; - - tv = _dbus_timeout_get_interval_tv(dbus_timeout_get_interval(timeout)); - - struct timeval rightnow; - gettimeofday(&rightnow, NULL); - - conn_t_ctx->te = event_add_timed(conn_t_ctx->top->ev, conn_t_ctx, tv, - sbus_conn_timeout_handler, conn_t_ctx); - - /* Save the event to the watch object so it can be removed later */ - dbus_timeout_set_data(conn_t_ctx->timeout,conn_t_ctx->te,NULL); - - return TRUE; -} - -/* - * sbus_toggle_conn_timeout - * Hook for D-BUS to toggle the enabled/disabled state of a mainloop - * event - */ -void sbus_toggle_conn_timeout(DBusTimeout *timeout, void *data) -{ - if (dbus_timeout_get_enabled(timeout)) { - sbus_add_conn_timeout(timeout, data); - } else { - sbus_remove_timeout(timeout, data); - } -} - -/* dbus_connection_wakeup_main - * D-BUS makes a callback to the wakeup_main function when - * it has data available for dispatching. - * In order to avoid blocking, this function will create a now() - * timed event to perform the dispatch during the next iteration - * through the mainloop - */ -static void sbus_conn_wakeup_main(void *data) { - struct sbus_conn_ctx *dct_ctx; - struct timeval tv; - struct timed_event *te; - - dct_ctx = talloc_get_type(data, struct sbus_conn_ctx); - gettimeofday(&tv, NULL); - - /* D-BUS calls this function when it is time to do a dispatch */ - te = event_add_timed(dct_ctx->ev, dct_ctx, - tv, sbus_dispatch, dct_ctx); - if (te == NULL) { - DEBUG(0,("Could not add dispatch event!\n")); - exit(1); - } -} - -/* - * integrate_connection_with_event_loop - * Set up a D-BUS connection to use the libevents mainloop - * for handling file descriptor and timed events - */ -int sbus_add_connection(TALLOC_CTX *ctx, - struct event_context *ev, - DBusConnection *dbus_conn, - struct sbus_conn_ctx **dct_ctx, - int connection_type) -{ - dbus_bool_t dbret; - struct sbus_conn_ctx *dt_ctx; - - DEBUG(0,("Adding connection %lX\n", dbus_conn)); - dt_ctx = talloc_zero(ctx, struct sbus_conn_ctx); - dt_ctx->ev = ev; - dt_ctx->conn = dbus_conn; - dt_ctx->connection_type = connection_type; - dt_ctx->disconnect = 0; - /* This will be replaced on the first call to sbus_conn_add_method_ctx() */ - dt_ctx->method_ctx_list = NULL; - - /* - * Set the default destructor - * Connections can override this with - * sbus_conn_set_destructor - */ - sbus_conn_set_destructor(dt_ctx, NULL); - - /* Set up DBusWatch functions */ - dbret = dbus_connection_set_watch_functions(dt_ctx->conn, - sbus_add_conn_watch, - sbus_remove_watch, - sbus_toggle_conn_watch, - dt_ctx, NULL); - if (!dbret) { - DEBUG(0,("Error setting up D-BUS connection watch functions\n")); - return EIO; - } - - /* Set up DBusTimeout functions */ - dbret = dbus_connection_set_timeout_functions(dt_ctx->conn, - sbus_add_conn_timeout, - sbus_remove_timeout, - sbus_toggle_conn_timeout, - dt_ctx, NULL); - if (!dbret) { - DEBUG(0,("Error setting up D-BUS server timeout functions\n")); - /* FIXME: free resources ? */ - return EIO; - } - - /* Set up dispatch handler */ - dbus_connection_set_wakeup_main_function(dt_ctx->conn, - sbus_conn_wakeup_main, - dt_ctx, NULL); - - /* Set up any method_contexts passed in */ - - /* Attempt to dispatch immediately in case of opportunistic - * services connecting before the handlers were all up. - * If there are no messages to be dispatched, this will do - * nothing. - */ - sbus_conn_wakeup_main(dt_ctx); - - /* Return the new toplevel object */ - *dct_ctx = dt_ctx; - - return EOK; -} - -/*int sbus_new_connection(struct sbus_method_ctx *ctx, const char *address, - DBusConnection **connection, - sbus_conn_destructor_fn destructor)*/ -int sbus_new_connection(TALLOC_CTX *ctx, struct event_context *ev, const char *address, - struct sbus_conn_ctx **dct_ctx, - sbus_conn_destructor_fn destructor) -{ - DBusConnection *dbus_conn; - DBusError dbus_error; - int ret; - - dbus_error_init(&dbus_error); - - /* Open a shared D-BUS connection to the address */ - dbus_conn = dbus_connection_open(address, &dbus_error); - if (!dbus_conn) { - DEBUG(0, ("Failed to open connection: name=%s, message=%s\n", - dbus_error.name, dbus_error.message)); - return EIO; - } - - ret = sbus_add_connection(ctx, ev, dbus_conn, dct_ctx, SBUS_CONN_TYPE_SHARED); - if (ret != EOK) { - /* FIXME: release resources */ - } - - dbus_connection_set_exit_on_disconnect((*dct_ctx)->conn, FALSE); - - /* Set connection destructor */ - sbus_conn_set_destructor(*dct_ctx, destructor); - - return ret; -} - -/* - * sbus_conn_set_destructor - * Configures a callback to clean up this connection when it - * is finalized. - * @param dct_ctx The sbus_conn_ctx created - * when this connection was established - * @param destructor The destructor function that should be - * called when the connection is finalized. If passed NULL, - * this will reset the connection to the default destructor. - */ -void sbus_conn_set_destructor(struct sbus_conn_ctx *dct_ctx, - sbus_conn_destructor_fn destructor) { - if (!dct_ctx) { - return; - } - - dct_ctx->destructor = destructor; - /* TODO: Should we try to handle the talloc_destructor too? */ -} - -int sbus_default_connection_destructor(void *ctx) { - struct sbus_conn_ctx *dct_ctx; - dct_ctx = talloc_get_type(ctx, struct sbus_conn_ctx); - - DEBUG(3, ("Invoking default destructor on connection %lX\n", dct_ctx->conn)); - if (dct_ctx->connection_type == SBUS_CONN_TYPE_PRIVATE) { - /* Private connections must be closed explicitly */ - dbus_connection_close(dct_ctx->conn); - } else if (dct_ctx->connection_type == SBUS_CONN_TYPE_SHARED) { - /* Shared connections are destroyed when their last reference is removed */ - } - else { - /* Critical Error! */ - DEBUG(0,("Critical Error, connection_type is neither shared nor private!\n")); - return -1; - } - - /* Remove object path */ - /* TODO: Remove object paths */ - - - dbus_connection_unref(dct_ctx->conn); - return 0; -} - -/* - * sbus_get_connection - * Utility function to retreive the DBusConnection object - * from a sbus_conn_ctx - */ -DBusConnection *sbus_get_connection(struct sbus_conn_ctx *dct_ctx) { - return dct_ctx->conn; -} - -void sbus_disconnect (struct sbus_conn_ctx *dct_ctx) { - if (dct_ctx == NULL) { - return; - } - - DEBUG(2,("Disconnecting %lX\n", dct_ctx->conn)); - dbus_connection_ref(dct_ctx->conn); - dct_ctx->disconnect = 1; - - /* Invoke the custom destructor, if it exists */ - if(dct_ctx->destructor) { - dct_ctx->destructor(dct_ctx); - } - - /* Unregister object paths */ - sbus_unreg_object_paths(dct_ctx); - - /* Disable watch functions */ - dbus_connection_set_watch_functions(dct_ctx->conn, - NULL, NULL, NULL, - NULL, NULL); - /* Disable timeout functions */ - dbus_connection_set_timeout_functions(dct_ctx->conn, - NULL, NULL, NULL, - NULL, NULL); - - /* Disable dispatch status function */ - dbus_connection_set_dispatch_status_function(dct_ctx->conn, NULL, NULL, NULL); - - /* Disable wakeup main function */ - dbus_connection_set_wakeup_main_function(dct_ctx->conn, NULL, NULL, NULL); - - /* Finalize the connection */ - sbus_default_connection_destructor(dct_ctx); - dbus_connection_unref(dct_ctx->conn); - DEBUG(2,("Disconnected %lX\n", dct_ctx->conn)); -} - -/* messsage_handler - * Receive messages and process them - */ -static DBusHandlerResult message_handler(DBusConnection *conn, - DBusMessage *message, - void *user_data) -{ - struct sbus_method_ctx *ctx; - const char *method; - const char *path; - const char *msg_interface; - DBusMessage *reply = NULL; - int i, ret; - - ctx = talloc_get_type(user_data, struct sbus_method_ctx); - - method = dbus_message_get_member(message); - path = dbus_message_get_path(message); - msg_interface = dbus_message_get_interface(message); - - if (!method || !path || !msg_interface) - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - - /* Validate the method interface */ - if (strcmp(msg_interface, ctx->interface) != 0) - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - - /* Validate the D-BUS path */ - if (strcmp(path, ctx->path) == 0) { - for (i = 0; ctx->methods[i].method != NULL; i++) { - if (strcmp(method, ctx->methods[i].method) == 0) { - ret = ctx->methods[i].fn(message, ctx, &reply); - /* FIXME: check error */ - break; - } - } - /* FIXME: check if we didn't find any matching method */ - } - - DEBUG(2, ("Method %s complete. Reply was %srequested.\n", method, reply?"":"not ")); - - if (reply) { - dbus_connection_send(conn, reply, NULL); - dbus_message_unref(reply); - } - - return reply ? DBUS_HANDLER_RESULT_HANDLED : - DBUS_HANDLER_RESULT_NOT_YET_HANDLED; -} - -/* Adds a new D-BUS path message handler to the connection - * Note: this must be a unique path. - */ -int sbus_conn_add_method_ctx(struct sbus_conn_ctx *dct_ctx, struct sbus_method_ctx *method_ctx) { - DBusObjectPathVTable *connection_vtable; - dbus_bool_t dbret; - if (!method_ctx) { - return EINVAL; - } - - if (_method_list_contains_path(dct_ctx->method_ctx_list, method_ctx)) { - return EINVAL; - } - - DLIST_ADD(dct_ctx->method_ctx_list, method_ctx); - - /* Set up the vtable for the object path */ - connection_vtable = talloc_zero(dct_ctx, DBusObjectPathVTable); - if (method_ctx->message_handler) { - connection_vtable->message_function = method_ctx->message_handler; - } else { - connection_vtable->message_function = message_handler; - } - - dbret = dbus_connection_register_object_path(dct_ctx->conn, method_ctx->path, connection_vtable, method_ctx); - if (!dbret) { - return ENOMEM; - } - - return EOK; -} - -static int _method_list_contains_path(struct sbus_method_ctx *list, struct sbus_method_ctx *method) { - struct sbus_method_ctx *iter; - - if (!list || !method) { - return 0; /* FALSE */ - } - - iter = list; - while (iter != NULL) { - if (strcmp(iter->path, method->path) == 0) - return 1; /* TRUE */ - - iter = iter->next; - } - - return 0; /* FALSE */ -} - -static void sbus_unreg_object_paths(struct sbus_conn_ctx *dct_ctx) { - struct sbus_method_ctx *iter = dct_ctx->method_ctx_list; - struct sbus_method_ctx *purge; - - while(iter != NULL) { - dbus_connection_unregister_object_path(dct_ctx->conn, iter->path); - DLIST_REMOVE(dct_ctx->method_ctx_list, iter); - purge = iter; - iter = iter->next; - talloc_free(purge); - } -} - -void sbus_conn_set_private_data(struct sbus_conn_ctx *dct_ctx, void *private) { - dct_ctx->private = private; -} diff --git a/server/dbus/sssd_dbus_private.h b/server/dbus/sssd_dbus_private.h deleted file mode 100644 index d102c8c9d..000000000 --- a/server/dbus/sssd_dbus_private.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef _SSSD_DBUS_PRIVATE_H_ -#define _SSSD_DBUS_PRIVATE_H_ - -int sbus_add_connection(TALLOC_CTX *ctx, - struct event_context *ev, - DBusConnection *dbus_conn, - struct sbus_conn_ctx **dct_ctx, - int connection_type); - -struct timeval _dbus_timeout_get_interval_tv(int interval); -void sbus_remove_watch(DBusWatch *watch, void *data); -void sbus_remove_timeout(DBusTimeout *timeout, void *data); - -#endif /* _SSSD_DBUS_PRIVATE_H_ */ diff --git a/server/dbus/sssd_dbus_server.c b/server/dbus/sssd_dbus_server.c deleted file mode 100644 index 633e4b7ec..000000000 --- a/server/dbus/sssd_dbus_server.c +++ /dev/null @@ -1,316 +0,0 @@ -/* - SSSD - - Service monitor - D-BUS features - - Copyright (C) Stephen Gallagher 2008 - - 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 . -*/ -#include -#include "events.h" -#include "util/util.h" -#include "dbus/dbus.h" -#include "dbus/sssd_dbus.h" -#include "dbus/sssd_dbus_private.h" - -/* Types */ -struct sbus_srv_ctx { - DBusServer *server; - /* - * sd_ctx here describes the object path that will be - * presented to all clients of this server. Additional - * connection-specific paths can be specified by the - * init_fn, which is called every time a new connection - * is established. - * There should only be one global object path (for - * simplicity's sake) - */ - struct event_context *ev; - struct sbus_method_ctx *sd_ctx; - sbus_server_conn_init_fn init_fn; -}; - -struct sbus_srv_watch_ctx { - DBusWatch *watch; - int fd; - struct fd_event *fde; - struct sbus_srv_ctx *top; -}; - -struct dbus_srv_timeout_ctx { - DBusTimeout *timeout; - struct timed_event *te; - struct sbus_srv_ctx *top; -}; - -static int sbus_server_destructor(void **server); - -/* - * dbus_server_read_write_handler - * Callback for D-BUS to handle messages on a file-descriptor - */ -static void sbus_srv_read_write_handler(struct event_context *ev, - struct fd_event *fde, - uint16_t flags, void *data) -{ - struct sbus_srv_watch_ctx *svw_ctx; - svw_ctx = talloc_get_type(data, struct sbus_srv_watch_ctx); - - dbus_server_ref(svw_ctx->top->server); - if (flags & EVENT_FD_READ) { - dbus_watch_handle(svw_ctx->watch, DBUS_WATCH_READABLE); - } - if (flags & EVENT_FD_WRITE) { - dbus_watch_handle(svw_ctx->watch, DBUS_WATCH_WRITABLE); - } - dbus_server_unref(svw_ctx->top->server); -} - -/* - * add_server_watch - * Set up hooks into the libevents mainloop for - * D-BUS to add file descriptor-based events - */ -static dbus_bool_t sbus_add_srv_watch(DBusWatch *watch, void *data) -{ - unsigned int flags; - unsigned int event_flags; - struct sbus_srv_ctx *dt_ctx; - struct sbus_srv_watch_ctx *svw_ctx; - - if (!dbus_watch_get_enabled(watch)) { - return FALSE; - } - - dt_ctx = talloc_get_type(data, struct sbus_srv_ctx); - - svw_ctx = talloc_zero(dt_ctx, struct sbus_srv_watch_ctx); - svw_ctx->top = dt_ctx; - svw_ctx->watch = watch; - - flags = dbus_watch_get_flags(watch); - svw_ctx->fd = dbus_watch_get_unix_fd(watch); - - event_flags = 0; - - if (flags & DBUS_WATCH_READABLE) { - event_flags |= EVENT_FD_READ; - } - - if (flags & DBUS_WATCH_WRITABLE) { - event_flags |= EVENT_FD_WRITE; - } - DEBUG(2,("%lX: %d, %d=%s\n", watch, svw_ctx->fd, event_flags, event_flags==EVENT_FD_READ?"READ":"WRITE")); - - svw_ctx->fde = event_add_fd(dt_ctx->ev, svw_ctx, svw_ctx->fd, - event_flags, sbus_srv_read_write_handler, - svw_ctx); - - /* Save the event to the watch object so it can be removed later */ - dbus_watch_set_data(svw_ctx->watch, svw_ctx->fde, NULL); - - return TRUE; -} - -/* - * server_watch_toggled - * Hook for D-BUS to toggle the enabled/disabled state of - * an event in the mainloop - */ -static void sbus_toggle_srv_watch(DBusWatch *watch, void *data) -{ - if (dbus_watch_get_enabled(watch)) { - sbus_add_srv_watch(watch, data); - } else { - sbus_remove_watch(watch, data); - } -} - -static void sbus_srv_timeout_handler(struct event_context *ev, - struct timed_event *te, - struct timeval t, void *data) -{ - struct dbus_srv_timeout_ctx *svt_ctx; - svt_ctx = talloc_get_type(data, struct dbus_srv_timeout_ctx); - dbus_timeout_handle(svt_ctx->timeout); -} - -/* - * add_server_timeout - * Hook for D-BUS to add time-based events to the mainloop - */ -static dbus_bool_t sbus_add_srv_timeout(DBusTimeout *timeout, void *data) -{ - struct sbus_srv_ctx *dt_ctx; - struct dbus_srv_timeout_ctx *svt_ctx; - struct timeval tv; - - if (!dbus_timeout_get_enabled(timeout)) - return TRUE; - - dt_ctx = talloc_get_type(data, struct sbus_srv_ctx); - - svt_ctx = talloc_zero(dt_ctx,struct dbus_srv_timeout_ctx); - svt_ctx->top = dt_ctx; - svt_ctx->timeout = timeout; - - tv = _dbus_timeout_get_interval_tv(dbus_timeout_get_interval(timeout)); - - svt_ctx->te = event_add_timed(dt_ctx->ev, svt_ctx, tv, - sbus_srv_timeout_handler, svt_ctx); - - /* Save the event to the watch object so it can be removed later */ - dbus_timeout_set_data(svt_ctx->timeout, svt_ctx->te, NULL); - - return TRUE; -} - -/* - * server_timeout_toggled - * Hook for D-BUS to toggle the enabled/disabled state of a mainloop - * event - */ -static void sbus_toggle_srv_timeout(DBusTimeout *timeout, void *data) -{ - if (dbus_timeout_get_enabled(timeout)) { - sbus_add_srv_timeout(timeout, data); - } else { - sbus_remove_timeout(timeout, data); - } -} - -/* - * new_connection_callback - * Actions to be run upon each new client connection - * Must either perform dbus_connection_ref() on the - * new connection or else close the connection with - * dbus_connection_close() - */ -static void sbus_server_init_new_connection(DBusServer *server, DBusConnection *conn, - void *data) -{ - struct sbus_srv_ctx *dst_ctx; - struct sbus_conn_ctx *dct_ctx; - struct sbus_method_ctx *iter; - - /*DBusObjectPathVTable *connection_vtable;*/ - int ret; - DEBUG(0,("Entering.\n")); - dst_ctx = talloc_get_type(data,struct sbus_srv_ctx); - if(dst_ctx == NULL) { - return; - } - - DEBUG(0,("Adding connection %lX.\n", conn)); - ret = sbus_add_connection(dst_ctx, dst_ctx->ev, conn, &dct_ctx, SBUS_CONN_TYPE_PRIVATE); - if (ret != 0) { - dbus_connection_close(conn); - DEBUG(0,("Closing connection (failed setup)")); - return; - } - - dbus_connection_ref(conn); - - DEBUG(3,("Got a connection\n")); - - /* Set up global methods */ - iter = dst_ctx->sd_ctx; - while (iter != NULL) { - sbus_conn_add_method_ctx(dct_ctx, iter); - iter = iter->next; - } - - /* - * Initialize connection-specific features - * This may set a more detailed destructor, but - * the default destructor will always be chained - * to handle connection cleanup. - * This function (or its callbacks) should also - * set up connection-specific methods. - */ - dst_ctx->init_fn(dct_ctx); -} - -/* - * dbus_new_server - * Set up a D-BUS server, integrate with the event loop - * for handling file descriptor and timed events - */ -int sbus_new_server(struct event_context *ev, struct sbus_method_ctx *ctx, const char *address, sbus_server_conn_init_fn init_fn) -{ - struct sbus_srv_ctx *dst_ctx; - DBusServer *dbus_server; - DBusServer **dbus_server_talloc; - DBusError dbus_error; - dbus_bool_t dbret; - - /* Set up D-BUS server */ - dbus_error_init(&dbus_error); - dbus_server = dbus_server_listen(address, &dbus_error); - if (!dbus_server) { - DEBUG(0,("dbus_server_listen failed! (name=%s, message=%s)\n", - dbus_error.name, dbus_error.message)); - return EIO; - } - - DEBUG(2, ("D-BUS Server listening on %s\n", - dbus_server_get_address(dbus_server))); - - dst_ctx = talloc_zero(ev, struct sbus_srv_ctx); - if (!dst_ctx) { - return ENOMEM; - } - - dbus_server_talloc = talloc_takeover(ctx, dbus_server, sbus_server_destructor); - dst_ctx->ev = ev; - dst_ctx->server = dbus_server; - dst_ctx->sd_ctx = ctx; - dst_ctx->init_fn = init_fn; - - /* Set up D-BUS new connection handler */ - dbus_server_set_new_connection_function(dst_ctx->server, - sbus_server_init_new_connection, - dst_ctx, NULL); - - /* Set up DBusWatch functions */ - dbret = dbus_server_set_watch_functions(dst_ctx->server, sbus_add_srv_watch, - sbus_remove_watch, sbus_toggle_srv_watch, - dst_ctx, NULL); - if (!dbret) { - DEBUG(0, ("Error setting up D-BUS server watch functions")); - talloc_free(dst_ctx); - return EIO; - } - - /* Set up DBusTimeout functions */ - dbret = dbus_server_set_timeout_functions(dst_ctx->server, - sbus_add_srv_timeout, - sbus_remove_timeout, - sbus_toggle_srv_timeout, - dst_ctx, NULL); - if (!dbret) { - DEBUG(0,("Error setting up D-BUS server timeout functions")); - dbus_server_set_watch_functions(dst_ctx->server, NULL, NULL, NULL, NULL, NULL); - talloc_free(dst_ctx); - return EIO; - } - - return EOK; -} - -static int sbus_server_destructor(void **server) { - dbus_server_disconnect(*server); - return 0; -} diff --git a/server/dbus/tests/test_client.c b/server/dbus/tests/test_client.c deleted file mode 100644 index 34e740185..000000000 --- a/server/dbus/tests/test_client.c +++ /dev/null @@ -1,223 +0,0 @@ -#include -#include -#include -#include "events.h" -#include "util/util.h" -#include "dbus/dbus.h" -#include "dbus/sssd_dbus.h" - -/* TODO: get this value from LDB */ -#define DBUS_ADDRESS "unix:path=/var/lib/sss/pipes/private/dbus" - -/* Identity */ -#define TEST_CLIENT_NAME "testclient" -#define TEST_CLIENT_VERSION 1 - -/* Monitor Interface */ -#define MONITOR_DBUS_INTERFACE "org.freeipa.sssd.monitor" -#define MONITOR_DBUS_PATH "/org/freeipa/sssd/monitor" -#define MONITOR_METHOD_VERSION "getVersion" - -/* Service Interface */ -#define SERVICE_PATH "/org/freeipa/sssd/service" -#define SERVICE_INTERFACE "org.freeipa.sssd.service" -#define SERVICE_METHOD_IDENTITY "getIdentity" - -struct test_cli_ctx { - struct sbus_method_ctx *sd_ctx; - /*DBusConnection *conn;*/ - struct event_context *ev; - struct sbus_conn_ctx *dct_ctx; -}; - -static int provide_identity(DBusMessage *message, void *data, DBusMessage **r); - -struct sbus_method monitor_service_methods [] = { - {SERVICE_METHOD_IDENTITY, provide_identity}, - {NULL, NULL} -}; - -static void request_version_timed(struct test_cli_ctx *ctx); - -static void print_version(DBusPendingCall *pending, void *data) -{ - DBusMessage *reply; - DBusError error; - const char *version_string; - int type; - - dbus_error_init(&error); - - reply = dbus_pending_call_steal_reply(pending); - if (!reply) { - /* reply should never be null. This function shouldn't be called - * until reply is valid. If reply is NULL here, something is seriously - * wrong and we should bail out. - */ - DEBUG(0, ("Serious error. A reply callback was called but no reply was received")); - exit(3); - } - - type = dbus_message_get_type(reply); - - switch (type) { - case DBUS_MESSAGE_TYPE_METHOD_RETURN: - if (dbus_message_get_args(reply, &error, - DBUS_TYPE_STRING, - &version_string, - DBUS_TYPE_INVALID)) { - fprintf(stdout, "Version: %s\n", version_string); - fflush(stdout); - } else { - DEBUG(0, ("Error getting arguments in print_version")); - } - break; - case DBUS_MESSAGE_TYPE_ERROR: - - if (strcmp(DBUS_ERROR_NO_REPLY, dbus_message_get_error_name(reply))==0) { - DEBUG(0, ("Received error. Timeout")); - } - else { - DEBUG(0, ("Received error. Not a timeout: %s", dbus_message_get_error_name(reply))); - } - break; - default: - DEBUG(0, ("Received unexpected message\n")); - exit(4); - } -} - -static void test_timed_handler(struct event_context *ev, - struct timed_event *te, - struct timeval tv, void *data) -{ - struct test_cli_ctx *test_ctx; - struct sbus_method_ctx *ctx; - DBusPendingCall *pending_reply; - DBusMessage *vmsg; - DBusError error; - dbus_bool_t dbret; - - test_ctx = talloc_get_type(data, struct test_cli_ctx); - ctx = test_ctx->sd_ctx; - - fprintf(stdout, "."); - fflush(stdout); - - dbus_error_init(&error); - vmsg = dbus_message_new_method_call(NULL, - ctx->path, ctx->interface, - MONITOR_METHOD_VERSION); - - dbret = dbus_connection_send_with_reply(sbus_get_connection(test_ctx->dct_ctx), vmsg, - &pending_reply, -1); - if (!dbret) { - /* Critical failure */ - DEBUG(0,("Failed to send version_request")); - exit(2); - } - - dbus_pending_call_set_notify(pending_reply, print_version, NULL, NULL); - - dbus_message_unref(vmsg); - - request_version_timed(test_ctx); -} - -static void request_version_timed(struct test_cli_ctx *ctx) -{ - struct timed_event *te = NULL; - struct timeval tv; - - gettimeofday(&tv, NULL); - tv.tv_sec += 5; - tv.tv_usec = 0; - te = event_add_timed(ctx->ev, ctx, tv, test_timed_handler, ctx); - if (te == NULL) { - DEBUG(0, ("failed to add event!\n")); - exit(1); - } -} - -int main (int argc, const char *argv[]) -{ - struct event_context *event_ctx; - struct sbus_method_ctx *ctx; - struct test_cli_ctx *test_ctx; - struct sbus_method_ctx *service_methods; - int ret; - - event_ctx = event_context_init(talloc_autofree_context()); - if (!event_ctx) { - printf("Out of memory!?\n"); - exit(1); - } - - ctx = talloc_zero(event_ctx, struct sbus_method_ctx); - if (!ctx) { - printf("Out of memory!?\n"); - exit(1); - } - - test_ctx = talloc(event_ctx, struct test_cli_ctx); - if (!test_ctx) { - printf("Out of memory!?\n"); - exit(1); - } - - test_ctx->ev = event_ctx; - ctx->interface = talloc_strdup(ctx, MONITOR_DBUS_INTERFACE); - ctx->path = talloc_strdup(ctx, MONITOR_DBUS_PATH); - if (!ctx->interface || !ctx->path) { - printf("Out of memory!?\n"); - exit(1); - } - - ret = sbus_new_connection(test_ctx, test_ctx->ev, DBUS_ADDRESS, &(test_ctx->dct_ctx), NULL); - if (ret != EOK) { - exit(1); - } - - test_ctx->sd_ctx = ctx; - - dbus_connection_set_exit_on_disconnect(sbus_get_connection(test_ctx->dct_ctx), TRUE); - - /* Set up a timed event to request the server version every - * five seconds and print it to the screen. - */ - request_version_timed(test_ctx); - - /* Set up handler for service methods */ - service_methods = talloc_zero(test_ctx, struct sbus_method_ctx); - service_methods->interface = talloc_strdup(service_methods, SERVICE_INTERFACE); - service_methods->path = talloc_strdup(service_methods, SERVICE_PATH); - service_methods->methods = monitor_service_methods; - sbus_conn_add_method_ctx(test_ctx->dct_ctx, service_methods); - - /* Enter the main loop (and hopefully never return) */ - event_loop_wait(event_ctx); - - talloc_free(event_ctx); - return EXIT_SUCCESS; -} - -static int provide_identity(DBusMessage *message, void *data, DBusMessage **r) { - const char *name = TEST_CLIENT_NAME; - dbus_uint16_t version = TEST_CLIENT_VERSION; - - DBusMessage *reply; - dbus_bool_t ret; - - reply = dbus_message_new_method_return(message); - ret = dbus_message_append_args(reply, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_UINT16, &version, - DBUS_TYPE_INVALID); - - if (!ret) { - return EIO; - } - - *r = reply; - return EOK; -} diff --git a/server/monitor.c b/server/monitor.c index 12e1b2fb1..0ca38b566 100644 --- a/server/monitor.c +++ b/server/monitor.c @@ -29,7 +29,7 @@ #include "confdb/confdb.h" #include "monitor.h" #include "dbus/dbus.h" -#include "dbus/sssd_dbus.h" +#include "sbus/sssd_dbus.h" /* TODO: Get these values from LDB */ #define SERVICE_PATH "/org/freeipa/sssd/service" diff --git a/server/sbus/sssd_dbus.h b/server/sbus/sssd_dbus.h new file mode 100644 index 000000000..1bd062d42 --- /dev/null +++ b/server/sbus/sssd_dbus.h @@ -0,0 +1,86 @@ +/* + SSSD + + SSSD - D-BUS interface + + Copyright (C) Stephen Gallagher 2008 + + 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 . +*/ + +#ifndef _SSSD_DBUS_H_ +#define _SSSD_DBUS_H_ +struct sbus_conn_ctx; +typedef int (*sbus_msg_handler_fn)(DBusMessage *msg, void *data, + DBusMessage **reply); + +/* + * sbus_conn_destructor_fn + * Function to be called when a connection is finalized + */ +typedef int (*sbus_conn_destructor_fn)( + void *ctx); + +/* + * sbus_server_conn_init_fn + * Set up function for connection-specific activities + * This function should define the sbus_conn_destructor_fn + * for this connection at a minimum + */ +typedef int (*sbus_server_conn_init_fn)( + struct sbus_conn_ctx *dct_ctx); + +enum { + SBUS_CONN_TYPE_PRIVATE = 1, + SBUS_CONN_TYPE_SHARED +}; + +struct sbus_method { + const char *method; + sbus_msg_handler_fn fn; +}; + +struct sbus_method_ctx { + struct sbus_method_ctx *prev, *next; + /*struct event_context *ev;*/ + char *interface; + char *path; + + /* If a non-default message_handler is desired, set it in this + * object before calling sbus_conn_add_method_ctx() + * Otherwise it will default to message_handler() in + * sssd_dbus_connection.c + */ + DBusObjectPathMessageFunction message_handler; + struct sbus_method *methods; +}; + +/* Server Functions */ +int sbus_new_server(struct event_context *ev, struct sbus_method_ctx *ctx, const char *address, sbus_server_conn_init_fn init_fn); + +/* Connection Functions */ +int sbus_new_connection(TALLOC_CTX *ctx, struct event_context *ev, const char *address, + struct sbus_conn_ctx **dct_ctx, + sbus_conn_destructor_fn destructor); + +void sbus_conn_set_destructor(struct sbus_conn_ctx *dct_ctx, + sbus_conn_destructor_fn destructor); +int sbus_default_connection_destructor(void *ctx); + +DBusConnection *sbus_get_connection(struct sbus_conn_ctx *dct_ctx); +void sbus_disconnect (struct sbus_conn_ctx *dct_ctx); +void sbus_conn_set_private_data(struct sbus_conn_ctx *dct_ctx, void *private); +int sbus_conn_add_method_ctx(struct sbus_conn_ctx *dct_ctx, struct sbus_method_ctx *method_ctx); + +#endif /* _SSSD_DBUS_H_*/ diff --git a/server/sbus/sssd_dbus_common.c b/server/sbus/sssd_dbus_common.c new file mode 100644 index 000000000..0ea66ccb3 --- /dev/null +++ b/server/sbus/sssd_dbus_common.c @@ -0,0 +1,45 @@ +#include +#include "events.h" +#include "dbus/dbus.h" +#include "util/util.h" + +struct timeval _dbus_timeout_get_interval_tv(int interval) { + struct timeval tv; + struct timeval rightnow; + + gettimeofday(&rightnow,NULL); + + tv.tv_sec = interval / 1000 + rightnow.tv_sec; + tv.tv_usec = (interval % 1000) * 1000 + rightnow.tv_usec; + return tv; +} + +/* + * sbus_remove_watch + * Hook for D-BUS to remove file descriptor-based events + * from the libevents mainloop + */ +void sbus_remove_watch(DBusWatch *watch, void *data) { + struct fd_event *fde; + + DEBUG(2, ("%lX\n", watch)); + fde = talloc_get_type(dbus_watch_get_data(watch), struct fd_event); + + /* Freeing the event object will remove it from the event loop */ + talloc_free(fde); + dbus_watch_set_data(watch, NULL, NULL); +} + + +/* + * sbus_remove_timeout + * Hook for D-BUS to remove time-based events from the mainloop + */ +void sbus_remove_timeout(DBusTimeout *timeout, void *data) { + struct timed_event *te; + te = talloc_get_type(dbus_timeout_get_data(timeout), struct timed_event); + + /* Freeing the event object will remove it from the event loop */ + talloc_free(te); + dbus_timeout_set_data(timeout, NULL, NULL); +} diff --git a/server/sbus/sssd_dbus_connection.c b/server/sbus/sssd_dbus_connection.c new file mode 100644 index 000000000..bd95c0abe --- /dev/null +++ b/server/sbus/sssd_dbus_connection.c @@ -0,0 +1,576 @@ +#include +#include "events.h" +#include "util/util.h" +#include "dbus/dbus.h" +#include "sbus/sssd_dbus.h" +#include "sbus/sssd_dbus_private.h" + +/* Types */ +struct dbus_ctx_list; + +struct sbus_conn_ctx { + DBusConnection *conn; + struct event_context *ev; + int connection_type; + int disconnect; + struct sbus_method_ctx *method_ctx_list; + sbus_conn_destructor_fn destructor; + void *private; /* Private data for this connection */ +}; + +struct sbus_conn_watch_ctx { + DBusWatch *watch; + int fd; + struct fd_event *fde; + struct sbus_conn_ctx *top; +}; + +struct sbus_conn_timeout_ctx { + DBusTimeout *timeout; + struct timed_event *te; + struct sbus_conn_ctx *top; +}; + +static int _method_list_contains_path(struct sbus_method_ctx *list, struct sbus_method_ctx *method); +static void sbus_unreg_object_paths(struct sbus_conn_ctx *dct_ctx); + +static void sbus_dispatch(struct event_context *ev, + struct timed_event *te, + struct timeval tv, void *data) +{ + struct timed_event *new_event; + struct sbus_conn_ctx *dct_ctx; + DBusConnection *conn; + int ret; + + if (data == NULL) { + return; + } + + dct_ctx = talloc_get_type(data, struct sbus_conn_ctx); + + conn = dct_ctx->conn; + DEBUG(3, ("conn: %lX\n", conn)); + + if((dct_ctx->disconnect) || (!dbus_connection_get_is_connected(conn))) { + DEBUG(0,("Connection is not open for dispatching.\n")); + /* + * Free the connection object. + * This will invoke the destructor for the connection + */ + talloc_free(dct_ctx); + dct_ctx = NULL; + return; + } + + /* Dispatch only once each time through the mainloop to avoid + * starving other features + */ + ret = dbus_connection_get_dispatch_status(conn); + if (ret != DBUS_DISPATCH_COMPLETE) { + DEBUG(2,("Dispatching.\n")); + dbus_connection_dispatch(conn); + } + + /* If other dispatches are waiting, queue up the do_dispatch function + * for the next loop. + */ + ret = dbus_connection_get_dispatch_status(conn); + if (ret != DBUS_DISPATCH_COMPLETE) { + new_event = event_add_timed(ev, dct_ctx, tv, sbus_dispatch, dct_ctx); + if (new_event == NULL) { + DEBUG(0,("Could not add dispatch event!\n")); + + /* TODO: Calling exit here is bad */ + exit(1); + } + } +} + +/* + * dbus_connection_read_write_handler + * Callback for D-BUS to handle messages on a file-descriptor + */ +static void sbus_conn_read_write_handler(struct event_context *ev, + struct fd_event *fde, + uint16_t flags, void *data) +{ + struct sbus_conn_watch_ctx *conn_w_ctx; + conn_w_ctx = talloc_get_type(data, struct sbus_conn_watch_ctx); + + DEBUG(0,("Connection is open for read/write.\n")); + dbus_connection_ref(conn_w_ctx->top->conn); + if (flags & EVENT_FD_READ) { + dbus_watch_handle(conn_w_ctx->watch, DBUS_WATCH_READABLE); + } + if (flags & EVENT_FD_WRITE) { + dbus_watch_handle(conn_w_ctx->watch, DBUS_WATCH_WRITABLE); + } + dbus_connection_unref(conn_w_ctx->top->conn); +} + +/* + * add_connection_watch + * Set up hooks into the libevents mainloop for + * D-BUS to add file descriptor-based events + */ +static dbus_bool_t sbus_add_conn_watch(DBusWatch *watch, void *data) +{ + unsigned int flags; + unsigned int event_flags; + struct sbus_conn_ctx *dt_ctx; + struct sbus_conn_watch_ctx *conn_w_ctx; + + if (!dbus_watch_get_enabled(watch)) { + return TRUE; + } + + dt_ctx = talloc_get_type(data, struct sbus_conn_ctx); + + conn_w_ctx = talloc_zero(dt_ctx, struct sbus_conn_watch_ctx); + conn_w_ctx->top = dt_ctx; + conn_w_ctx->watch = watch; + + flags = dbus_watch_get_flags(watch); + conn_w_ctx->fd = dbus_watch_get_unix_fd(watch); + + event_flags = 0; + + if (flags & DBUS_WATCH_READABLE) + event_flags |= EVENT_FD_READ; + + if (flags & DBUS_WATCH_WRITABLE) + event_flags |= EVENT_FD_WRITE; + + if (event_flags == 0) + return FALSE; + + DEBUG(2,("%lX: %d, %d=%s\n", watch, conn_w_ctx->fd, event_flags, event_flags==EVENT_FD_READ?"READ":"WRITE")); + + /* Add the file descriptor to the event loop */ + conn_w_ctx->fde = event_add_fd(conn_w_ctx->top->ev, conn_w_ctx, + conn_w_ctx->fd, event_flags, + sbus_conn_read_write_handler, + conn_w_ctx); + + /* Save the event to the watch object so it can be removed later */ + dbus_watch_set_data(conn_w_ctx->watch,conn_w_ctx->fde,NULL); + + return TRUE; +} + +/* + * toggle_connection_watch + * Hook for D-BUS to toggle the enabled/disabled state of + * an event in the mainloop + */ +static void sbus_toggle_conn_watch(DBusWatch *watch, void *data) +{ + if (dbus_watch_get_enabled(watch)) { + sbus_add_conn_watch(watch, data); + } else { + sbus_remove_watch(watch, data); + } +} + +/* + * dbus_connection_timeout_handler + * Callback for D-BUS to handle timed events + */ +static void sbus_conn_timeout_handler(struct event_context *ev, + struct timed_event *te, + struct timeval t, void *data) +{ + struct sbus_conn_timeout_ctx *conn_t_ctx; + conn_t_ctx = talloc_get_type(data, struct sbus_conn_timeout_ctx); + + dbus_timeout_handle(conn_t_ctx->timeout); +} + + +/* + * add_connection_timeout + * Hook for D-BUS to add time-based events to the mainloop + */ +static dbus_bool_t sbus_add_conn_timeout(DBusTimeout *timeout, void *data) +{ + struct sbus_conn_ctx *dt_ctx; + struct sbus_conn_timeout_ctx *conn_t_ctx; + struct timeval tv; + + if (!dbus_timeout_get_enabled(timeout)) + return TRUE; + + dt_ctx = talloc_get_type(data, struct sbus_conn_ctx); + + conn_t_ctx = talloc_zero(dt_ctx,struct sbus_conn_timeout_ctx); + conn_t_ctx->top = dt_ctx; + conn_t_ctx->timeout = timeout; + + tv = _dbus_timeout_get_interval_tv(dbus_timeout_get_interval(timeout)); + + struct timeval rightnow; + gettimeofday(&rightnow, NULL); + + conn_t_ctx->te = event_add_timed(conn_t_ctx->top->ev, conn_t_ctx, tv, + sbus_conn_timeout_handler, conn_t_ctx); + + /* Save the event to the watch object so it can be removed later */ + dbus_timeout_set_data(conn_t_ctx->timeout,conn_t_ctx->te,NULL); + + return TRUE; +} + +/* + * sbus_toggle_conn_timeout + * Hook for D-BUS to toggle the enabled/disabled state of a mainloop + * event + */ +void sbus_toggle_conn_timeout(DBusTimeout *timeout, void *data) +{ + if (dbus_timeout_get_enabled(timeout)) { + sbus_add_conn_timeout(timeout, data); + } else { + sbus_remove_timeout(timeout, data); + } +} + +/* dbus_connection_wakeup_main + * D-BUS makes a callback to the wakeup_main function when + * it has data available for dispatching. + * In order to avoid blocking, this function will create a now() + * timed event to perform the dispatch during the next iteration + * through the mainloop + */ +static void sbus_conn_wakeup_main(void *data) { + struct sbus_conn_ctx *dct_ctx; + struct timeval tv; + struct timed_event *te; + + dct_ctx = talloc_get_type(data, struct sbus_conn_ctx); + gettimeofday(&tv, NULL); + + /* D-BUS calls this function when it is time to do a dispatch */ + te = event_add_timed(dct_ctx->ev, dct_ctx, + tv, sbus_dispatch, dct_ctx); + if (te == NULL) { + DEBUG(0,("Could not add dispatch event!\n")); + exit(1); + } +} + +/* + * integrate_connection_with_event_loop + * Set up a D-BUS connection to use the libevents mainloop + * for handling file descriptor and timed events + */ +int sbus_add_connection(TALLOC_CTX *ctx, + struct event_context *ev, + DBusConnection *dbus_conn, + struct sbus_conn_ctx **dct_ctx, + int connection_type) +{ + dbus_bool_t dbret; + struct sbus_conn_ctx *dt_ctx; + + DEBUG(0,("Adding connection %lX\n", dbus_conn)); + dt_ctx = talloc_zero(ctx, struct sbus_conn_ctx); + dt_ctx->ev = ev; + dt_ctx->conn = dbus_conn; + dt_ctx->connection_type = connection_type; + dt_ctx->disconnect = 0; + /* This will be replaced on the first call to sbus_conn_add_method_ctx() */ + dt_ctx->method_ctx_list = NULL; + + /* + * Set the default destructor + * Connections can override this with + * sbus_conn_set_destructor + */ + sbus_conn_set_destructor(dt_ctx, NULL); + + /* Set up DBusWatch functions */ + dbret = dbus_connection_set_watch_functions(dt_ctx->conn, + sbus_add_conn_watch, + sbus_remove_watch, + sbus_toggle_conn_watch, + dt_ctx, NULL); + if (!dbret) { + DEBUG(0,("Error setting up D-BUS connection watch functions\n")); + return EIO; + } + + /* Set up DBusTimeout functions */ + dbret = dbus_connection_set_timeout_functions(dt_ctx->conn, + sbus_add_conn_timeout, + sbus_remove_timeout, + sbus_toggle_conn_timeout, + dt_ctx, NULL); + if (!dbret) { + DEBUG(0,("Error setting up D-BUS server timeout functions\n")); + /* FIXME: free resources ? */ + return EIO; + } + + /* Set up dispatch handler */ + dbus_connection_set_wakeup_main_function(dt_ctx->conn, + sbus_conn_wakeup_main, + dt_ctx, NULL); + + /* Set up any method_contexts passed in */ + + /* Attempt to dispatch immediately in case of opportunistic + * services connecting before the handlers were all up. + * If there are no messages to be dispatched, this will do + * nothing. + */ + sbus_conn_wakeup_main(dt_ctx); + + /* Return the new toplevel object */ + *dct_ctx = dt_ctx; + + return EOK; +} + +/*int sbus_new_connection(struct sbus_method_ctx *ctx, const char *address, + DBusConnection **connection, + sbus_conn_destructor_fn destructor)*/ +int sbus_new_connection(TALLOC_CTX *ctx, struct event_context *ev, const char *address, + struct sbus_conn_ctx **dct_ctx, + sbus_conn_destructor_fn destructor) +{ + DBusConnection *dbus_conn; + DBusError dbus_error; + int ret; + + dbus_error_init(&dbus_error); + + /* Open a shared D-BUS connection to the address */ + dbus_conn = dbus_connection_open(address, &dbus_error); + if (!dbus_conn) { + DEBUG(0, ("Failed to open connection: name=%s, message=%s\n", + dbus_error.name, dbus_error.message)); + return EIO; + } + + ret = sbus_add_connection(ctx, ev, dbus_conn, dct_ctx, SBUS_CONN_TYPE_SHARED); + if (ret != EOK) { + /* FIXME: release resources */ + } + + dbus_connection_set_exit_on_disconnect((*dct_ctx)->conn, FALSE); + + /* Set connection destructor */ + sbus_conn_set_destructor(*dct_ctx, destructor); + + return ret; +} + +/* + * sbus_conn_set_destructor + * Configures a callback to clean up this connection when it + * is finalized. + * @param dct_ctx The sbus_conn_ctx created + * when this connection was established + * @param destructor The destructor function that should be + * called when the connection is finalized. If passed NULL, + * this will reset the connection to the default destructor. + */ +void sbus_conn_set_destructor(struct sbus_conn_ctx *dct_ctx, + sbus_conn_destructor_fn destructor) { + if (!dct_ctx) { + return; + } + + dct_ctx->destructor = destructor; + /* TODO: Should we try to handle the talloc_destructor too? */ +} + +int sbus_default_connection_destructor(void *ctx) { + struct sbus_conn_ctx *dct_ctx; + dct_ctx = talloc_get_type(ctx, struct sbus_conn_ctx); + + DEBUG(3, ("Invoking default destructor on connection %lX\n", dct_ctx->conn)); + if (dct_ctx->connection_type == SBUS_CONN_TYPE_PRIVATE) { + /* Private connections must be closed explicitly */ + dbus_connection_close(dct_ctx->conn); + } else if (dct_ctx->connection_type == SBUS_CONN_TYPE_SHARED) { + /* Shared connections are destroyed when their last reference is removed */ + } + else { + /* Critical Error! */ + DEBUG(0,("Critical Error, connection_type is neither shared nor private!\n")); + return -1; + } + + /* Remove object path */ + /* TODO: Remove object paths */ + + + dbus_connection_unref(dct_ctx->conn); + return 0; +} + +/* + * sbus_get_connection + * Utility function to retreive the DBusConnection object + * from a sbus_conn_ctx + */ +DBusConnection *sbus_get_connection(struct sbus_conn_ctx *dct_ctx) { + return dct_ctx->conn; +} + +void sbus_disconnect (struct sbus_conn_ctx *dct_ctx) { + if (dct_ctx == NULL) { + return; + } + + DEBUG(2,("Disconnecting %lX\n", dct_ctx->conn)); + dbus_connection_ref(dct_ctx->conn); + dct_ctx->disconnect = 1; + + /* Invoke the custom destructor, if it exists */ + if(dct_ctx->destructor) { + dct_ctx->destructor(dct_ctx); + } + + /* Unregister object paths */ + sbus_unreg_object_paths(dct_ctx); + + /* Disable watch functions */ + dbus_connection_set_watch_functions(dct_ctx->conn, + NULL, NULL, NULL, + NULL, NULL); + /* Disable timeout functions */ + dbus_connection_set_timeout_functions(dct_ctx->conn, + NULL, NULL, NULL, + NULL, NULL); + + /* Disable dispatch status function */ + dbus_connection_set_dispatch_status_function(dct_ctx->conn, NULL, NULL, NULL); + + /* Disable wakeup main function */ + dbus_connection_set_wakeup_main_function(dct_ctx->conn, NULL, NULL, NULL); + + /* Finalize the connection */ + sbus_default_connection_destructor(dct_ctx); + dbus_connection_unref(dct_ctx->conn); + DEBUG(2,("Disconnected %lX\n", dct_ctx->conn)); +} + +/* messsage_handler + * Receive messages and process them + */ +static DBusHandlerResult message_handler(DBusConnection *conn, + DBusMessage *message, + void *user_data) +{ + struct sbus_method_ctx *ctx; + const char *method; + const char *path; + const char *msg_interface; + DBusMessage *reply = NULL; + int i, ret; + + ctx = talloc_get_type(user_data, struct sbus_method_ctx); + + method = dbus_message_get_member(message); + path = dbus_message_get_path(message); + msg_interface = dbus_message_get_interface(message); + + if (!method || !path || !msg_interface) + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + /* Validate the method interface */ + if (strcmp(msg_interface, ctx->interface) != 0) + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + /* Validate the D-BUS path */ + if (strcmp(path, ctx->path) == 0) { + for (i = 0; ctx->methods[i].method != NULL; i++) { + if (strcmp(method, ctx->methods[i].method) == 0) { + ret = ctx->methods[i].fn(message, ctx, &reply); + /* FIXME: check error */ + break; + } + } + /* FIXME: check if we didn't find any matching method */ + } + + DEBUG(2, ("Method %s complete. Reply was %srequested.\n", method, reply?"":"not ")); + + if (reply) { + dbus_connection_send(conn, reply, NULL); + dbus_message_unref(reply); + } + + return reply ? DBUS_HANDLER_RESULT_HANDLED : + DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +/* Adds a new D-BUS path message handler to the connection + * Note: this must be a unique path. + */ +int sbus_conn_add_method_ctx(struct sbus_conn_ctx *dct_ctx, struct sbus_method_ctx *method_ctx) { + DBusObjectPathVTable *connection_vtable; + dbus_bool_t dbret; + if (!method_ctx) { + return EINVAL; + } + + if (_method_list_contains_path(dct_ctx->method_ctx_list, method_ctx)) { + return EINVAL; + } + + DLIST_ADD(dct_ctx->method_ctx_list, method_ctx); + + /* Set up the vtable for the object path */ + connection_vtable = talloc_zero(dct_ctx, DBusObjectPathVTable); + if (method_ctx->message_handler) { + connection_vtable->message_function = method_ctx->message_handler; + } else { + connection_vtable->message_function = message_handler; + } + + dbret = dbus_connection_register_object_path(dct_ctx->conn, method_ctx->path, connection_vtable, method_ctx); + if (!dbret) { + return ENOMEM; + } + + return EOK; +} + +static int _method_list_contains_path(struct sbus_method_ctx *list, struct sbus_method_ctx *method) { + struct sbus_method_ctx *iter; + + if (!list || !method) { + return 0; /* FALSE */ + } + + iter = list; + while (iter != NULL) { + if (strcmp(iter->path, method->path) == 0) + return 1; /* TRUE */ + + iter = iter->next; + } + + return 0; /* FALSE */ +} + +static void sbus_unreg_object_paths(struct sbus_conn_ctx *dct_ctx) { + struct sbus_method_ctx *iter = dct_ctx->method_ctx_list; + struct sbus_method_ctx *purge; + + while(iter != NULL) { + dbus_connection_unregister_object_path(dct_ctx->conn, iter->path); + DLIST_REMOVE(dct_ctx->method_ctx_list, iter); + purge = iter; + iter = iter->next; + talloc_free(purge); + } +} + +void sbus_conn_set_private_data(struct sbus_conn_ctx *dct_ctx, void *private) { + dct_ctx->private = private; +} diff --git a/server/sbus/sssd_dbus_private.h b/server/sbus/sssd_dbus_private.h new file mode 100644 index 000000000..d102c8c9d --- /dev/null +++ b/server/sbus/sssd_dbus_private.h @@ -0,0 +1,14 @@ +#ifndef _SSSD_DBUS_PRIVATE_H_ +#define _SSSD_DBUS_PRIVATE_H_ + +int sbus_add_connection(TALLOC_CTX *ctx, + struct event_context *ev, + DBusConnection *dbus_conn, + struct sbus_conn_ctx **dct_ctx, + int connection_type); + +struct timeval _dbus_timeout_get_interval_tv(int interval); +void sbus_remove_watch(DBusWatch *watch, void *data); +void sbus_remove_timeout(DBusTimeout *timeout, void *data); + +#endif /* _SSSD_DBUS_PRIVATE_H_ */ diff --git a/server/sbus/sssd_dbus_server.c b/server/sbus/sssd_dbus_server.c new file mode 100644 index 000000000..22dcbf39a --- /dev/null +++ b/server/sbus/sssd_dbus_server.c @@ -0,0 +1,316 @@ +/* + SSSD + + Service monitor - D-BUS features + + Copyright (C) Stephen Gallagher 2008 + + 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 . +*/ +#include +#include "events.h" +#include "util/util.h" +#include "dbus/dbus.h" +#include "sbus/sssd_dbus.h" +#include "sbus/sssd_dbus_private.h" + +/* Types */ +struct sbus_srv_ctx { + DBusServer *server; + /* + * sd_ctx here describes the object path that will be + * presented to all clients of this server. Additional + * connection-specific paths can be specified by the + * init_fn, which is called every time a new connection + * is established. + * There should only be one global object path (for + * simplicity's sake) + */ + struct event_context *ev; + struct sbus_method_ctx *sd_ctx; + sbus_server_conn_init_fn init_fn; +}; + +struct sbus_srv_watch_ctx { + DBusWatch *watch; + int fd; + struct fd_event *fde; + struct sbus_srv_ctx *top; +}; + +struct dbus_srv_timeout_ctx { + DBusTimeout *timeout; + struct timed_event *te; + struct sbus_srv_ctx *top; +}; + +static int sbus_server_destructor(void **server); + +/* + * dbus_server_read_write_handler + * Callback for D-BUS to handle messages on a file-descriptor + */ +static void sbus_srv_read_write_handler(struct event_context *ev, + struct fd_event *fde, + uint16_t flags, void *data) +{ + struct sbus_srv_watch_ctx *svw_ctx; + svw_ctx = talloc_get_type(data, struct sbus_srv_watch_ctx); + + dbus_server_ref(svw_ctx->top->server); + if (flags & EVENT_FD_READ) { + dbus_watch_handle(svw_ctx->watch, DBUS_WATCH_READABLE); + } + if (flags & EVENT_FD_WRITE) { + dbus_watch_handle(svw_ctx->watch, DBUS_WATCH_WRITABLE); + } + dbus_server_unref(svw_ctx->top->server); +} + +/* + * add_server_watch + * Set up hooks into the libevents mainloop for + * D-BUS to add file descriptor-based events + */ +static dbus_bool_t sbus_add_srv_watch(DBusWatch *watch, void *data) +{ + unsigned int flags; + unsigned int event_flags; + struct sbus_srv_ctx *dt_ctx; + struct sbus_srv_watch_ctx *svw_ctx; + + if (!dbus_watch_get_enabled(watch)) { + return FALSE; + } + + dt_ctx = talloc_get_type(data, struct sbus_srv_ctx); + + svw_ctx = talloc_zero(dt_ctx, struct sbus_srv_watch_ctx); + svw_ctx->top = dt_ctx; + svw_ctx->watch = watch; + + flags = dbus_watch_get_flags(watch); + svw_ctx->fd = dbus_watch_get_unix_fd(watch); + + event_flags = 0; + + if (flags & DBUS_WATCH_READABLE) { + event_flags |= EVENT_FD_READ; + } + + if (flags & DBUS_WATCH_WRITABLE) { + event_flags |= EVENT_FD_WRITE; + } + DEBUG(2,("%lX: %d, %d=%s\n", watch, svw_ctx->fd, event_flags, event_flags==EVENT_FD_READ?"READ":"WRITE")); + + svw_ctx->fde = event_add_fd(dt_ctx->ev, svw_ctx, svw_ctx->fd, + event_flags, sbus_srv_read_write_handler, + svw_ctx); + + /* Save the event to the watch object so it can be removed later */ + dbus_watch_set_data(svw_ctx->watch, svw_ctx->fde, NULL); + + return TRUE; +} + +/* + * server_watch_toggled + * Hook for D-BUS to toggle the enabled/disabled state of + * an event in the mainloop + */ +static void sbus_toggle_srv_watch(DBusWatch *watch, void *data) +{ + if (dbus_watch_get_enabled(watch)) { + sbus_add_srv_watch(watch, data); + } else { + sbus_remove_watch(watch, data); + } +} + +static void sbus_srv_timeout_handler(struct event_context *ev, + struct timed_event *te, + struct timeval t, void *data) +{ + struct dbus_srv_timeout_ctx *svt_ctx; + svt_ctx = talloc_get_type(data, struct dbus_srv_timeout_ctx); + dbus_timeout_handle(svt_ctx->timeout); +} + +/* + * add_server_timeout + * Hook for D-BUS to add time-based events to the mainloop + */ +static dbus_bool_t sbus_add_srv_timeout(DBusTimeout *timeout, void *data) +{ + struct sbus_srv_ctx *dt_ctx; + struct dbus_srv_timeout_ctx *svt_ctx; + struct timeval tv; + + if (!dbus_timeout_get_enabled(timeout)) + return TRUE; + + dt_ctx = talloc_get_type(data, struct sbus_srv_ctx); + + svt_ctx = talloc_zero(dt_ctx,struct dbus_srv_timeout_ctx); + svt_ctx->top = dt_ctx; + svt_ctx->timeout = timeout; + + tv = _dbus_timeout_get_interval_tv(dbus_timeout_get_interval(timeout)); + + svt_ctx->te = event_add_timed(dt_ctx->ev, svt_ctx, tv, + sbus_srv_timeout_handler, svt_ctx); + + /* Save the event to the watch object so it can be removed later */ + dbus_timeout_set_data(svt_ctx->timeout, svt_ctx->te, NULL); + + return TRUE; +} + +/* + * server_timeout_toggled + * Hook for D-BUS to toggle the enabled/disabled state of a mainloop + * event + */ +static void sbus_toggle_srv_timeout(DBusTimeout *timeout, void *data) +{ + if (dbus_timeout_get_enabled(timeout)) { + sbus_add_srv_timeout(timeout, data); + } else { + sbus_remove_timeout(timeout, data); + } +} + +/* + * new_connection_callback + * Actions to be run upon each new client connection + * Must either perform dbus_connection_ref() on the + * new connection or else close the connection with + * dbus_connection_close() + */ +static void sbus_server_init_new_connection(DBusServer *server, DBusConnection *conn, + void *data) +{ + struct sbus_srv_ctx *dst_ctx; + struct sbus_conn_ctx *dct_ctx; + struct sbus_method_ctx *iter; + + /*DBusObjectPathVTable *connection_vtable;*/ + int ret; + DEBUG(0,("Entering.\n")); + dst_ctx = talloc_get_type(data,struct sbus_srv_ctx); + if(dst_ctx == NULL) { + return; + } + + DEBUG(0,("Adding connection %lX.\n", conn)); + ret = sbus_add_connection(dst_ctx, dst_ctx->ev, conn, &dct_ctx, SBUS_CONN_TYPE_PRIVATE); + if (ret != 0) { + dbus_connection_close(conn); + DEBUG(0,("Closing connection (failed setup)")); + return; + } + + dbus_connection_ref(conn); + + DEBUG(3,("Got a connection\n")); + + /* Set up global methods */ + iter = dst_ctx->sd_ctx; + while (iter != NULL) { + sbus_conn_add_method_ctx(dct_ctx, iter); + iter = iter->next; + } + + /* + * Initialize connection-specific features + * This may set a more detailed destructor, but + * the default destructor will always be chained + * to handle connection cleanup. + * This function (or its callbacks) should also + * set up connection-specific methods. + */ + dst_ctx->init_fn(dct_ctx); +} + +/* + * dbus_new_server + * Set up a D-BUS server, integrate with the event loop + * for handling file descriptor and timed events + */ +int sbus_new_server(struct event_context *ev, struct sbus_method_ctx *ctx, const char *address, sbus_server_conn_init_fn init_fn) +{ + struct sbus_srv_ctx *dst_ctx; + DBusServer *dbus_server; + DBusServer **dbus_server_talloc; + DBusError dbus_error; + dbus_bool_t dbret; + + /* Set up D-BUS server */ + dbus_error_init(&dbus_error); + dbus_server = dbus_server_listen(address, &dbus_error); + if (!dbus_server) { + DEBUG(0,("dbus_server_listen failed! (name=%s, message=%s)\n", + dbus_error.name, dbus_error.message)); + return EIO; + } + + DEBUG(2, ("D-BUS Server listening on %s\n", + dbus_server_get_address(dbus_server))); + + dst_ctx = talloc_zero(ev, struct sbus_srv_ctx); + if (!dst_ctx) { + return ENOMEM; + } + + dbus_server_talloc = talloc_takeover(ctx, dbus_server, sbus_server_destructor); + dst_ctx->ev = ev; + dst_ctx->server = dbus_server; + dst_ctx->sd_ctx = ctx; + dst_ctx->init_fn = init_fn; + + /* Set up D-BUS new connection handler */ + dbus_server_set_new_connection_function(dst_ctx->server, + sbus_server_init_new_connection, + dst_ctx, NULL); + + /* Set up DBusWatch functions */ + dbret = dbus_server_set_watch_functions(dst_ctx->server, sbus_add_srv_watch, + sbus_remove_watch, sbus_toggle_srv_watch, + dst_ctx, NULL); + if (!dbret) { + DEBUG(0, ("Error setting up D-BUS server watch functions")); + talloc_free(dst_ctx); + return EIO; + } + + /* Set up DBusTimeout functions */ + dbret = dbus_server_set_timeout_functions(dst_ctx->server, + sbus_add_srv_timeout, + sbus_remove_timeout, + sbus_toggle_srv_timeout, + dst_ctx, NULL); + if (!dbret) { + DEBUG(0,("Error setting up D-BUS server timeout functions")); + dbus_server_set_watch_functions(dst_ctx->server, NULL, NULL, NULL, NULL, NULL); + talloc_free(dst_ctx); + return EIO; + } + + return EOK; +} + +static int sbus_server_destructor(void **server) { + dbus_server_disconnect(*server); + return 0; +} diff --git a/server/sbus/tests/test_client.c b/server/sbus/tests/test_client.c new file mode 100644 index 000000000..bf1c207e5 --- /dev/null +++ b/server/sbus/tests/test_client.c @@ -0,0 +1,223 @@ +#include +#include +#include +#include "events.h" +#include "util/util.h" +#include "dbus/dbus.h" +#include "sbus/sssd_dbus.h" + +/* TODO: get this value from LDB */ +#define DBUS_ADDRESS "unix:path=/var/lib/sss/pipes/private/dbus" + +/* Identity */ +#define TEST_CLIENT_NAME "testclient" +#define TEST_CLIENT_VERSION 1 + +/* Monitor Interface */ +#define MONITOR_DBUS_INTERFACE "org.freeipa.sssd.monitor" +#define MONITOR_DBUS_PATH "/org/freeipa/sssd/monitor" +#define MONITOR_METHOD_VERSION "getVersion" + +/* Service Interface */ +#define SERVICE_PATH "/org/freeipa/sssd/service" +#define SERVICE_INTERFACE "org.freeipa.sssd.service" +#define SERVICE_METHOD_IDENTITY "getIdentity" + +struct test_cli_ctx { + struct sbus_method_ctx *sd_ctx; + /*DBusConnection *conn;*/ + struct event_context *ev; + struct sbus_conn_ctx *dct_ctx; +}; + +static int provide_identity(DBusMessage *message, void *data, DBusMessage **r); + +struct sbus_method monitor_service_methods [] = { + {SERVICE_METHOD_IDENTITY, provide_identity}, + {NULL, NULL} +}; + +static void request_version_timed(struct test_cli_ctx *ctx); + +static void print_version(DBusPendingCall *pending, void *data) +{ + DBusMessage *reply; + DBusError error; + const char *version_string; + int type; + + dbus_error_init(&error); + + reply = dbus_pending_call_steal_reply(pending); + if (!reply) { + /* reply should never be null. This function shouldn't be called + * until reply is valid. If reply is NULL here, something is seriously + * wrong and we should bail out. + */ + DEBUG(0, ("Serious error. A reply callback was called but no reply was received")); + exit(3); + } + + type = dbus_message_get_type(reply); + + switch (type) { + case DBUS_MESSAGE_TYPE_METHOD_RETURN: + if (dbus_message_get_args(reply, &error, + DBUS_TYPE_STRING, + &version_string, + DBUS_TYPE_INVALID)) { + fprintf(stdout, "Version: %s\n", version_string); + fflush(stdout); + } else { + DEBUG(0, ("Error getting arguments in print_version")); + } + break; + case DBUS_MESSAGE_TYPE_ERROR: + + if (strcmp(DBUS_ERROR_NO_REPLY, dbus_message_get_error_name(reply))==0) { + DEBUG(0, ("Received error. Timeout")); + } + else { + DEBUG(0, ("Received error. Not a timeout: %s", dbus_message_get_error_name(reply))); + } + break; + default: + DEBUG(0, ("Received unexpected message\n")); + exit(4); + } +} + +static void test_timed_handler(struct event_context *ev, + struct timed_event *te, + struct timeval tv, void *data) +{ + struct test_cli_ctx *test_ctx; + struct sbus_method_ctx *ctx; + DBusPendingCall *pending_reply; + DBusMessage *vmsg; + DBusError error; + dbus_bool_t dbret; + + test_ctx = talloc_get_type(data, struct test_cli_ctx); + ctx = test_ctx->sd_ctx; + + fprintf(stdout, "."); + fflush(stdout); + + dbus_error_init(&error); + vmsg = dbus_message_new_method_call(NULL, + ctx->path, ctx->interface, + MONITOR_METHOD_VERSION); + + dbret = dbus_connection_send_with_reply(sbus_get_connection(test_ctx->dct_ctx), vmsg, + &pending_reply, -1); + if (!dbret) { + /* Critical failure */ + DEBUG(0,("Failed to send version_request")); + exit(2); + } + + dbus_pending_call_set_notify(pending_reply, print_version, NULL, NULL); + + dbus_message_unref(vmsg); + + request_version_timed(test_ctx); +} + +static void request_version_timed(struct test_cli_ctx *ctx) +{ + struct timed_event *te = NULL; + struct timeval tv; + + gettimeofday(&tv, NULL); + tv.tv_sec += 5; + tv.tv_usec = 0; + te = event_add_timed(ctx->ev, ctx, tv, test_timed_handler, ctx); + if (te == NULL) { + DEBUG(0, ("failed to add event!\n")); + exit(1); + } +} + +int main (int argc, const char *argv[]) +{ + struct event_context *event_ctx; + struct sbus_method_ctx *ctx; + struct test_cli_ctx *test_ctx; + struct sbus_method_ctx *service_methods; + int ret; + + event_ctx = event_context_init(talloc_autofree_context()); + if (!event_ctx) { + printf("Out of memory!?\n"); + exit(1); + } + + ctx = talloc_zero(event_ctx, struct sbus_method_ctx); + if (!ctx) { + printf("Out of memory!?\n"); + exit(1); + } + + test_ctx = talloc(event_ctx, struct test_cli_ctx); + if (!test_ctx) { + printf("Out of memory!?\n"); + exit(1); + } + + test_ctx->ev = event_ctx; + ctx->interface = talloc_strdup(ctx, MONITOR_DBUS_INTERFACE); + ctx->path = talloc_strdup(ctx, MONITOR_DBUS_PATH); + if (!ctx->interface || !ctx->path) { + printf("Out of memory!?\n"); + exit(1); + } + + ret = sbus_new_connection(test_ctx, test_ctx->ev, DBUS_ADDRESS, &(test_ctx->dct_ctx), NULL); + if (ret != EOK) { + exit(1); + } + + test_ctx->sd_ctx = ctx; + + dbus_connection_set_exit_on_disconnect(sbus_get_connection(test_ctx->dct_ctx), TRUE); + + /* Set up a timed event to request the server version every + * five seconds and print it to the screen. + */ + request_version_timed(test_ctx); + + /* Set up handler for service methods */ + service_methods = talloc_zero(test_ctx, struct sbus_method_ctx); + service_methods->interface = talloc_strdup(service_methods, SERVICE_INTERFACE); + service_methods->path = talloc_strdup(service_methods, SERVICE_PATH); + service_methods->methods = monitor_service_methods; + sbus_conn_add_method_ctx(test_ctx->dct_ctx, service_methods); + + /* Enter the main loop (and hopefully never return) */ + event_loop_wait(event_ctx); + + talloc_free(event_ctx); + return EXIT_SUCCESS; +} + +static int provide_identity(DBusMessage *message, void *data, DBusMessage **r) { + const char *name = TEST_CLIENT_NAME; + dbus_uint16_t version = TEST_CLIENT_VERSION; + + DBusMessage *reply; + dbus_bool_t ret; + + reply = dbus_message_new_method_return(message); + ret = dbus_message_append_args(reply, + DBUS_TYPE_STRING, &name, + DBUS_TYPE_UINT16, &version, + DBUS_TYPE_INVALID); + + if (!ret) { + return EIO; + } + + *r = reply; + return EOK; +} diff --git a/server/server.mk b/server/server.mk index a65dcb582..6339791e0 100644 --- a/server/server.mk +++ b/server/server.mk @@ -13,15 +13,15 @@ SERVER_OBJ = \ nss/nsssrv_packet.o \ nss/nsssrv_cmd.o \ nss/nsssrv_ldb.o \ - dbus/sssd_dbus_common.o \ - dbus/sssd_dbus_connection.o \ - dbus/sssd_dbus_server.o + sbus/sssd_dbus_common.o \ + sbus/sssd_dbus_connection.o \ + sbus/sssd_dbus_server.o CLIENT_OBJ = \ - dbus/sssd_dbus_common.o \ - dbus/sssd_dbus_connection.o \ + sbus/sssd_dbus_common.o \ + sbus/sssd_dbus_connection.o \ util/debug.o \ - dbus/tests/test_client.o + sbus/tests/test_client.o install:: all ${INSTALLCMD} -d $(DESTDIR)$(sbindir) -- cgit