summaryrefslogtreecommitdiffstats
path: root/server/sbus/sssd_dbus_server.c
diff options
context:
space:
mode:
Diffstat (limited to 'server/sbus/sssd_dbus_server.c')
-rw-r--r--server/sbus/sssd_dbus_server.c316
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;
+}