From 054a931b01f98cf94b42f1ff1f48fbcb4928c869 Mon Sep 17 00:00:00 2001 From: Stephen Gallagher Date: Fri, 24 Oct 2008 07:58:00 -0400 Subject: Integrate D-BUS support for use as IPC between parts. Integrates DBUS with the event system so that it is asynchronous. --- server/Makefile.in | 11 +- server/configure.ac | 2 + server/dbus/sssd_dbus_client.c | 237 ++++++++++++++++++++++++++++++++++++++++ server/dbus/sssd_dbus_client.h | 67 ++++++++++++ server/dbus/sssd_dbus_common.c | 40 +++++++ server/dbus/sssd_dbus_common.h | 14 +++ server/dbus/sssd_dbus_server.c | 210 +++++++++++++++++++++++++++++++++++ server/dbus/sssd_dbus_server.h | 69 ++++++++++++ server/dbus/tests/test_client.c | 123 +++++++++++++++++++++ server/monitor.c | 108 +++++++++++++++++- server/monitor.h | 27 +++++ server/server.mk | 26 ++++- 12 files changed, 923 insertions(+), 11 deletions(-) create mode 100644 server/dbus/sssd_dbus_client.c create mode 100644 server/dbus/sssd_dbus_client.h create mode 100644 server/dbus/sssd_dbus_common.c create mode 100644 server/dbus/sssd_dbus_common.h create mode 100644 server/dbus/sssd_dbus_server.c create mode 100644 server/dbus/sssd_dbus_server.h create mode 100644 server/dbus/tests/test_client.c diff --git a/server/Makefile.in b/server/Makefile.in index 262e1c95b..f2d2c69fb 100644 --- a/server/Makefile.in +++ b/server/Makefile.in @@ -33,6 +33,9 @@ POPT_CFLAGS = @POPT_CFLAGS@ LDB_LIBS = @LDB_LIBS@ LDB_CFLAGS = @LDB_CFLAGS@ +DBUS_LIBS = @DBUS_LIBS@ +DBUS_CFLAGS = @DBUS_CFLAGS@ + LIBDL = @LIBDL@ SHLIBEXT = @SHLIBEXT@ @@ -42,11 +45,11 @@ SHLD = @SHLD@ SHLD_FLAGS = @SHLD_FLAGS@ LDFLAGS += @LDFLAGS@ -LIBS = @LIBS@ $(TALLOC_LIBS) $(TDB_LIBS) $(EVENTS_LIBS) $(POPT_LIBS) $(LDB_LIBS) +LIBS = @LIBS@ $(TALLOC_LIBS) $(TDB_LIBS) $(EVENTS_LIBS) $(POPT_LIBS) $(LDB_LIBS) $(DBUS_LIBS) PICFLAG = @PICFLAG@ CFLAGS += -g -I$(srcdir)/include -Iinclude -I$(srcdir) -I$(srcdir)/.. \ - $(POPT_CFLAGS) $(TALLOC_CFLAGS) $(TDB_CFLAGS) $(EVENTS_CFLAGS) $(LDB_FLAGS)\ + $(POPT_CFLAGS) $(TALLOC_CFLAGS) $(TDB_CFLAGS) $(EVENTS_CFLAGS) $(LDB_CFLAGS) $(DBUS_CFLAGS)\ -DLIBDIR=\"$(libdir)\" -DSHLIBEXT=\"$(SHLIBEXT)\" -DUSE_MMAP=1 @CFLAGS@ MDLD = @MDLD@ @@ -56,7 +59,7 @@ OBJS = $(SERVER_OBJ) @LIBREPLACEOBJ@ $(EXTRA_OBJ) headers = .h -BINS = sbin/sssd +BINS = sbin/sssd sbin/sssd-dbus-client DIRS = sbin @@ -77,7 +80,7 @@ clean:: distclean:: clean rm -rf $(DIRS) - rm -f config.log config.status config.cache include/config.h + rm -f config.log config.status config.cache config.h rm -f Makefile realdistclean:: distclean diff --git a/server/configure.ac b/server/configure.ac index b334d8fae..1b01a2ec2 100644 --- a/server/configure.ac +++ b/server/configure.ac @@ -37,6 +37,8 @@ m4_include(libldb.m4) m4_include(libevents.m4) m4_include(util/signal.m4) +PKG_CHECK_MODULES(DBUS,dbus-1) + AC_SUBST(TESTS) AC_SUBST(EXTRA_OBJ) diff --git a/server/dbus/sssd_dbus_client.c b/server/dbus/sssd_dbus_client.c new file mode 100644 index 000000000..48f1ae456 --- /dev/null +++ b/server/dbus/sssd_dbus_client.c @@ -0,0 +1,237 @@ +#include "dbus/sssd_dbus_common.h" +#include "dbus/sssd_dbus_client.h" +#include "util/util.h" +#include +#include "events.h" + +const char* print_status(int status) { + switch (status){ + case DBUS_DISPATCH_DATA_REMAINS: + return "DBUS_DISPATCH_DATA_REMAINS"; + case DBUS_DISPATCH_COMPLETE: + return "DBUS_DISPATCH_COMPLETE"; + case DBUS_DISPATCH_NEED_MEMORY: + return "DBUS_DISPATCH_NEED_MEMORY"; + default: + return "ERROR"; + } +} + +void do_dispatch(struct event_context *ev, + struct timed_event *te, + struct timeval t, void *ptr) { + struct timed_event *new_event; + DBusConnection *conn = (DBusConnection *)ptr; + + /* Dispatch only once each time through the mainloop to avoid + * starving other features + */ + if(dbus_connection_get_dispatch_status(conn) != 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. + */ + if(dbus_connection_get_dispatch_status(conn) != DBUS_DISPATCH_COMPLETE) { + new_event = event_add_timed(ev, ev, t, do_dispatch, conn); + if (new_event == 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 integrate_connection_with_event_loop(struct event_context *event_ctx, + DBusConnection *dbus_conn) { + struct dbus_connection_toplevel_context *dt_ctx; + dt_ctx = talloc_zero(event_ctx, struct dbus_connection_toplevel_context); + dt_ctx->ev = event_ctx; + dt_ctx->conn = dbus_conn; + + /* Set up DBusWatch functions */ + if (!dbus_connection_set_watch_functions(dt_ctx->conn, add_connection_watch, + remove_watch, toggle_connection_watch, dt_ctx, NULL)) { + DEBUG(0,("Error setting up D-BUS connection watch functions\n")); + return -1; + } + + /* Set up DBusTimeout functions */ + if (!dbus_connection_set_timeout_functions(dt_ctx->conn, add_connection_timeout, + remove_timeout, toggle_connection_timeout, dt_ctx, NULL)) { + DEBUG(0,("Error setting up D-BUS server timeout functions\n")); + return -1; + } + + /* Set up dispatch handler */ + dbus_connection_set_wakeup_main_function(dt_ctx->conn, + dbus_connection_wakeup_main, dt_ctx, NULL); + + /* 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. + */ + dbus_connection_wakeup_main(dt_ctx); + + return 0; +} + +/* + * add_connection_watch + * Set up hooks into the libevents mainloop for + * D-BUS to add file descriptor-based events + */ +dbus_bool_t add_connection_watch(DBusWatch *watch, void *data) { + unsigned int flags; + unsigned int event_flags; + struct dbus_connection_toplevel_context *dt_ctx; + struct dbus_connection_watch_context *conn_w_ctx; + + if (!dbus_watch_get_enabled(watch)) { + return TRUE; + } + + dt_ctx = talloc_get_type(data, struct dbus_connection_toplevel_context); + + conn_w_ctx = talloc_zero(dt_ctx, struct dbus_connection_watch_context); + 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; + + /* 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, dbus_connection_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 + */ +void toggle_connection_watch(DBusWatch *watch, void *data) { + if (dbus_watch_get_enabled(watch)) + add_connection_watch(watch, data); + else + remove_watch(watch, data); +} + +/* + * add_connection_timeout + * Hook for D-BUS to add time-based events to the mainloop + */ +dbus_bool_t add_connection_timeout(DBusTimeout *timeout, void *data) { + struct dbus_connection_toplevel_context *dt_ctx; + struct dbus_connection_timeout_context *conn_t_ctx; + struct timeval tv; + + if (!dbus_timeout_get_enabled(timeout)) + return TRUE; + + dt_ctx = talloc_get_type(data, struct dbus_connection_toplevel_context); + + conn_t_ctx = talloc_zero(dt_ctx,struct dbus_connection_timeout_context); + 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, + dbus_connection_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; +} + +/* + * toggle_connection_timeout + * Hook for D-BUS to toggle the enabled/disabled state of a mainloop + * event + */ +void toggle_connection_timeout(DBusTimeout *timeout, void *data) { + if (dbus_timeout_get_enabled(timeout)) + add_connection_timeout(timeout, data); + else + remove_timeout(timeout, data); +} + +/* + * dbus_connection_read_write_handler + * Callback for D-BUS to handle messages on a file-descriptor + */ + +void dbus_connection_read_write_handler(struct event_context *ev, struct fd_event *fde, + uint16_t flags, void *ptr) { + struct dbus_connection_watch_context *conn_w_ctx; + conn_w_ctx = talloc_get_type(ptr,struct dbus_connection_watch_context); + + 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_ref(conn_w_ctx->top->conn); +} +/* + * dbus_connection_timeout_handler + * Callback for D-BUS to handle timed events + */ +void dbus_connection_timeout_handler(struct event_context *ev, struct timed_event *te, + struct timeval t, void *data) { + struct dbus_connection_timeout_context *conn_t_ctx; + conn_t_ctx = talloc_get_type(data, struct dbus_connection_timeout_context); + dbus_timeout_handle(conn_t_ctx->timeout); +} + +/* 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 + */ +void dbus_connection_wakeup_main(void *data) { + struct dbus_connection_toplevel_context *dct_ctx; + struct timeval tv; + struct timed_event *te; + dct_ctx = talloc_get_type(data, struct dbus_connection_toplevel_context); + 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->ev, tv, do_dispatch, dct_ctx->conn); + if (te == NULL) { + DEBUG(0,("Could not add dispatch event!\n")); + exit(1); + } +} diff --git a/server/dbus/sssd_dbus_client.h b/server/dbus/sssd_dbus_client.h new file mode 100644 index 000000000..8e1bc876f --- /dev/null +++ b/server/dbus/sssd_dbus_client.h @@ -0,0 +1,67 @@ +#ifndef CLIENT_DBUS_H_ +#define CLIENT_DBUS_H_ +/* + 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 "dbus/dbus.h" +#include "events.h" + +/* Types */ +struct dbus_connection_toplevel_context { + DBusConnection *conn; + struct event_context *ev; +}; + +struct dbus_connection_watch_context { + DBusWatch *watch; + int fd; + struct fd_event *fde; + struct dbus_connection_toplevel_context *top; +}; + +struct dbus_connection_timeout_context { + DBusTimeout *timeout; + struct timed_event *te; + struct dbus_connection_toplevel_context *top; +}; +/* Functions */ +int integrate_connection_with_event_loop(struct event_context *event_ctx, + DBusConnection *dbus_conn); +void dbus_connection_wakeup_main_setup(struct dbus_connection_toplevel_context *dct_ctx); + +dbus_bool_t add_connection_watch(DBusWatch *watch, void *data); +void toggle_connection_watch(DBusWatch *watch, void *data); + +dbus_bool_t add_connection_timeout(DBusTimeout *timeout, void *data); +void toggle_connection_timeout(DBusTimeout *timeout, void *data); +void dbus_connection_wakeup_main(void *data); + +void dbus_connection_read_write_handler(struct event_context *ev, struct fd_event *fde, uint16_t flags, void *ptr); +void dbus_connection_timeout_handler(struct event_context *ev, struct timed_event *te, struct timeval t, void *data); +void dbus_connection_wakeup_main_handler(struct event_context *ev_ctx, + struct signal_event *se, int signum, + int count, void *_info, void *data); + +void do_dispatch(struct event_context *ev, + struct timed_event *te, + struct timeval t, void *ptr); + +const char* print_status(int status); +#endif /*CLIENT_DBUS_H_*/ diff --git a/server/dbus/sssd_dbus_common.c b/server/dbus/sssd_dbus_common.c new file mode 100644 index 000000000..140d2f1a7 --- /dev/null +++ b/server/dbus/sssd_dbus_common.c @@ -0,0 +1,40 @@ +#include +#include "dbus/sssd_dbus_common.h" +#include "events.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; +} + +/* + * remove_watch + * Hook for D-BUS to remove file descriptor-based events + * from the libevents mainloop + */ +void remove_watch(DBusWatch *watch, void *data) { + struct fd_event *fde; + 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); +} + + +/* + * remove_timeout + * Hook for D-BUS to remove time-based events from the mainloop + */ +void 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); +} \ No newline at end of file diff --git a/server/dbus/sssd_dbus_common.h b/server/dbus/sssd_dbus_common.h new file mode 100644 index 000000000..e0683be8f --- /dev/null +++ b/server/dbus/sssd_dbus_common.h @@ -0,0 +1,14 @@ +#ifndef SSSD_DBUS_COMMON_H_ +#define SSSD_DBUS_COMMON_H_ + +#include "dbus/dbus.h" + +/* TODO: get this value from LDB */ +#define DBUS_ADDRESS "unix:path=/tmp/dbus-sgallagh.sock" + +/* Functions */ +struct timeval _dbus_timeout_get_interval_tv(int interval); +void remove_watch(DBusWatch *watch, void *data); +void remove_timeout(DBusTimeout *timeout, void *data); + +#endif /*SSSD_DBUS_COMMON_H_*/ diff --git a/server/dbus/sssd_dbus_server.c b/server/dbus/sssd_dbus_server.c new file mode 100644 index 000000000..288a33338 --- /dev/null +++ b/server/dbus/sssd_dbus_server.c @@ -0,0 +1,210 @@ +/* + 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 "dbus/dbus.h" +#include "monitor.h" +#include "dbus/sssd_dbus_common.h" +#include "dbus/sssd_dbus_server.h" +#include "dbus/sssd_dbus_client.h" +#include "events.h" +#include "util/util.h" + +/* + * integrate_server_with_event_loop + * Set up a D-BUS server to use the libevents mainloop + * for handling file descriptor and timed events + */ +int integrate_server_with_event_loop(struct event_context *event_ctx, + DBusServer *dbus_server, + void(*server_connection_setup)(DBusConnection *conn, struct event_context *)) { + struct dbus_server_toplevel_context *dt_ctx; + dt_ctx = talloc_zero(event_ctx, struct dbus_server_toplevel_context); + dt_ctx->ev = event_ctx; + dt_ctx->server = dbus_server; + dt_ctx->server_connection_setup = server_connection_setup; + + /* Set up D-BUS new connection handler */ + dbus_server_set_new_connection_function(dt_ctx->server, + new_connection_callback, dt_ctx, NULL); + + /* Set up DBusWatch functions */ + if (!dbus_server_set_watch_functions(dt_ctx->server, add_server_watch, + remove_watch, toggle_server_watch, dt_ctx, NULL)) { + DEBUG(0,("Error setting up D-BUS server watch functions")); + return -1; + } + + /* Set up DBusTimeout functions */ + if (!dbus_server_set_timeout_functions(dt_ctx->server, add_server_timeout, + remove_timeout, toggle_server_timeout, dt_ctx, NULL)) { + DEBUG(0,("Error setting up D-BUS server timeout functions")); + return -1; + } + + return 0; +} + +/* + * 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() + */ +void new_connection_callback(DBusServer *server, + DBusConnection *new_connection, void *data) { + + struct dbus_server_toplevel_context *dst_ctx; + dst_ctx = talloc_get_type(data,struct dbus_server_toplevel_context); + + if(integrate_connection_with_event_loop(dst_ctx->ev,new_connection) != 0) { + dbus_connection_close(new_connection); + DEBUG(0,("Closing connection (failed setup)")); + return; + } + dbus_connection_ref(new_connection); + + /* Run connection setup function */ + DEBUG(3,("Got a connection\n")); + dst_ctx->server_connection_setup(new_connection, dst_ctx->ev); + DEBUG(3,("New connection set up.\n")); +} + +/* + * add_server_watch + * Set up hooks into the libevents mainloop for + * D-BUS to add file descriptor-based events + */ +dbus_bool_t add_server_watch(DBusWatch *watch, void *data) { + unsigned int flags; + unsigned int event_flags; + struct dbus_server_toplevel_context *dt_ctx; + struct dbus_server_watch_context *svw_ctx; + + if (!dbus_watch_get_enabled(watch)) { + return FALSE; + } + + dt_ctx = talloc_get_type(data, struct dbus_server_toplevel_context); + + svw_ctx = talloc_zero(dt_ctx, struct dbus_server_watch_context); + 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; + } + svw_ctx->fde = event_add_fd(svw_ctx->top->ev, svw_ctx, svw_ctx->fd, + event_flags, dbus_server_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 + */ +void toggle_server_watch(DBusWatch *watch, void *data) { + if (dbus_watch_get_enabled(watch)) + add_server_watch(watch, data); + else + remove_watch(watch, data); +} + +/* + * add_server_timeout + * Hook for D-BUS to add time-based events to the mainloop + */ +dbus_bool_t add_server_timeout(DBusTimeout *timeout, void *data) { + struct dbus_server_toplevel_context *dt_ctx; + struct dbus_server_timeout_context *svt_ctx; + struct timeval tv; + + if (!dbus_timeout_get_enabled(timeout)) + return TRUE; + + dt_ctx = talloc_get_type(data, struct dbus_server_toplevel_context); + + svt_ctx = talloc_zero(dt_ctx,struct dbus_server_timeout_context); + 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(svt_ctx->top->ev, svt_ctx, tv, + dbus_server_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 + */ +void toggle_server_timeout(DBusTimeout *timeout, void *data) { + if (dbus_timeout_get_enabled(timeout)) + add_server_timeout(timeout, data); + else + remove_timeout(timeout, data); +} + +/* + * dbus_server_read_write_handler + * Callback for D-BUS to handle messages on a file-descriptor + */ +void dbus_server_read_write_handler(struct event_context *ev, struct fd_event *fde, + uint16_t flags, void *ptr) { + struct dbus_server_watch_context *svw_ctx; + svw_ctx = talloc_get_type(ptr,struct dbus_server_watch_context); + + 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_ref(svw_ctx->top->server); +} + +void dbus_server_timeout_handler(struct event_context *ev, struct timed_event *te, + struct timeval t, void *data) { + struct dbus_server_timeout_context *svt_ctx; + svt_ctx = talloc_get_type(data, struct dbus_server_timeout_context); + dbus_timeout_handle(svt_ctx->timeout); +} diff --git a/server/dbus/sssd_dbus_server.h b/server/dbus/sssd_dbus_server.h new file mode 100644 index 000000000..85fc12c6a --- /dev/null +++ b/server/dbus/sssd_dbus_server.h @@ -0,0 +1,69 @@ +/* + 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 . +*/ + +#ifndef MONITORDBUS_H_ +#define MONITORDBUS_H_ + +#include "dbus/dbus.h" +#include "monitor.h" +#include "events.h" +#include "sssd_dbus_common.h" + +/* Types */ +struct dbus_server_toplevel_context { + DBusServer *server; + struct event_context *ev; + void (*server_connection_setup)(DBusConnection *conn, struct event_context *); +}; + +struct dbus_server_watch_context { + DBusWatch *watch; + int fd; + struct fd_event *fde; + struct dbus_server_toplevel_context *top; +}; + +struct dbus_server_timeout_context { + DBusTimeout *timeout; + struct timed_event *te; + struct dbus_server_toplevel_context *top; +}; + +/* Functions */ +int integrate_server_with_event_loop( + struct event_context *event_ctx, + DBusServer *dbus_server, + void (*server_connection_setup)(DBusConnection *conn, struct event_context *) +); + +void new_connection_callback(DBusServer *server, + DBusConnection *new_connection, void *data); + +dbus_bool_t add_server_watch(DBusWatch *watch, void *data); +void toggle_server_watch(DBusWatch *watch, void *data); + +dbus_bool_t add_server_timeout(DBusTimeout *timeout, void *data); +void toggle_server_timeout(DBusTimeout *timeout, void *data); + +void dbus_server_read_write_handler(struct event_context *ev, struct fd_event *fde, uint16_t flags, void *ptr); +void dbus_server_timeout_handler(struct event_context *ev, struct timed_event *te, struct timeval t, void *data); + +#endif /*MONITORDBUS_H_*/ diff --git a/server/dbus/tests/test_client.c b/server/dbus/tests/test_client.c new file mode 100644 index 000000000..8a82284c8 --- /dev/null +++ b/server/dbus/tests/test_client.c @@ -0,0 +1,123 @@ +#include +#include +#include +#include "events.h" +#include "dbus/dbus.h" +#include "monitor.h" +#include "dbus/sssd_dbus_common.h" +#include "dbus/sssd_dbus_client.h" +#include "util/util.h" + +static void request_version_timed(struct event_context *ev, + DBusConnection *conn); + +static void print_version (DBusPendingCall *pending, void *ptr) { + 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); + + if (type == 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")); + } + } + else if (type == DBUS_MESSAGE_TYPE_ERROR) { + + } + else { + DEBUG(0, ("Received unexpected message")); + exit(4); + } +} + +static void test_timed_handler(struct event_context *ev, + struct timed_event *te, + struct timeval t, void *ptr) { + DBusConnection *conn; + DBusPendingCall *pending_reply; + DBusMessage *version_request; + DBusError error; + conn = (DBusConnection *) ptr; + + fprintf(stdout, "."); + fflush(stdout); + + dbus_error_init(&error); + version_request = dbus_message_new_method_call( + NULL, MONITOR_DBUS_PATH, MONITOR_DBUS_INTERFACE, + MONITOR_METHOD_VERSION); + + if(!dbus_connection_send_with_reply(conn, version_request, &pending_reply, -1)){ + /* 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(version_request); + + request_version_timed(ev,conn); +} + +static void request_version_timed(struct event_context *ev, DBusConnection *conn) { + struct timed_event *te = NULL; + struct timeval tv; + + gettimeofday(&tv, NULL); + tv.tv_sec += 5; + tv.tv_usec = 0; + te = event_add_timed(ev, ev, tv, test_timed_handler, conn); + if (te == NULL) { + DEBUG(0, ("failed to add event!\n")); + exit(1); + } +} + +int main (int argc, const char *argv[]) { + DBusError dbus_error; + DBusConnection *dbus_conn; + struct event_context *event_ctx; + + event_ctx = event_context_init(talloc_autofree_context()); + + dbus_error_init(&dbus_error); + dbus_conn = dbus_connection_open(DBUS_ADDRESS, &dbus_error); + if (dbus_conn == NULL) { + printf ("Error: name=%s, message=%s\n", dbus_error.name, dbus_error.message); + exit(1); + } + + integrate_connection_with_event_loop(event_ctx,dbus_conn); + dbus_connection_set_exit_on_disconnect (dbus_conn, TRUE); + + /* Set up a timed event to request the server version every + * five seconds and print it to the screen. + */ + request_version_timed(event_ctx,dbus_conn); + + /* Enter the main loop (and hopefully never return) */ + event_loop_wait(event_ctx); + + talloc_free(event_ctx); + return EXIT_SUCCESS; +} \ No newline at end of file diff --git a/server/monitor.c b/server/monitor.c index 2d3283fd3..45b21cd56 100644 --- a/server/monitor.c +++ b/server/monitor.c @@ -27,12 +27,9 @@ #include "util/util.h" #include "service.h" #include "confdb/confdb.h" - -struct mt_ctx { - struct event_context *ev; - struct confdb_ctx *cdb; - char **services; -}; +#include "dbus/dbus.h" +#include "dbus/sssd_dbus_server.h" +#include "dbus/sssd_dbus_client.h" struct mt_srv { const char *name; @@ -139,6 +136,11 @@ int start_monitor(TALLOC_CTX *mem_ctx, return EINVAL; } + /* Initialize D-BUS Server + * The monitor will act as a D-BUS server for all + * SSSD processes */ + monitor_dbus_init(event_ctx); + for (i = 0; ctx->services[i]; i++) { srv = talloc_zero(ctx, struct mt_srv); @@ -160,3 +162,97 @@ int start_monitor(TALLOC_CTX *mem_ctx, return EOK; } + + +/* + * monitor_dbus_init + * Set up the monitor service as a D-BUS Server + */ +int monitor_dbus_init(struct event_context *event_ctx) { + DBusError dbus_error; + DBusServer *dbus_server; + + /* Set up D-BUS server */ + dbus_error_init(&dbus_error); + dbus_server = dbus_server_listen(DBUS_ADDRESS, &dbus_error); + if (dbus_server == NULL) { + DEBUG(0,("Error: name=%s, message=%s\n", dbus_error.name, + dbus_error.message)); + } + + /* TODO: remove debug */ + DEBUG(2,("Server listening on %s\n", dbus_server_get_address(dbus_server))); + + integrate_server_with_event_loop(event_ctx, dbus_server, monitor_dbus_method_init); + + return 0; +} + +/* monitor_messsage_handler + * Receive messages and process them + */ +DBusHandlerResult monitor_message_handler(DBusConnection *conn, + DBusMessage *message, void *user_data) { + const char *method; + const char *path; + const char *msg_interface; + DBusMessage *reply = NULL; + + 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, MONITOR_DBUS_INTERFACE) != 0) + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + /* Validate the D-BUS path */ + if (strcmp(path, MONITOR_DBUS_PATH) == 0) { + /* TODO Fill in methods */ + if(strcmp(method,MONITOR_METHOD_VERSION) == 0) { + reply = dbus_get_monitor_version(message); + } + } + + if(reply) { + dbus_connection_send(conn,reply, NULL); + dbus_message_unref(reply); + } + + return reply ? DBUS_HANDLER_RESULT_HANDLED : + DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +/* dbus_get_monitor_version + * Return the monitor version over D-BUS + */ +DBusMessage *dbus_get_monitor_version(DBusMessage *message) { + DBusMessage *reply; + const char *version = MONITOR_VERSION; + + reply = dbus_message_new_method_return(message); + dbus_message_append_args(reply,DBUS_TYPE_STRING, &version, DBUS_TYPE_INVALID); + + return reply; +} + +/* monitor_dbus_method_init + * Initialize D-BUS methods on the monitor + * Sets up a callback to monitor_message_handler + */ +void monitor_dbus_method_init(DBusConnection *conn, struct event_context *event_ctx) { + DBusObjectPathVTable *monitor_vtable; + monitor_vtable = talloc_zero(event_ctx, DBusObjectPathVTable); + + DEBUG (3,("Initializing D-BUS methods.\n")); + monitor_vtable->message_function = monitor_message_handler; + + dbus_connection_register_object_path( + conn, MONITOR_DBUS_PATH, + monitor_vtable, event_ctx); + + DEBUG(3,("D-BUS method initialization complete.\n")); +} diff --git a/server/monitor.h b/server/monitor.h index 17094a851..074c5a81c 100644 --- a/server/monitor.h +++ b/server/monitor.h @@ -1,3 +1,30 @@ +#ifndef MONITOR_H_ +#define MONITOR_H_ + +#include "talloc.h" +#include "service_task.h" +#include "dbus/dbus.h" + +#define MONITOR_VERSION "0.1" +#define MONITOR_DBUS_INTERFACE "org.freeipa.sssd.monitor" +#define MONITOR_DBUS_PATH "/org/freeipa/sssd/monitor" + +/* D-BUS Methods */ +#define MONITOR_METHOD_VERSION "getVersion" + +struct mt_ctx { + struct event_context *ev; + struct confdb_ctx *cdb; + char **services; +}; + int start_monitor(TALLOC_CTX *mem_ctx, struct event_context *event_ctx, struct confdb_ctx *cdb); +int monitor_dbus_init(struct event_context *event_ctx); +void monitor_dbus_method_init(DBusConnection *conn, struct event_context *event_ctx); +DBusHandlerResult monitor_message_handler(DBusConnection *conn, + DBusMessage *message, void *user_data); +DBusMessage *dbus_get_monitor_version(DBusMessage *message); + +#endif /* MONITOR_H */ diff --git a/server/server.mk b/server/server.mk index 8558c7311..655b4fe31 100644 --- a/server/server.mk +++ b/server/server.mk @@ -1,4 +1,26 @@ -SERVER_OBJ = server.o monitor.o process.o service.o service_task.o util/debug.o util/signal.o util/become_daemon.o confdb/confdb.o nss/nsssrv.o nss/nsssrv_packet.o nss/nsssrv_cmd.o nss/nsssrv_ldb.o +SERVER_OBJ = \ + server.o \ + monitor.o \ + process.o \ + service.o \ + service_task.o \ + util/debug.o \ + util/signal.o \ + util/become_daemon.o \ + confdb/confdb.o \ + nss/nsssrv.o \ + nss/nsssrv_packet.o \ + nss/nsssrv_cmd.o \ + nss/nsssrv_ldb.o \ + dbus/sssd_dbus_server.o \ + dbus/sssd_dbus_client.o \ + dbus/sssd_dbus_common.o + +CLIENT_OBJ = \ + dbus/sssd_dbus_common.o \ + dbus/sssd_dbus_client.o \ + util/debug.o \ + dbus/tests/test_client.o install:: all ${INSTALLCMD} -d $(DESTDIR)$(sbindir) @@ -10,3 +32,5 @@ clean:: sbin/sssd: $(SERVER_OBJ) $(CC) -o sbin/sssd $(SERVER_OBJ) $(LDFLAGS) $(LIBS) +sbin/sssd-dbus-client: $(CLIENT_OBJ) + $(CC) -o sbin/sssd-dbus-client $(CLIENT_OBJ) $(LDFLAGS) $(LIBS) -- cgit