diff options
author | Søren Sandmann Pedersen <sandmann@daimi.au.dk> | 2009-04-19 20:21:14 -0400 |
---|---|---|
committer | Søren Sandmann Pedersen <sandmann@daimi.au.dk> | 2009-04-19 20:21:14 -0400 |
commit | a7e801c5ab9e6257011007a4ac08cd604843dd96 (patch) | |
tree | fe272658d428ee7e4d18af6a841482aeda47ec97 | |
parent | 1592cccff1d81879726c36c030b6790e7b2c4c6e (diff) |
First part of moving lowlevel dbus code to its own file
-rw-r--r-- | Makefile.am | 2 | ||||
-rw-r--r-- | dbus-int.c | 406 | ||||
-rw-r--r-- | libnul-private.h | 15 |
3 files changed, 422 insertions, 1 deletions
diff --git a/Makefile.am b/Makefile.am index 35c6f3a..1896093 100644 --- a/Makefile.am +++ b/Makefile.am @@ -8,7 +8,7 @@ libnul_la_SOURCES = \ dbus.c \ array.c \ epoll.c \ - libdbus.c \ + dbus-int.c \ signal-handler.c \ file-utils.c \ libnul.h diff --git a/dbus-int.c b/dbus-int.c new file mode 100644 index 0000000..f398bd1 --- /dev/null +++ b/dbus-int.c @@ -0,0 +1,406 @@ +/* This file deals with the pain and suffering of using libdbus. + * + * Some day, I'll implement dbus directly here. + */ + +#include <dbus/dbus.h> +#include <string.h> +#include "libnul-private.h" +typedef struct object_info_t object_info_t; +struct object_info_t +{ + char * name; + message_func_t func; + gpointer data; +}; + +struct connection_t +{ + DBusConnection *dconnection; + + object_info_t **objects; +}; + +static void +process_watch (DBusWatch *watch, int flags) +{ + dbus_watch_handle (watch, flags); +} + +static void +on_hangup (gpointer data) +{ + DBusWatch *watch = data; + + process_watch (watch, DBUS_WATCH_HANGUP); +} + +static void +on_error (gpointer data) +{ + DBusWatch *watch = data; + + process_watch (watch, DBUS_WATCH_ERROR); +} + +static void +on_read (gpointer data) +{ + GList *list = data; + + for (list = data; list != NULL; list = list->next) + { + DBusWatch *watch = list->data; + + if (dbus_watch_get_enabled (watch) && + (dbus_watch_get_flags (watch) & DBUS_WATCH_READABLE)) + { + process_watch (watch, DBUS_WATCH_READABLE); + } + } +} + +static void +on_write (gpointer data) +{ + GList *list = data; + + for (list = data; list != NULL; list = list->next) + { + DBusWatch *watch = list->data; + + if (dbus_watch_get_enabled (watch) && + (dbus_watch_get_flags (watch) & DBUS_WATCH_WRITABLE)) + { + process_watch (watch, DBUS_WATCH_WRITABLE); + } + } +} + +static void +update_fd (int fd) +{ + int enabled, flags; + GList *watches, *list; + + watches = nul_fd_get_data (fd); + + enabled = FALSE; + flags = 0; + + for (list = watches; list != NULL; list = list->next) + { + DBusWatch *watch = list->data; + + if (dbus_watch_get_enabled (watch)) + { + enabled = TRUE; + flags |= dbus_watch_get_flags (watch); + } + } + + if (enabled) + { + nul_fd_set_error_callback (fd, on_hangup); + nul_fd_set_hangup_callback (fd, on_error); + + if (flags & DBUS_WATCH_READABLE) + nul_fd_set_read_callback (fd, on_read); + else + nul_fd_set_read_callback (fd, NULL); + + if (flags & DBUS_WATCH_WRITABLE) + nul_fd_set_write_callback (fd, on_write); + else + nul_fd_set_write_callback (fd, NULL); + } + else + { + nul_fd_set_error_callback (fd, NULL); + nul_fd_set_hangup_callback (fd, NULL); + nul_fd_set_read_callback (fd, NULL); + nul_fd_set_write_callback (fd, NULL); + } +} + +static dbus_bool_t +add_watch (DBusWatch *watch, void *data) +{ + DBusConnection *connection = data; + int fd = dbus_watch_get_unix_fd (watch); + + dbus_watch_set_data (watch, connection, NULL); + + /* DBus apparently will create multiple watches for + * the same fd. + */ + if (nul_fd_is_watched (fd)) + { + GList *watches = nul_fd_get_data (fd); + + watches = g_list_prepend (watches, watch); + + nul_fd_set_data (fd, watches); + } + else + { + nul_fd_add_watch (fd, g_list_prepend (NULL, watch)); + } + + update_fd (fd); + + return TRUE; +} + +static void +remove_watch (DBusWatch *watch, void *data) +{ + int fd = dbus_watch_get_unix_fd (watch); + GList *watches = nul_fd_get_data (fd); + + watches = g_list_remove (watches, watch); + + if (!watches) + { + nul_fd_remove_watch (fd); + } + else + { + nul_fd_set_data (fd, watches); + update_fd (fd); + } +} + +static void +toggle_watch (DBusWatch *watch, void *data) +{ + update_fd (dbus_watch_get_unix_fd (watch)); +} + +static gboolean +on_timeout (gpointer data) +{ + DBusTimeout *timeout = data; + + dbus_timeout_handle (timeout); + + return TRUE; +} + +static dbus_bool_t +add_timeout (DBusTimeout *timeout, void *data) +{ + dbus_timeout_set_data (timeout, GINT_TO_POINTER (0), NULL); + + if (dbus_timeout_get_enabled (timeout)) + { + int id; + + id = g_timeout_add (dbus_timeout_get_interval (timeout), + on_timeout, timeout); + + dbus_timeout_set_data (timeout, GINT_TO_POINTER (id), NULL); + } + + return TRUE; +} + +static void +remove_timeout (DBusTimeout *timeout, void *data) +{ + int id = GPOINTER_TO_INT (dbus_timeout_get_data (timeout)); + + if (id) + { + g_source_remove (id); + + dbus_timeout_set_data (timeout, GINT_TO_POINTER (0), NULL); + } +} + +static void +toggle_timeout (DBusTimeout *timeout, void *data) +{ + remove_timeout (timeout, NULL); + + add_timeout (timeout, NULL); +} + +static dbus_int32_t idle_id_slot = -1; + +static int +get_idle_id (DBusConnection *connection) +{ + if (idle_id_slot == -1) + dbus_connection_allocate_data_slot (&idle_id_slot); + + return (int)dbus_connection_get_data (connection, idle_id_slot); +} + +static void +set_idle_id (DBusConnection *connection, int id) +{ + if (idle_id_slot == -1) + dbus_connection_allocate_data_slot (&idle_id_slot); + + dbus_connection_set_data (connection, idle_id_slot, (void *)id, NULL); +} + +static gboolean +do_dispatch (gpointer data) +{ + DBusConnection *connection = data; + + while (dbus_connection_dispatch (connection) == DBUS_DISPATCH_DATA_REMAINS) + ; + + set_idle_id (connection, 0); + + return FALSE; +} + +static void +on_dispatch_status_changed (DBusConnection *connection, + DBusDispatchStatus new_status, + void *data) +{ + if (!get_idle_id (connection)) + set_idle_id (connection, g_idle_add (do_dispatch, connection)); +} + +static connection_t * +ensure_connection (connection_t **connection, + DBusBusType type, + DBusError *err) +{ + if (!*connection) + { + DBusConnection *dconn; + + dconn = dbus_bus_get (type, err); + + if (dconn) + { + connection_t *conn; + + dbus_connection_set_dispatch_status_function ( + dconn, + on_dispatch_status_changed, *connection, NULL); + + dbus_connection_set_watch_functions ( + dconn, + add_watch, remove_watch, toggle_watch, + dconn, NULL); + + dbus_connection_set_timeout_functions ( + dconn, + add_timeout, remove_timeout, toggle_timeout, + dconn, NULL); + + do_dispatch (dconn); + + conn = g_new0 (connection_t, 1); + conn->dconnection = dconn; + conn->objects = nul_array_new (object_info_t *); + + *connection = conn; + } + } + + return *connection; +} + +static connection_t * +get_connection (DBusBusType type, DBusError *err) +{ + static connection_t *session_bus; + static connection_t *system_bus; + + if (type == DBUS_BUS_SESSION) + return ensure_connection (&session_bus, DBUS_BUS_SESSION, err); + else if (type == DBUS_BUS_SYSTEM) + return ensure_connection (&system_bus, DBUS_BUS_SYSTEM, err); + else + return NULL; +} + +connection_t * +connection_new_session (void) +{ + return get_connection (DBUS_BUS_SESSION, NULL /* FIXME */); +} + +connection_t * +connection_new_system (void) +{ + return get_connection (DBUS_BUS_SYSTEM, NULL /* FIXME */); +} + +static void +unregister_connection (DBusConnection *connection, + gpointer data) +{ + /* nothing */ +} + +static DBusHandlerResult +message_function (DBusConnection *connection, + DBusMessage *message, + gpointer data) +{ + object_info_t *info = data; + + /* Parse the message into something sensible here */ + + if (info->func ((void *)message, info->data)) + return DBUS_HANDLER_RESULT_HANDLED; + else + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +static const DBusObjectPathVTable vtable = +{ + unregister_connection, + message_function, + NULL, +}; + +void +connection_register_object (connection_t *connection, + const char *object_name, + message_func_t func, + nul_ptr_t data) +{ + object_info_t *info = g_new0 (object_info_t, 1); + info->name = g_strdup (object_name); + info->func = func; + info->data = data; + + connection->objects = nul_array_append (connection->objects, info); + + dbus_connection_register_object_path ( + connection->dconnection, object_name, &vtable, data); +} + +void +connection_unregister_object (connection_t *connection, + const char *object_name) +{ + int i; + + for (i = 0; connection->objects[i] != NULL; ++i) + { + object_info_t *info = connection->objects[i]; + + if (strcmp (info->name, object_name) == 0) + { + connection->objects = + nul_array_remove_fast (connection->objects, info); + + g_free (info->name); + g_free (info); + + break; + } + } +} diff --git a/libnul-private.h b/libnul-private.h new file mode 100644 index 0000000..df7cf3e --- /dev/null +++ b/libnul-private.h @@ -0,0 +1,15 @@ +#include "libnul.h" + +typedef struct connection_t connection_t; +typedef struct message_t message_t; +typedef gboolean (* message_func_t) (DBusMessage *message, + nul_ptr_t data); + +connection_t *connection_new_session (void); +connection_t *connection_new_system (void); +void connection_register_object (connection_t *connection, + const char *object_name, + message_func_t func, + nul_ptr_t data); +void connection_unregister_object (connection_t *connection, + const char *object_name); |