diff options
Diffstat (limited to 'server/sbus/sssd_dbus_server.c')
-rw-r--r-- | server/sbus/sssd_dbus_server.c | 316 |
1 files changed, 316 insertions, 0 deletions
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 <http://www.gnu.org/licenses/>. +*/ +#include <sys/time.h> +#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; +} |