1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 2 of the License, or (at your option) any later version.
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the
15 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
16 * Boston, MA 02110-1301 USA.
18 * Copyright 2013 Red Hat, Inc.
21 #include "nm-default.h"
23 #include "nm-dbus-helpers.h"
27 #include "nm-dbus-interface.h"
29 static GBusType nm_bus = G_BUS_TYPE_SYSTEM;
32 _nm_dbus_bus_type (void)
34 static gsize init_value = 0;
36 if (g_once_init_enter (&init_value)) {
37 if (g_getenv ("LIBNM_USE_SESSION_BUS"))
38 nm_bus = G_BUS_TYPE_SESSION;
40 g_once_init_leave (&init_value, 1);
47 _nm_dbus_new_connection (GCancellable *cancellable, GError **error)
49 return g_bus_get_sync (_nm_dbus_bus_type (), cancellable, error);
53 new_connection_async_got_system (GObject *source, GAsyncResult *result, gpointer user_data)
55 GSimpleAsyncResult *simple = user_data;
56 GDBusConnection *connection;
59 connection = g_bus_get_finish (result, &error);
61 g_simple_async_result_set_op_res_gpointer (simple, connection, g_object_unref);
63 g_simple_async_result_take_error (simple, error);
65 g_simple_async_result_complete (simple);
66 g_object_unref (simple);
70 _nm_dbus_new_connection_async (GCancellable *cancellable,
71 GAsyncReadyCallback callback,
74 GSimpleAsyncResult *simple;
76 simple = g_simple_async_result_new (NULL, callback, user_data, _nm_dbus_new_connection_async);
78 g_bus_get (_nm_dbus_bus_type (),
80 new_connection_async_got_system, simple);
84 _nm_dbus_new_connection_finish (GAsyncResult *result,
87 GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
89 if (g_simple_async_result_propagate_error (simple, error))
92 return g_object_ref (g_simple_async_result_get_op_res_gpointer (simple));
96 _nm_dbus_is_connection_private (GDBusConnection *connection)
98 return g_dbus_connection_get_unique_name (connection) == NULL;
101 static GHashTable *proxy_types;
103 #undef _nm_dbus_register_proxy_type
105 _nm_dbus_register_proxy_type (const char *interface,
109 proxy_types = g_hash_table_new (g_str_hash, g_str_equal);
111 g_assert (g_hash_table_lookup (proxy_types, interface) == NULL);
112 g_hash_table_insert (proxy_types, (char *) interface, GSIZE_TO_POINTER (proxy_type));
115 /* We don't (currently) use GDBus's property-handling code */
116 #define NM_DBUS_PROXY_FLAGS (G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | \
117 G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START)
119 /* D-Bus has an upper limit on number of Match rules and it's rather easy
120 * to hit as the proxy likes to add one for each object. Let's remove the Match
121 * rule the proxy added and ensure a less granular rule is present instead.
123 * Also, don't do this immediately since it has a performance penalty.
124 * Still better than loosing the signals altogether.
126 * Ideally, we should be able to tell glib not to hook its rules:
127 * https://bugzilla.gnome.org/show_bug.cgi?id=758749
130 _nm_dbus_proxy_replace_match (GDBusProxy *proxy)
132 GDBusConnection *connection = g_dbus_proxy_get_connection (proxy);
133 static unsigned match_counter = 1024;
136 nm_assert (!g_strcmp0 (g_dbus_proxy_get_name (proxy), NM_DBUS_SERVICE));
138 if (match_counter == 1) {
139 /* If we hit the low matches watermark, install a
140 * less granular one. */
141 g_dbus_connection_call (connection,
142 "org.freedesktop.DBus",
143 "/org/freedesktop/DBus",
144 "org.freedesktop.DBus",
146 g_variant_new ("(s)", "type='signal',sender='" NM_DBUS_SERVICE "'"),
148 G_DBUS_CALL_FLAGS_NONE,
160 /* Remove what this proxy added. */
161 match = g_strdup_printf ("type='signal',sender='" NM_DBUS_SERVICE "',"
162 "interface='%s',path='%s'",
163 g_dbus_proxy_get_interface_name (proxy),
164 g_dbus_proxy_get_object_path (proxy));
165 g_dbus_connection_call (connection,
166 "org.freedesktop.DBus",
167 "/org/freedesktop/DBus",
168 "org.freedesktop.DBus",
170 g_variant_new ("(s)", match),
172 G_DBUS_CALL_FLAGS_NONE,
181 _nm_dbus_new_proxy_for_connection (GDBusConnection *connection,
183 const char *interface,
184 GCancellable *cancellable,
191 proxy_type = GPOINTER_TO_SIZE (g_hash_table_lookup (proxy_types, interface));
193 proxy_type = G_TYPE_DBUS_PROXY;
195 if (_nm_dbus_is_connection_private (connection))
198 name = NM_DBUS_SERVICE;
200 proxy = g_initable_new (proxy_type, cancellable, error,
201 "g-connection", connection,
202 "g-flags", NM_DBUS_PROXY_FLAGS,
204 "g-object-path", path,
205 "g-interface-name", interface,
207 _nm_dbus_proxy_replace_match (proxy);
213 _nm_dbus_new_proxy_for_connection_async (GDBusConnection *connection,
215 const char *interface,
216 GCancellable *cancellable,
217 GAsyncReadyCallback callback,
223 proxy_type = GPOINTER_TO_SIZE (g_hash_table_lookup (proxy_types, interface));
225 proxy_type = G_TYPE_DBUS_PROXY;
227 if (_nm_dbus_is_connection_private (connection))
230 name = NM_DBUS_SERVICE;
232 g_async_initable_new_async (proxy_type, G_PRIORITY_DEFAULT,
233 cancellable, callback, user_data,
234 "g-connection", connection,
235 "g-flags", NM_DBUS_PROXY_FLAGS,
237 "g-object-path", path,
238 "g-interface-name", interface,
243 _nm_dbus_new_proxy_for_connection_finish (GAsyncResult *result,
249 source = g_async_result_get_source_object (result);
250 proxy = G_DBUS_PROXY (g_async_initable_new_finish (G_ASYNC_INITABLE (source), result, error));
251 g_object_unref (source);
252 _nm_dbus_proxy_replace_match (proxy);
257 /* Binds the properties on a generated server-side GDBus object to the
258 * corresponding properties on the public object.
261 _nm_dbus_bind_properties (gpointer object, gpointer skeleton)
263 GParamSpec **properties;
267 properties = g_object_class_list_properties (G_OBJECT_GET_CLASS (skeleton), &n_properties);
268 for (i = 0; i < n_properties; i++) {
269 if (g_str_has_prefix (properties[i]->name, "g-"))
272 g_object_bind_property (object, properties[i]->name,
273 skeleton, properties[i]->name,
274 G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
280 signal_name_from_method_name (const char *method_name)
282 GString *signal_name;
285 signal_name = g_string_new ("handle");
286 for (p = method_name; *p; p++) {
287 if (g_ascii_isupper (*p))
288 g_string_append_c (signal_name, '-');
289 g_string_append_c (signal_name, g_ascii_tolower (*p));
292 return g_string_free (signal_name, FALSE);
296 _nm_dbus_method_meta_marshal (GClosure *closure, GValue *return_value,
297 guint n_param_values, const GValue *param_values,
298 gpointer invocation_hint, gpointer marshal_data)
300 closure->marshal (closure, return_value, n_param_values,
301 param_values, invocation_hint,
302 ((GCClosure *)closure)->callback);
304 g_value_set_boolean (return_value, TRUE);
307 /* Takes (method_name, handler_func) pairs and connects the handlers to the
308 * signals on skeleton, with object as the user_data, but swapped so it comes
309 * first in the argument list, and handling the return value automatically.
312 _nm_dbus_bind_methods (gpointer object, gpointer skeleton, ...)
315 const char *method_name;
320 va_start (ap, skeleton);
321 while ( (method_name = va_arg (ap, const char *))
322 && (handler = va_arg (ap, GCallback))) {
323 signal_name = signal_name_from_method_name (method_name);
324 closure = g_cclosure_new_swap (handler, object, NULL);
325 g_closure_set_meta_marshal (closure, NULL, _nm_dbus_method_meta_marshal);
326 g_signal_connect_closure (skeleton, signal_name, closure, FALSE);
327 g_free (signal_name);