summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSøren Sandmann Pedersen <sandmann@daimi.au.dk>2009-04-19 20:21:14 -0400
committerSøren Sandmann Pedersen <sandmann@daimi.au.dk>2009-04-19 20:21:14 -0400
commita7e801c5ab9e6257011007a4ac08cd604843dd96 (patch)
treefe272658d428ee7e4d18af6a841482aeda47ec97
parent1592cccff1d81879726c36c030b6790e7b2c4c6e (diff)
First part of moving lowlevel dbus code to its own file
-rw-r--r--Makefile.am2
-rw-r--r--dbus-int.c406
-rw-r--r--libnul-private.h15
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);