summaryrefslogtreecommitdiff
path: root/libnm/nm-dbus-helpers.c
diff options
context:
space:
mode:
Diffstat (limited to 'libnm/nm-dbus-helpers.c')
-rw-r--r--libnm/nm-dbus-helpers.c318
1 files changed, 245 insertions, 73 deletions
diff --git a/libnm/nm-dbus-helpers.c b/libnm/nm-dbus-helpers.c
index 4329adfb96..0d8e0f2be6 100644
--- a/libnm/nm-dbus-helpers.c
+++ b/libnm/nm-dbus-helpers.c
@@ -21,59 +21,100 @@
#include <string.h>
#include <config.h>
#include <gio/gio.h>
-#include <dbus/dbus.h>
-#include <dbus/dbus-glib-lowlevel.h>
#include "nm-dbus-helpers.h"
#include "nm-dbus-interface.h"
-static dbus_int32_t priv_slot = -1;
-static DBusBusType nm_bus = DBUS_BUS_SYSTEM;
+#define NM_DBUS_PRIVATE_CONNECTION_TAG "libnm-private-connection"
+static GBusType nm_bus = G_BUS_TYPE_SYSTEM;
-static void
-_ensure_nm_dbus_helpers_inited (void)
+GBusType
+_nm_dbus_bus_type (void)
{
static gsize init_value = 0;
if (g_once_init_enter (&init_value)) {
- dbus_connection_allocate_data_slot (&priv_slot);
- g_assert (priv_slot != -1);
-
if (g_getenv ("LIBNM_USE_SESSION_BUS"))
- nm_bus = DBUS_BUS_SESSION;
+ nm_bus = G_BUS_TYPE_SESSION;
g_once_init_leave (&init_value, 1);
}
+
+ return nm_bus;
}
-DBusGConnection *
-_nm_dbus_new_connection (GCancellable *cancellable,
- GError **error)
+GDBusConnection *
+_nm_dbus_new_connection (GCancellable *cancellable, GError **error)
{
- DBusGConnection *connection = NULL;
+ GDBusConnection *connection = NULL;
- _ensure_nm_dbus_helpers_inited ();
-
-#if HAVE_DBUS_GLIB_100
/* If running as root try the private bus first */
- if (0 == geteuid () && nm_bus == DBUS_BUS_SYSTEM) {
- connection = dbus_g_connection_open ("unix:path=" NMRUNDIR "/private", error);
- if (connection) {
- DBusConnection *dbus_connection = dbus_g_connection_get_connection (connection);
+ if (0 == geteuid ()) {
+ GError *local = NULL;
+ connection = g_dbus_connection_new_for_address_sync ("unix:path=" NMRUNDIR "/private",
+ G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
+ NULL, cancellable, &local);
+ if (connection) {
/* Mark this connection as private */
- dbus_connection_set_data (dbus_connection, priv_slot, GUINT_TO_POINTER (TRUE), NULL);
- dbus_connection_set_exit_on_disconnect (dbus_connection, FALSE);
+ g_object_set_data (G_OBJECT (connection),
+ NM_DBUS_PRIVATE_CONNECTION_TAG,
+ GUINT_TO_POINTER (TRUE));
return connection;
}
- /* Fall back to a bus if for some reason private socket isn't available */
- g_clear_error (error);
+
+ if (g_error_matches (local, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+ g_propagate_error (error, local);
+ return NULL;
+ }
+ g_error_free (local);
}
-#endif
- if (connection == NULL)
- connection = dbus_g_bus_get (nm_bus, error);
+ return g_bus_get_sync (_nm_dbus_bus_type (), cancellable, error);
+}
- return connection;
+static void
+new_connection_async_got_system (GObject *source, GAsyncResult *result, gpointer user_data)
+{
+ GSimpleAsyncResult *simple = user_data;
+ GDBusConnection *connection;
+ GError *error = NULL;
+
+ connection = g_bus_get_finish (result, &error);
+ if (connection)
+ g_simple_async_result_set_op_res_gpointer (simple, connection, g_object_unref);
+ else
+ g_simple_async_result_take_error (simple, error);
+
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+}
+
+static void
+new_connection_async_got_private (GObject *source, GAsyncResult *result, gpointer user_data)
+{
+ GSimpleAsyncResult *simple = user_data;
+ GDBusConnection *connection;
+ GError *error = NULL;
+
+ connection = g_dbus_connection_new_for_address_finish (result, &error);
+ if (connection) {
+ g_simple_async_result_set_op_res_gpointer (simple, connection, g_object_unref);
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+ return;
+ }
+
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+ g_simple_async_result_take_error (simple, error);
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+ return;
+ }
+
+ g_clear_error (&error);
+ g_bus_get (_nm_dbus_bus_type (),
+ g_object_get_data (G_OBJECT (simple), "cancellable"),
+ new_connection_async_got_system, simple);
}
void
@@ -82,22 +123,26 @@ _nm_dbus_new_connection_async (GCancellable *cancellable,
gpointer user_data)
{
GSimpleAsyncResult *simple;
- DBusGConnection *connection;
- GError *error = NULL;
- simple = g_simple_async_result_new (NULL, callback, user_data,
- _nm_dbus_new_connection_async);
- connection = _nm_dbus_new_connection (cancellable, &error);
- if (connection)
- g_simple_async_result_set_op_res_gpointer (simple, connection, (GDestroyNotify) dbus_g_connection_unref);
- else
- g_simple_async_result_take_error (simple, error);
+ simple = g_simple_async_result_new (NULL, callback, user_data, _nm_dbus_new_connection_async);
- g_simple_async_result_complete_in_idle (simple);
- g_object_unref (simple);
+ /* If running as root try the private bus first */
+ if (0 == geteuid ()) {
+ g_object_set_data_full (G_OBJECT (simple), "cancellable",
+ g_object_ref (cancellable), g_object_unref);
+ g_dbus_connection_new_for_address ("unix:path=" NMRUNDIR "/private",
+ G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
+ NULL,
+ cancellable,
+ new_connection_async_got_private, simple);
+ } else {
+ g_bus_get (_nm_dbus_bus_type (),
+ cancellable,
+ new_connection_async_got_system, simple);
+ }
}
-DBusGConnection *
+GDBusConnection *
_nm_dbus_new_connection_finish (GAsyncResult *result,
GError **error)
{
@@ -106,68 +151,195 @@ _nm_dbus_new_connection_finish (GAsyncResult *result,
if (g_simple_async_result_propagate_error (simple, error))
return NULL;
- return dbus_g_connection_ref (g_simple_async_result_get_op_res_gpointer (simple));
+ return g_object_ref (g_simple_async_result_get_op_res_gpointer (simple));
}
gboolean
-_nm_dbus_is_connection_private (DBusGConnection *connection)
+_nm_dbus_is_connection_private (GDBusConnection *connection)
{
- if (priv_slot == -1)
- return FALSE;
- return !!dbus_connection_get_data (dbus_g_connection_get_connection (connection), priv_slot);
+ return !!g_object_get_data (G_OBJECT (connection), NM_DBUS_PRIVATE_CONNECTION_TAG);
}
-DBusGProxy *
-_nm_dbus_new_proxy_for_connection (DBusGConnection *connection,
+static GHashTable *proxy_types;
+
+#undef _nm_dbus_register_proxy_type
+void
+_nm_dbus_register_proxy_type (const char *interface,
+ GType proxy_type)
+{
+ if (!proxy_types)
+ proxy_types = g_hash_table_new (g_str_hash, g_str_equal);
+
+ g_assert (g_hash_table_lookup (proxy_types, interface) == NULL);
+ g_hash_table_insert (proxy_types, (char *) interface, GSIZE_TO_POINTER (proxy_type));
+}
+
+/* We don't (currently) use GDBus's property-handling code */
+#define NM_DBUS_PROXY_FLAGS (G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | \
+ G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START)
+
+GDBusProxy *
+_nm_dbus_new_proxy_for_connection (GDBusConnection *connection,
const char *path,
const char *interface,
GCancellable *cancellable,
GError **error)
{
- /* Private connections can't use dbus_g_proxy_new_for_name() or
- * dbus_g_proxy_new_for_name_owner() because peer-to-peer connections don't
- * have either a bus daemon or name owners, both of which those functions
- * require.
- */
+ GType proxy_type;
+ const char *name;
+
+ proxy_type = GPOINTER_TO_SIZE (g_hash_table_lookup (proxy_types, interface));
+ if (!proxy_type)
+ proxy_type = G_TYPE_DBUS_PROXY;
+
if (_nm_dbus_is_connection_private (connection))
- return dbus_g_proxy_new_for_peer (connection, path, interface);
+ name = NULL;
+ else
+ name = NM_DBUS_SERVICE;
- return dbus_g_proxy_new_for_name (connection, NM_DBUS_SERVICE, path, interface);
+ return g_initable_new (proxy_type, cancellable, error,
+ "g-connection", connection,
+ "g-flags", NM_DBUS_PROXY_FLAGS,
+ "g-name", name,
+ "g-object-path", path,
+ "g-interface-name", interface,
+ NULL);
}
void
-_nm_dbus_new_proxy_for_connection_async (DBusGConnection *connection,
+_nm_dbus_new_proxy_for_connection_async (GDBusConnection *connection,
const char *path,
const char *interface,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
- GSimpleAsyncResult *simple;
- DBusGProxy *proxy;
- GError *error = NULL;
+ GType proxy_type;
+ const char *name;
+
+ proxy_type = GPOINTER_TO_SIZE (g_hash_table_lookup (proxy_types, interface));
+ if (!proxy_type)
+ proxy_type = G_TYPE_DBUS_PROXY;
- simple = g_simple_async_result_new (NULL, callback, user_data,
- _nm_dbus_new_proxy_for_connection_async);
- proxy = _nm_dbus_new_proxy_for_connection (connection, path, interface,
- cancellable, &error);
- if (proxy)
- g_simple_async_result_set_op_res_gpointer (simple, proxy, g_object_unref);
+ if (_nm_dbus_is_connection_private (connection))
+ name = NULL;
else
- g_simple_async_result_take_error (simple, error);
+ name = NM_DBUS_SERVICE;
- g_simple_async_result_complete_in_idle (simple);
- g_object_unref (simple);
+ g_async_initable_new_async (proxy_type, G_PRIORITY_DEFAULT,
+ cancellable, callback, user_data,
+ "g-connection", connection,
+ "g-flags", NM_DBUS_PROXY_FLAGS,
+ "g-name", name,
+ "g-object-path", path,
+ "g-interface-name", interface,
+ NULL);
}
-DBusGProxy *
+GDBusProxy *
_nm_dbus_new_proxy_for_connection_finish (GAsyncResult *result,
GError **error)
{
- GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
+ GObject *source, *proxy;
- if (g_simple_async_result_propagate_error (simple, error))
- return NULL;
+ source = g_async_result_get_source_object (result);
+ proxy = g_async_initable_new_finish (G_ASYNC_INITABLE (source), result, error);
+ g_object_unref (source);
- return g_object_ref (g_simple_async_result_get_op_res_gpointer (simple));
+ return G_DBUS_PROXY (proxy);
+}
+
+void
+_nm_dbus_register_error_domain (GQuark domain,
+ const char *interface,
+ GType enum_type)
+{
+ GEnumClass *enum_class;
+ GEnumValue *e;
+ char *error_name;
+ int i;
+
+ enum_class = g_type_class_ref (enum_type);
+ for (i = 0; i < enum_class->n_values; i++) {
+ e = &enum_class->values[i];
+ error_name = g_strdup_printf ("%s.%s", interface, e->value_nick);
+ g_dbus_error_register_error (domain, e->value, error_name);
+ g_free (error_name);
+ }
+
+ g_type_class_unref (enum_class);
+}
+
+/* Binds the properties on a generated server-side GDBus object to the
+ * corresponding properties on the public object.
+ */
+void
+_nm_dbus_bind_properties (gpointer object, gpointer skeleton)
+{
+ GParamSpec **properties;
+ guint n_properties;
+ int i;
+
+ properties = g_object_class_list_properties (G_OBJECT_GET_CLASS (skeleton), &n_properties);
+ for (i = 0; i < n_properties; i++) {
+ if (g_str_has_prefix (properties[i]->name, "g-"))
+ continue;
+
+ g_object_bind_property (object, properties[i]->name,
+ skeleton, properties[i]->name,
+ G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
+ }
+}
+
+static char *
+signal_name_from_method_name (const char *method_name)
+{
+ GString *signal_name;
+ const char *p;
+
+ signal_name = g_string_new ("handle");
+ for (p = method_name; *p; p++) {
+ if (g_ascii_isupper (*p))
+ g_string_append_c (signal_name, '-');
+ g_string_append_c (signal_name, g_ascii_tolower (*p));
+ }
+
+ return g_string_free (signal_name, FALSE);
+}
+
+static void
+_nm_dbus_method_meta_marshal (GClosure *closure, GValue *return_value,
+ guint n_param_values, const GValue *param_values,
+ gpointer invocation_hint, gpointer marshal_data)
+{
+ closure->marshal (closure, return_value, n_param_values,
+ param_values, invocation_hint,
+ ((GCClosure *)closure)->callback);
+
+ g_value_set_boolean (return_value, TRUE);
+}
+
+/* Takes (method_name, handler_func) pairs and connects the handlers to the
+ * signals on skeleton, with object as the user_data, but swapped so it comes
+ * first in the argument list, and handling the return value automatically.
+ */
+void
+_nm_dbus_bind_methods (gpointer object, gpointer skeleton, ...)
+{
+ va_list ap;
+ const char *method_name;
+ char *signal_name;
+ GCallback handler;
+ GClosure *closure;
+
+ va_start (ap, skeleton);
+ while ( (method_name = va_arg (ap, const char *))
+ && (handler = va_arg (ap, GCallback))) {
+ signal_name = signal_name_from_method_name (method_name);
+ closure = g_cclosure_new_swap (handler, object, NULL);
+ g_closure_set_meta_marshal (closure, NULL, _nm_dbus_method_meta_marshal);
+ g_signal_connect_closure (skeleton, signal_name, closure, FALSE);
+ g_free (signal_name);
+ }
+ va_end (ap);
}