1 /*
2 * dbus-daemon.c - Source for TpDBusDaemon
3 *
4 * Copyright (C) 2005-2009 Collabora Ltd. <http://www.collabora.co.uk/>
5 * Copyright (C) 2005-2009 Nokia Corporation
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 #include "config.h"
23
24 #include <telepathy-glib/dbus.h>
25 #include <telepathy-glib/dbus-internal.h>
26
27 #include <dbus/dbus.h>
28 #include <dbus/dbus-glib-lowlevel.h>
29
30 #include <telepathy-glib/errors.h>
31 #include <telepathy-glib/interfaces.h>
32 #include <telepathy-glib/proxy-subclass.h>
33 #include <telepathy-glib/util.h>
34
35 #include "telepathy-glib/_gen/tp-cli-dbus-daemon-body.h"
36
37 #define DEBUG_FLAG TP_DEBUG_PROXY
38 #include "debug-internal.h"
39
40 /**
41 * TpDBusDaemonClass:
42 *
43 * The class of #TpDBusDaemon.
44 *
45 * Since: 0.7.1
46 */
47 struct _TpDBusDaemonClass
48 {
49 /*<private>*/
50 TpProxyClass parent_class;
51 gpointer priv;
52 };
53
54 /**
55 * TpDBusDaemon:
56 *
57 * A subclass of #TpProxy that represents the D-Bus daemon. It mainly provides
58 * functionality to manage well-known names on the bus.
59 *
60 * Since: 0.7.1
61 */
62 struct _TpDBusDaemon
63 {
64 /*<private>*/
65 TpProxy parent;
66
67 TpDBusDaemonPrivate *priv;
68 };
69
70 struct _TpDBusDaemonPrivate
71 {
72 /* dup'd name => _NameOwnerWatch */
73 GHashTable *name_owner_watches;
74 /* reffed */
75 DBusConnection *libdbus;
76 };
77
78 G_DEFINE_TYPE (TpDBusDaemon, tp_dbus_daemon, TP_TYPE_PROXY)
79
80 static gpointer starter_bus_daemon = NULL;
81
82 /**
83 * tp_dbus_daemon_dup:
84 * @error: Used to indicate error if %NULL is returned
85 *
86 * Returns a proxy for signals and method calls on the D-Bus daemon on which
87 * this process was activated (if it was launched by D-Bus service
88 * activation), or the session bus (otherwise).
89 *
90 * If it is not possible to connect to the appropriate bus, raise an error
91 * and return %NULL.
92 *
93 * The returned #TpDBusDaemon is cached; the same #TpDBusDaemon object will
94 * be returned by this function repeatedly, as long as at least one reference
95 * exists.
96 *
97 * Returns: (transfer full): a reference to a proxy for signals and method
98 * calls on the bus daemon, or %NULL
99 *
100 * Since: 0.7.26
101 */
102 TpDBusDaemon *
tp_dbus_daemon_dup(GError ** error)103 tp_dbus_daemon_dup (GError **error)
104 {
105 DBusGConnection *conn;
106
107 if (starter_bus_daemon != NULL)
108 return g_object_ref (starter_bus_daemon);
109
110 conn = _tp_dbus_starter_bus_conn (error);
111
112 if (conn == NULL)
113 return NULL;
114
115 starter_bus_daemon = tp_dbus_daemon_new (conn);
116 g_assert (starter_bus_daemon != NULL);
117 g_object_add_weak_pointer (starter_bus_daemon, &starter_bus_daemon);
118
119 return starter_bus_daemon;
120 }
121
122 /**
123 * tp_dbus_daemon_new: (skip)
124 * @connection: a connection to D-Bus
125 *
126 * Returns a proxy for signals and method calls on a particular bus
127 * connection.
128 *
129 * Use tp_dbus_daemon_dup() instead if you just want a connection to the
130 * starter or session bus (which is almost always the right thing for
131 * Telepathy).
132 *
133 * Returns: a new proxy for signals and method calls on the bus daemon
134 * to which @connection is connected
135 *
136 * Since: 0.7.1
137 */
138 TpDBusDaemon *
tp_dbus_daemon_new(DBusGConnection * connection)139 tp_dbus_daemon_new (DBusGConnection *connection)
140 {
141 g_return_val_if_fail (connection != NULL, NULL);
142
143 return TP_DBUS_DAEMON (g_object_new (TP_TYPE_DBUS_DAEMON,
144 "dbus-connection", connection,
145 "bus-name", DBUS_SERVICE_DBUS,
146 "object-path", DBUS_PATH_DBUS,
147 NULL));
148 }
149
150 typedef struct
151 {
152 gchar *last_owner;
153 GArray *callbacks;
154 gsize invoking;
155 } _NameOwnerWatch;
156
157 typedef struct
158 {
159 TpDBusDaemonNameOwnerChangedCb callback;
160 gpointer user_data;
161 GDestroyNotify destroy;
162 } _NameOwnerSubWatch;
163
164 static void _tp_dbus_daemon_stop_watching (TpDBusDaemon *self,
165 const gchar *name, _NameOwnerWatch *watch);
166
167 static void
tp_dbus_daemon_maybe_free_name_owner_watch(TpDBusDaemon * self,const gchar * name,_NameOwnerWatch * watch)168 tp_dbus_daemon_maybe_free_name_owner_watch (TpDBusDaemon *self,
169 const gchar *name,
170 _NameOwnerWatch *watch)
171 {
172 /* Check to see whether this (callback, user_data) pair is in the watch's
173 * array of callbacks. */
174 GArray *array = watch->callbacks;
175 /* 1 greater than an index into @array, to avoid it going negative: we
176 * iterate in reverse so we can delete elements without needing to adjust
177 * @i to compensate */
178 guint i;
179
180 if (watch->invoking > 0)
181 return;
182
183 for (i = array->len; i > 0; i--)
184 {
185 _NameOwnerSubWatch *entry = &g_array_index (array,
186 _NameOwnerSubWatch, i - 1);
187
188 if (entry->callback != NULL)
189 continue;
190
191 if (entry->destroy != NULL)
192 entry->destroy (entry->user_data);
193
194 g_array_remove_index (array, i - 1);
195 }
196
197 if (array->len == 0)
198 {
199 _tp_dbus_daemon_stop_watching (self, name, watch);
200 g_hash_table_remove (self->priv->name_owner_watches, name);
201 }
202 }
203
204 static void
_tp_dbus_daemon_name_owner_changed(TpDBusDaemon * self,const gchar * name,const gchar * new_owner)205 _tp_dbus_daemon_name_owner_changed (TpDBusDaemon *self,
206 const gchar *name,
207 const gchar *new_owner)
208 {
209 _NameOwnerWatch *watch = g_hash_table_lookup (self->priv->name_owner_watches,
210 name);
211 GArray *array;
212 guint i;
213
214 if (watch == NULL)
215 return;
216
217 /* This is partly to handle the case where an owner change happens
218 * while GetNameOwner is in flight, partly to be able to optimize by only
219 * calling GetNameOwner if we didn't already know, and partly because of a
220 * dbus-glib bug that means we get every signal twice
221 * (it thinks org.freedesktop.DBus is both a well-known name and a unique
222 * name). */
223 if (!tp_strdiff (watch->last_owner, new_owner))
224 return;
225
226 g_free (watch->last_owner);
227 watch->last_owner = g_strdup (new_owner);
228
229 /* We're calling out to user code which might end up removing its watch;
230 * tell it to be less destructive. Also hold a ref on self, to avoid it
231 * getting removed that way. */
232 array = watch->callbacks;
233 g_object_ref (self);
234 watch->invoking++;
235
236 for (i = 0; i < array->len; i++)
237 {
238 _NameOwnerSubWatch *subwatch = &g_array_index (array,
239 _NameOwnerSubWatch, i);
240
241 if (subwatch->callback != NULL)
242 subwatch->callback (self, name, new_owner, subwatch->user_data);
243 }
244
245 watch->invoking--;
246
247 tp_dbus_daemon_maybe_free_name_owner_watch (self, name, watch);
248 g_object_unref (self);
249 }
250
251 static dbus_int32_t daemons_slot = -1;
252
253 typedef struct {
254 DBusConnection *libdbus;
255 DBusMessage *message;
256 } NOCIdleContext;
257
258 static NOCIdleContext *
noc_idle_context_new(DBusConnection * libdbus,DBusMessage * message)259 noc_idle_context_new (DBusConnection *libdbus,
260 DBusMessage *message)
261 {
262 NOCIdleContext *context = g_slice_new (NOCIdleContext);
263
264 context->libdbus = dbus_connection_ref (libdbus);
265 context->message = dbus_message_ref (message);
266 return context;
267 }
268
269 static void
noc_idle_context_free(gpointer data)270 noc_idle_context_free (gpointer data)
271 {
272 NOCIdleContext *context = data;
273
274 dbus_connection_unref (context->libdbus);
275 dbus_message_unref (context->message);
276 g_slice_free (NOCIdleContext, context);
277 }
278
279 static gboolean
noc_idle_context_invoke(gpointer data)280 noc_idle_context_invoke (gpointer data)
281 {
282 NOCIdleContext *context = data;
283 const gchar *name;
284 const gchar *old_owner;
285 const gchar *new_owner;
286 DBusError dbus_error = DBUS_ERROR_INIT;
287 GSList **daemons;
288
289 if (daemons_slot == -1)
290 return FALSE;
291
292 if (!dbus_message_get_args (context->message, &dbus_error,
293 DBUS_TYPE_STRING, &name,
294 DBUS_TYPE_STRING, &old_owner,
295 DBUS_TYPE_STRING, &new_owner,
296 DBUS_TYPE_INVALID))
297 {
298 DEBUG ("Couldn't unpack NameOwnerChanged(s, s, s): %s: %s",
299 dbus_error.name, dbus_error.message);
300 dbus_error_free (&dbus_error);
301 return FALSE;
302 }
303
304 daemons = dbus_connection_get_data (context->libdbus, daemons_slot);
305
306 DEBUG ("NameOwnerChanged(%s, %s -> %s)", name, old_owner, new_owner);
307
308 /* should always be non-NULL, barring bugs */
309 if (G_LIKELY (daemons != NULL))
310 {
311 GSList *iter;
312
313 for (iter = *daemons; iter != NULL; iter = iter->next)
314 {
315 _tp_dbus_daemon_name_owner_changed (iter->data, name, new_owner);
316 }
317 }
318
319 return FALSE;
320 }
321
322 static DBusHandlerResult
_tp_dbus_daemon_name_owner_changed_filter(DBusConnection * libdbus,DBusMessage * message,void * unused G_GNUC_UNUSED)323 _tp_dbus_daemon_name_owner_changed_filter (DBusConnection *libdbus,
324 DBusMessage *message,
325 void *unused G_GNUC_UNUSED)
326 {
327 /* We have to do the real work in an idle, so we don't break re-entrant
328 * calls (the dbus-glib event source isn't re-entrant) */
329 if (dbus_message_is_signal (message, DBUS_INTERFACE_DBUS,
330 "NameOwnerChanged") &&
331 dbus_message_has_sender (message, DBUS_SERVICE_DBUS))
332 g_idle_add_full (G_PRIORITY_HIGH, noc_idle_context_invoke,
333 noc_idle_context_new (libdbus, message),
334 noc_idle_context_free);
335
336 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
337 }
338
339 typedef struct {
340 TpDBusDaemon *self;
341 gchar *name;
342 DBusMessage *reply;
343 gsize refs;
344 } GetNameOwnerContext;
345
346 static GetNameOwnerContext *
get_name_owner_context_new(TpDBusDaemon * self,const gchar * name)347 get_name_owner_context_new (TpDBusDaemon *self,
348 const gchar *name)
349 {
350 GetNameOwnerContext *context = g_slice_new (GetNameOwnerContext);
351
352 context->self = g_object_ref (self);
353 context->name = g_strdup (name);
354 context->reply = NULL;
355 context->refs = 1;
356 return context;
357 }
358
359 static void
get_name_owner_context_unref(gpointer data)360 get_name_owner_context_unref (gpointer data)
361 {
362 GetNameOwnerContext *context = data;
363
364 if (--context->refs == 0)
365 {
366 g_object_unref (context->self);
367 g_free (context->name);
368
369 if (context->reply != NULL)
370 dbus_message_unref (context->reply);
371
372 g_slice_free (GetNameOwnerContext, context);
373 }
374 }
375
376 static gboolean
_tp_dbus_daemon_get_name_owner_idle(gpointer data)377 _tp_dbus_daemon_get_name_owner_idle (gpointer data)
378 {
379 GetNameOwnerContext *context = data;
380 const gchar *owner = "";
381
382 if (context->reply == NULL)
383 {
384 DEBUG ("Connection disconnected or no reply to GetNameOwner(%s)",
385 context->name);
386 }
387 else if (dbus_message_get_type (context->reply) ==
388 DBUS_MESSAGE_TYPE_METHOD_RETURN)
389 {
390 if (dbus_message_get_args (context->reply, NULL,
391 DBUS_TYPE_STRING, &owner,
392 DBUS_TYPE_INVALID))
393 {
394 DEBUG ("GetNameOwner(%s) -> %s", context->name, owner);
395 }
396 else
397 {
398 DEBUG ("Malformed reply from GetNameOwner(%s), assuming no owner",
399 context->name);
400 }
401 }
402 else
403 {
404 if (DEBUGGING)
405 {
406 DBusError error = DBUS_ERROR_INIT;
407
408 if (dbus_set_error_from_message (&error, context->reply))
409 {
410 DEBUG ("GetNameOwner(%s) raised %s: %s", context->name,
411 error.name, error.message);
412 dbus_error_free (&error);
413 }
414 else
415 {
416 DEBUG ("Unexpected message type from GetNameOwner(%s)",
417 context->name);
418 }
419 }
420 }
421
422 _tp_dbus_daemon_name_owner_changed (context->self, context->name, owner);
423
424 return FALSE;
425 }
426
427 /**
428 * TpDBusDaemonNameOwnerChangedCb:
429 * @bus_daemon: The D-Bus daemon
430 * @name: The name whose ownership has changed or been discovered
431 * @new_owner: The unique name that now owns @name
432 * @user_data: Arbitrary user-supplied data as passed to
433 * tp_dbus_daemon_watch_name_owner()
434 *
435 * The signature of the callback called by tp_dbus_daemon_watch_name_owner().
436 *
437 * Since: 0.7.1
438 */
439
440 static inline gchar *
_tp_dbus_daemon_get_noc_rule(const gchar * name)441 _tp_dbus_daemon_get_noc_rule (const gchar *name)
442 {
443 return g_strdup_printf ("type='signal',"
444 "sender='" DBUS_SERVICE_DBUS "',"
445 "path='" DBUS_PATH_DBUS "',"
446 "interface='"DBUS_INTERFACE_DBUS "',"
447 "member='NameOwnerChanged',"
448 "arg0='%s'", name);
449 }
450
451 static void
_tp_dbus_daemon_get_name_owner_notify(DBusPendingCall * pc,gpointer data)452 _tp_dbus_daemon_get_name_owner_notify (DBusPendingCall *pc,
453 gpointer data)
454 {
455 GetNameOwnerContext *context = data;
456
457 /* we recycle this function for the case where the connection is already
458 * disconnected: in that case we use pc = NULL */
459 if (pc != NULL)
460 context->reply = dbus_pending_call_steal_reply (pc);
461
462 /* We have to do the real work in an idle, so we don't break re-entrant
463 * calls (the dbus-glib event source isn't re-entrant) */
464 context->refs++;
465 g_idle_add_full (G_PRIORITY_HIGH, _tp_dbus_daemon_get_name_owner_idle,
466 context, get_name_owner_context_unref);
467
468 if (pc != NULL)
469 dbus_pending_call_unref (pc);
470 }
471
472 /**
473 * tp_dbus_daemon_watch_name_owner:
474 * @self: The D-Bus daemon
475 * @name: The name whose ownership is to be watched
476 * @callback: Callback to call when the ownership is discovered or changes
477 * @user_data: Arbitrary data to pass to @callback
478 * @destroy: Called to destroy @user_data when the name owner watch is
479 * cancelled due to tp_dbus_daemon_cancel_name_owner_watch()
480 *
481 * Arrange for @callback to be called with the owner of @name as soon as
482 * possible (which might even be before this function returns!), then
483 * again every time the ownership of @name changes.
484 *
485 * If multiple watches are registered for the same @name, they will be called
486 * in the order they were registered.
487 *
488 * Since: 0.7.1
489 */
490 void
tp_dbus_daemon_watch_name_owner(TpDBusDaemon * self,const gchar * name,TpDBusDaemonNameOwnerChangedCb callback,gpointer user_data,GDestroyNotify destroy)491 tp_dbus_daemon_watch_name_owner (TpDBusDaemon *self,
492 const gchar *name,
493 TpDBusDaemonNameOwnerChangedCb callback,
494 gpointer user_data,
495 GDestroyNotify destroy)
496 {
497 _NameOwnerWatch *watch = g_hash_table_lookup (self->priv->name_owner_watches,
498 name);
499 _NameOwnerSubWatch tmp = { callback, user_data, destroy };
500
501 g_return_if_fail (TP_IS_DBUS_DAEMON (self));
502 g_return_if_fail (tp_dbus_check_valid_bus_name (name,
503 TP_DBUS_NAME_TYPE_ANY, NULL));
504 g_return_if_fail (callback != NULL);
505
506 if (watch == NULL)
507 {
508 gchar *match_rule;
509 DBusMessage *message;
510 DBusPendingCall *pc = NULL;
511 GetNameOwnerContext *context = get_name_owner_context_new (self, name);
512
513 /* Allocate a new watch */
514 watch = g_slice_new0 (_NameOwnerWatch);
515 watch->last_owner = NULL;
516 watch->callbacks = g_array_new (FALSE, FALSE,
517 sizeof (_NameOwnerSubWatch));
518
519 g_hash_table_insert (self->priv->name_owner_watches, g_strdup (name),
520 watch);
521
522 /* We want to be notified about name owner changes for this one.
523 * Assume the match addition will succeed; there's no good way to cope
524 * with failure here... */
525 match_rule = _tp_dbus_daemon_get_noc_rule (name);
526 DEBUG ("Adding match rule %s", match_rule);
527 dbus_bus_add_match (self->priv->libdbus, match_rule, NULL);
528 g_free (match_rule);
529
530 message = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
531 DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "GetNameOwner");
532
533 if (message == NULL)
534 ERROR ("Out of memory");
535
536 /* We already checked that @name was in (a small subset of) UTF-8,
537 * so OOM is the only thing that can go wrong. The use of &name here
538 * is because libdbus is strange. */
539 if (!dbus_message_append_args (message,
540 DBUS_TYPE_STRING, &name,
541 DBUS_TYPE_INVALID))
542 ERROR ("Out of memory");
543
544 if (!dbus_connection_send_with_reply (self->priv->libdbus,
545 message, &pc, -1))
546 ERROR ("Out of memory");
547 /* pc is unreffed by _tp_dbus_daemon_get_name_owner_notify */
548 dbus_message_unref (message);
549
550 if (pc == NULL || dbus_pending_call_get_completed (pc))
551 {
552 /* pc can be NULL when the connection is already disconnected */
553 _tp_dbus_daemon_get_name_owner_notify (pc, context);
554 get_name_owner_context_unref (context);
555 }
556 else if (!dbus_pending_call_set_notify (pc,
557 _tp_dbus_daemon_get_name_owner_notify,
558 context, get_name_owner_context_unref))
559 {
560 ERROR ("Out of memory");
561 }
562 }
563
564 g_array_append_val (watch->callbacks, tmp);
565
566 if (watch->last_owner != NULL)
567 {
568 /* FIXME: should avoid reentrancy? */
569 callback (self, name, watch->last_owner, user_data);
570 }
571 }
572
573 static void
_tp_dbus_daemon_stop_watching(TpDBusDaemon * self,const gchar * name,_NameOwnerWatch * watch)574 _tp_dbus_daemon_stop_watching (TpDBusDaemon *self,
575 const gchar *name,
576 _NameOwnerWatch *watch)
577 {
578 gchar *match_rule;
579
580 /* Clean up any leftöver callbacks. */
581 if (watch->callbacks->len > 0)
582 {
583 guint i;
584
585 for (i = 0; i < watch->callbacks->len; i++)
586 {
587 _NameOwnerSubWatch *entry = &g_array_index (watch->callbacks,
588 _NameOwnerSubWatch, i);
589
590 if (entry->destroy != NULL)
591 entry->destroy (entry->user_data);
592 }
593 }
594
595 g_array_unref (watch->callbacks);
596 g_free (watch->last_owner);
597 g_slice_free (_NameOwnerWatch, watch);
598
599 match_rule = _tp_dbus_daemon_get_noc_rule (name);
600 DEBUG ("Removing match rule %s", match_rule);
601 dbus_bus_remove_match (self->priv->libdbus, match_rule, NULL);
602 g_free (match_rule);
603 }
604
605 /**
606 * tp_dbus_daemon_cancel_name_owner_watch: (skip)
607 * @self: the D-Bus daemon
608 * @name: the name that was being watched
609 * @callback: the callback that was called
610 * @user_data: the user data that was provided
611 *
612 * If there was a previous call to tp_dbus_daemon_watch_name_owner()
613 * with exactly the given @name, @callback and @user_data, remove it.
614 *
615 * If more than one watch matching the details provided was active, remove
616 * only the most recently added one.
617 *
618 * Returns: %TRUE if there was such a watch, %FALSE otherwise
619 *
620 * Since: 0.7.1
621 */
622 gboolean
tp_dbus_daemon_cancel_name_owner_watch(TpDBusDaemon * self,const gchar * name,TpDBusDaemonNameOwnerChangedCb callback,gconstpointer user_data)623 tp_dbus_daemon_cancel_name_owner_watch (TpDBusDaemon *self,
624 const gchar *name,
625 TpDBusDaemonNameOwnerChangedCb callback,
626 gconstpointer user_data)
627 {
628 _NameOwnerWatch *watch = g_hash_table_lookup (self->priv->name_owner_watches,
629 name);
630
631 g_return_val_if_fail (TP_IS_DBUS_DAEMON (self), FALSE);
632 g_return_val_if_fail (name != NULL, FALSE);
633 g_return_val_if_fail (callback != NULL, FALSE);
634
635 if (watch != NULL)
636 {
637 /* Check to see whether this (callback, user_data) pair is in the watch's
638 * array of callbacks. */
639 GArray *array = watch->callbacks;
640 /* 1 greater than an index into @array, to avoid it going negative;
641 * we iterate in reverse to have "last in = first out" as documented. */
642 guint i;
643
644 for (i = array->len; i > 0; i--)
645 {
646 _NameOwnerSubWatch *entry = &g_array_index (array,
647 _NameOwnerSubWatch, i - 1);
648
649 if (entry->callback == callback && entry->user_data == user_data)
650 {
651 entry->callback = NULL;
652 tp_dbus_daemon_maybe_free_name_owner_watch (self, name, watch);
653 return TRUE;
654 }
655 }
656 }
657
658 /* We haven't found it */
659 return FALSE;
660 }
661
662 /* for internal use (TpChannel, TpConnection _new convenience functions) */
663 gboolean
_tp_dbus_daemon_get_name_owner(TpDBusDaemon * self,gint timeout_ms,const gchar * well_known_name,gchar ** unique_name,GError ** error)664 _tp_dbus_daemon_get_name_owner (TpDBusDaemon *self,
665 gint timeout_ms,
666 const gchar *well_known_name,
667 gchar **unique_name,
668 GError **error)
669 {
670 DBusGConnection *gconn;
671 DBusConnection *dbc;
672 DBusMessage *message;
673 DBusMessage *reply;
674 DBusError dbus_error;
675 const char *name_in_reply;
676 const GError *invalidated;
677
678 g_return_val_if_fail (TP_IS_DBUS_DAEMON (self), FALSE);
679 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
680
681 invalidated = tp_proxy_get_invalidated (self);
682
683 if (invalidated != NULL)
684 {
685 if (error != NULL)
686 *error = g_error_copy (invalidated);
687
688 return FALSE;
689 }
690
691 gconn = tp_proxy_get_dbus_connection (self);
692 dbc = dbus_g_connection_get_connection (gconn);
693
694 message = dbus_message_new_method_call (DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
695 DBUS_INTERFACE_DBUS, "GetNameOwner");
696
697 if (message == NULL)
698 ERROR ("Out of memory");
699
700 if (!dbus_message_append_args (message,
701 DBUS_TYPE_STRING, &well_known_name,
702 DBUS_TYPE_INVALID))
703 ERROR ("Out of memory");
704
705 dbus_error_init (&dbus_error);
706 reply = dbus_connection_send_with_reply_and_block (dbc, message,
707 timeout_ms, &dbus_error);
708
709 dbus_message_unref (message);
710
711 if (reply == NULL)
712 {
713 if (!tp_strdiff (dbus_error.name, DBUS_ERROR_NO_MEMORY))
714 ERROR ("Out of memory");
715
716 /* FIXME: ideally we'd use dbus-glib's error mapping for this */
717 g_set_error (error, TP_DBUS_ERRORS, TP_DBUS_ERROR_NAME_OWNER_LOST,
718 "%s: %s", dbus_error.name, dbus_error.message);
719
720 dbus_error_free (&dbus_error);
721 return FALSE;
722 }
723
724 if (!dbus_message_get_args (reply, &dbus_error,
725 DBUS_TYPE_STRING, &name_in_reply,
726 DBUS_TYPE_INVALID))
727 {
728 g_set_error (error, TP_DBUS_ERRORS, TP_DBUS_ERROR_NAME_OWNER_LOST,
729 "%s: %s", dbus_error.name, dbus_error.message);
730
731 dbus_error_free (&dbus_error);
732 dbus_message_unref (reply);
733 return FALSE;
734 }
735
736 if (unique_name != NULL)
737 *unique_name = g_strdup (name_in_reply);
738
739 dbus_message_unref (reply);
740
741 return TRUE;
742 }
743
744 /**
745 * tp_dbus_daemon_request_name:
746 * @self: a TpDBusDaemon
747 * @well_known_name: a well-known name to acquire
748 * @idempotent: whether to consider it to be a success if this process
749 * already owns the name
750 * @error: used to raise an error if %FALSE is returned
751 *
752 * Claim the given well-known name without queueing, allowing replacement
753 * or replacing an existing name-owner. This makes a synchronous call to the
754 * bus daemon.
755 *
756 * Returns: %TRUE if @well_known_name was claimed, or %FALSE and sets @error if
757 * an error occurred.
758 *
759 * Since: 0.7.30
760 */
761 gboolean
tp_dbus_daemon_request_name(TpDBusDaemon * self,const gchar * well_known_name,gboolean idempotent,GError ** error)762 tp_dbus_daemon_request_name (TpDBusDaemon *self,
763 const gchar *well_known_name,
764 gboolean idempotent,
765 GError **error)
766 {
767 TpProxy *as_proxy = (TpProxy *) self;
768 DBusGConnection *gconn;
769 DBusConnection *dbc;
770 DBusError dbus_error;
771 int result;
772 const GError *invalidated;
773
774 g_return_val_if_fail (TP_IS_DBUS_DAEMON (self), FALSE);
775 g_return_val_if_fail (tp_dbus_check_valid_bus_name (well_known_name,
776 TP_DBUS_NAME_TYPE_WELL_KNOWN, error), FALSE);
777 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
778
779 invalidated = tp_proxy_get_invalidated (self);
780
781 if (invalidated != NULL)
782 {
783 if (error != NULL)
784 *error = g_error_copy (invalidated);
785
786 return FALSE;
787 }
788
789 gconn = as_proxy->dbus_connection;
790 dbc = dbus_g_connection_get_connection (gconn);
791
792 dbus_error_init (&dbus_error);
793 result = dbus_bus_request_name (dbc, well_known_name,
794 DBUS_NAME_FLAG_DO_NOT_QUEUE, &dbus_error);
795
796 switch (result)
797 {
798 case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
799 return TRUE;
800
801 case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
802 if (idempotent)
803 {
804 return TRUE;
805 }
806 else
807 {
808 g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE,
809 "Name '%s' already in use by this process", well_known_name);
810 return FALSE;
811 }
812
813 case DBUS_REQUEST_NAME_REPLY_EXISTS:
814 case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
815 /* the latter shouldn't actually happen since we said DO_NOT_QUEUE */
816 g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE,
817 "Name '%s' already in use by another process", well_known_name);
818 return FALSE;
819
820 case -1:
821 g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE,
822 "%s: %s", dbus_error.name, dbus_error.message);
823 dbus_error_free (&dbus_error);
824 return FALSE;
825
826 default:
827 g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE,
828 "RequestName('%s') returned %d and I don't know what that means",
829 well_known_name, result);
830 return FALSE;
831 }
832 }
833
834 /**
835 * tp_dbus_daemon_release_name:
836 * @self: a TpDBusDaemon
837 * @well_known_name: a well-known name owned by this process to release
838 * @error: used to raise an error if %FALSE is returned
839 *
840 * Release the given well-known name. This makes a synchronous call to the bus
841 * daemon.
842 *
843 * Returns: %TRUE if @well_known_name was released, or %FALSE and sets @error
844 * if an error occurred.
845 *
846 * Since: 0.7.30
847 */
848 gboolean
tp_dbus_daemon_release_name(TpDBusDaemon * self,const gchar * well_known_name,GError ** error)849 tp_dbus_daemon_release_name (TpDBusDaemon *self,
850 const gchar *well_known_name,
851 GError **error)
852 {
853 TpProxy *as_proxy = (TpProxy *) self;
854 DBusGConnection *gconn;
855 DBusConnection *dbc;
856 DBusError dbus_error;
857 int result;
858 const GError *invalidated;
859
860 g_return_val_if_fail (TP_IS_DBUS_DAEMON (self), FALSE);
861 g_return_val_if_fail (tp_dbus_check_valid_bus_name (well_known_name,
862 TP_DBUS_NAME_TYPE_WELL_KNOWN, error), FALSE);
863 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
864
865 invalidated = tp_proxy_get_invalidated (self);
866
867 if (invalidated != NULL)
868 {
869 if (error != NULL)
870 *error = g_error_copy (invalidated);
871
872 return FALSE;
873 }
874
875 gconn = as_proxy->dbus_connection;
876 dbc = dbus_g_connection_get_connection (gconn);
877 dbus_error_init (&dbus_error);
878 result = dbus_bus_release_name (dbc, well_known_name, &dbus_error);
879
880 switch (result)
881 {
882 case DBUS_RELEASE_NAME_REPLY_RELEASED:
883 return TRUE;
884
885 case DBUS_RELEASE_NAME_REPLY_NOT_OWNER:
886 g_set_error (error, TP_ERROR, TP_ERROR_NOT_YOURS,
887 "Name '%s' owned by another process", well_known_name);
888 return FALSE;
889
890 case DBUS_RELEASE_NAME_REPLY_NON_EXISTENT:
891 g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE,
892 "Name '%s' not owned", well_known_name);
893 return FALSE;
894
895 case -1:
896 g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE,
897 "%s: %s", dbus_error.name, dbus_error.message);
898 dbus_error_free (&dbus_error);
899 return FALSE;
900
901 default:
902 g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE,
903 "ReleaseName('%s') returned %d and I don't know what that means",
904 well_known_name, result);
905 return FALSE;
906 }
907 }
908
909 /**
910 * tp_dbus_daemon_register_object:
911 * @self: object representing a connection to a bus
912 * @object_path: an object path
913 * @object: (type GObject.Object) (transfer none): an object to export
914 *
915 * Export @object at @object_path. This is a convenience wrapper around
916 * dbus_g_connection_register_g_object(), and behaves similarly.
917 *
918 * Since: 0.11.3
919 */
920 void
tp_dbus_daemon_register_object(TpDBusDaemon * self,const gchar * object_path,gpointer object)921 tp_dbus_daemon_register_object (TpDBusDaemon *self,
922 const gchar *object_path,
923 gpointer object)
924 {
925 TpProxy *as_proxy = (TpProxy *) self;
926
927 g_return_if_fail (TP_IS_DBUS_DAEMON (self));
928 g_return_if_fail (tp_dbus_check_valid_object_path (object_path, NULL));
929 g_return_if_fail (G_IS_OBJECT (object));
930
931 dbus_g_connection_register_g_object (as_proxy->dbus_connection,
932 object_path, object);
933 }
934
935 /**
936 * tp_dbus_daemon_unregister_object:
937 * @self: object representing a connection to a bus
938 * @object: (type GObject.Object) (transfer none): an object previously exported
939 * with tp_dbus_daemon_register_object()
940 *
941 * Stop exporting @object on D-Bus. This is a convenience wrapper around
942 * dbus_g_connection_unregister_g_object(), and behaves similarly.
943 *
944 * Since: 0.11.3
945 */
946 void
tp_dbus_daemon_unregister_object(TpDBusDaemon * self,gpointer object)947 tp_dbus_daemon_unregister_object (TpDBusDaemon *self,
948 gpointer object)
949 {
950 TpProxy *as_proxy = (TpProxy *) self;
951
952 g_return_if_fail (TP_IS_DBUS_DAEMON (self));
953 g_return_if_fail (G_IS_OBJECT (object));
954
955 dbus_g_connection_unregister_g_object (as_proxy->dbus_connection, object);
956 }
957
958 /**
959 * tp_dbus_daemon_get_unique_name:
960 * @self: object representing a connection to a bus
961 *
962 * <!-- Returns: is enough -->
963 *
964 * Returns: the unique name of this connection to the bus, which is valid for
965 * as long as this #TpDBusDaemon is
966 * Since: 0.7.35
967 */
968 const gchar *
tp_dbus_daemon_get_unique_name(TpDBusDaemon * self)969 tp_dbus_daemon_get_unique_name (TpDBusDaemon *self)
970 {
971 g_return_val_if_fail (TP_IS_DBUS_DAEMON (self), NULL);
972
973 return dbus_bus_get_unique_name (self->priv->libdbus);
974 }
975
976 typedef struct {
977 TpDBusDaemon *self;
978 DBusMessage *reply;
979 TpDBusDaemonListNamesCb callback;
980 gpointer user_data;
981 GDestroyNotify destroy;
982 gpointer weak_object;
983 gsize refs;
984 } ListNamesContext;
985
986 static ListNamesContext *
list_names_context_new(TpDBusDaemon * self,TpDBusDaemonListNamesCb callback,gpointer user_data,GDestroyNotify destroy,GObject * weak_object)987 list_names_context_new (TpDBusDaemon *self,
988 TpDBusDaemonListNamesCb callback,
989 gpointer user_data,
990 GDestroyNotify destroy,
991 GObject *weak_object)
992 {
993 ListNamesContext *context = g_slice_new (ListNamesContext);
994
995 context->self = g_object_ref (self);
996 context->reply = NULL;
997 context->callback = callback;
998 context->user_data = user_data;
999 context->destroy = destroy;
1000 context->weak_object = weak_object;
1001
1002 if (context->weak_object != NULL)
1003 g_object_add_weak_pointer (weak_object, &context->weak_object);
1004
1005 context->refs = 1;
1006 return context;
1007 }
1008
1009 static void
list_names_context_unref(gpointer data)1010 list_names_context_unref (gpointer data)
1011 {
1012 ListNamesContext *context = data;
1013
1014 if (--context->refs == 0)
1015 {
1016 g_object_unref (context->self);
1017
1018 if (context->reply != NULL)
1019 dbus_message_unref (context->reply);
1020
1021 if (context->destroy != NULL)
1022 context->destroy (context->user_data);
1023
1024 context->destroy = NULL;
1025
1026 if (context->weak_object != NULL)
1027 g_object_remove_weak_pointer (context->weak_object,
1028 &context->weak_object);
1029
1030 g_slice_free (ListNamesContext, context);
1031 }
1032 }
1033
1034 static gboolean
_tp_dbus_daemon_list_names_idle(gpointer data)1035 _tp_dbus_daemon_list_names_idle (gpointer data)
1036 {
1037 ListNamesContext *context = data;
1038 char **array = NULL;
1039 const gchar * const *result = NULL;
1040 GError *error = NULL;
1041
1042 if (context->callback == NULL)
1043 {
1044 DEBUG ("Caller no longer cares (weak object vanished), ignoring");
1045 return FALSE;
1046 }
1047
1048 if (context->reply == NULL)
1049 {
1050 g_set_error_literal (&error, DBUS_GERROR, DBUS_GERROR_DISCONNECTED,
1051 "DBusConnection disconnected");
1052 }
1053 else if (dbus_message_get_type (context->reply) ==
1054 DBUS_MESSAGE_TYPE_METHOD_RETURN)
1055 {
1056 int n_elements;
1057
1058 if (dbus_message_get_args (context->reply, NULL,
1059 DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &array, &n_elements,
1060 DBUS_TYPE_INVALID))
1061 {
1062 result = (const gchar * const *) array;
1063 g_assert (result[n_elements] == NULL);
1064 }
1065 else
1066 {
1067 g_set_error_literal (&error, DBUS_GERROR, DBUS_GERROR_INVALID_ARGS,
1068 "Malformed reply from List*Names()");
1069 }
1070 }
1071 else
1072 {
1073 DBusError dbus_error = DBUS_ERROR_INIT;
1074
1075 if (dbus_set_error_from_message (&dbus_error, context->reply))
1076 {
1077 /* FIXME: ideally we'd use dbus-glib's error mapping here, but we
1078 * don't have access to it */
1079 g_set_error (&error, DBUS_GERROR, DBUS_GERROR_FAILED,
1080 "List*Names() raised %s: %s", dbus_error.name,
1081 dbus_error.message);
1082 dbus_error_free (&dbus_error);
1083 }
1084 else
1085 {
1086 g_set_error_literal (&error, DBUS_GERROR, DBUS_GERROR_INVALID_ARGS,
1087 "Unexpected message type from List*Names()");
1088 }
1089 }
1090
1091 if (error != NULL)
1092 DEBUG ("%s", error->message);
1093
1094 context->callback (context->self, result, error, context->user_data,
1095 context->weak_object);
1096 dbus_free_string_array (array); /* NULL-safe */
1097 return FALSE;
1098 }
1099
1100 static void
_tp_dbus_daemon_list_names_notify(DBusPendingCall * pc,gpointer data)1101 _tp_dbus_daemon_list_names_notify (DBusPendingCall *pc,
1102 gpointer data)
1103 {
1104 ListNamesContext *context = data;
1105
1106 /* we recycle this function for the case where the connection is already
1107 * disconnected: in that case we use pc = NULL */
1108 if (pc != NULL)
1109 context->reply = dbus_pending_call_steal_reply (pc);
1110
1111 /* We have to do the real work in an idle, so we don't break re-entrant
1112 * calls (the dbus-glib event source isn't re-entrant) */
1113 context->refs++;
1114 g_idle_add_full (G_PRIORITY_HIGH, _tp_dbus_daemon_list_names_idle,
1115 context, list_names_context_unref);
1116
1117 if (pc != NULL)
1118 dbus_pending_call_unref (pc);
1119 }
1120
1121 /**
1122 * TpDBusDaemonListNamesCb:
1123 * @bus_daemon: object representing a connection to a bus
1124 * @names: constant %NULL-terminated array of constant strings representing
1125 * bus names, or %NULL on error
1126 * @error: the error that occurred, or %NULL on success
1127 * @user_data: the same user data that was passed to
1128 * tp_dbus_daemon_list_names or tp_dbus_daemon_list_activatable_names
1129 * @weak_object: the same object that was passed to
1130 * tp_dbus_daemon_list_names or tp_dbus_daemon_list_activatable_names
1131 *
1132 * Signature of a callback for functions that list bus names.
1133 *
1134 * Since: 0.7.35
1135 */
1136
1137 static void
_tp_dbus_daemon_list_names_common(TpDBusDaemon * self,const gchar * method,gint timeout_ms,TpDBusDaemonListNamesCb callback,gpointer user_data,GDestroyNotify destroy,GObject * weak_object)1138 _tp_dbus_daemon_list_names_common (TpDBusDaemon *self,
1139 const gchar *method,
1140 gint timeout_ms,
1141 TpDBusDaemonListNamesCb callback,
1142 gpointer user_data,
1143 GDestroyNotify destroy,
1144 GObject *weak_object)
1145 {
1146 DBusMessage *message;
1147 DBusPendingCall *pc = NULL;
1148 ListNamesContext *context;
1149
1150 g_return_if_fail (TP_IS_DBUS_DAEMON (self));
1151 g_return_if_fail (callback != NULL);
1152 g_return_if_fail (weak_object == NULL || G_IS_OBJECT (weak_object));
1153
1154 message = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
1155 DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, method);
1156
1157 if (message == NULL)
1158 ERROR ("Out of memory");
1159
1160 if (!dbus_connection_send_with_reply (self->priv->libdbus,
1161 message, &pc, timeout_ms))
1162 ERROR ("Out of memory");
1163 /* pc is unreffed by _tp_dbus_daemon_list_names_notify */
1164 dbus_message_unref (message);
1165
1166 context = list_names_context_new (self, callback, user_data, destroy,
1167 weak_object);
1168
1169 if (pc == NULL || dbus_pending_call_get_completed (pc))
1170 {
1171 /* pc can be NULL when the connection is already disconnected */
1172 _tp_dbus_daemon_list_names_notify (pc, context);
1173 list_names_context_unref (context);
1174 }
1175 else if (!dbus_pending_call_set_notify (pc,
1176 _tp_dbus_daemon_list_names_notify, context,
1177 list_names_context_unref))
1178 {
1179 ERROR ("Out of memory");
1180 }
1181 }
1182
1183 /**
1184 * tp_dbus_daemon_list_names:
1185 * @self: object representing a connection to a bus
1186 * @timeout_ms: timeout for the call
1187 * @callback: callback to be called on success or failure; must not be %NULL
1188 * @user_data: opaque user-supplied data to pass to the callback
1189 * @destroy: if not %NULL, called with @user_data as argument after the call
1190 * has succeeded or failed, or after @weak_object has been destroyed
1191 * @weak_object: if not %NULL, a GObject which will be weakly referenced; if
1192 * it is destroyed, @callback will not be called at all
1193 *
1194 * Call the ListNames method on the bus daemon, asynchronously. The @callback
1195 * will be called from the main loop with a list of all the names (either
1196 * unique or well-known) that exist on the bus.
1197 *
1198 * In versions of telepathy-glib that have it, this should be preferred
1199 * instead of calling tp_cli_dbus_daemon_call_list_names(), since that
1200 * function will result in wakeups for every NameOwnerChanged signal.
1201 *
1202 * Since: 0.7.35
1203 */
1204 void
tp_dbus_daemon_list_names(TpDBusDaemon * self,gint timeout_ms,TpDBusDaemonListNamesCb callback,gpointer user_data,GDestroyNotify destroy,GObject * weak_object)1205 tp_dbus_daemon_list_names (TpDBusDaemon *self,
1206 gint timeout_ms,
1207 TpDBusDaemonListNamesCb callback,
1208 gpointer user_data,
1209 GDestroyNotify destroy,
1210 GObject *weak_object)
1211 {
1212 _tp_dbus_daemon_list_names_common (self, "ListNames", timeout_ms,
1213 callback, user_data, destroy, weak_object);
1214 }
1215
1216 /**
1217 * tp_dbus_daemon_list_activatable_names:
1218 * @self: object representing a connection to a bus daemon
1219 * @timeout_ms: timeout for the call
1220 * @callback: callback to be called on success or failure; must not be %NULL
1221 * @user_data: opaque user-supplied data to pass to the callback
1222 * @destroy: if not %NULL, called with @user_data as argument after the call
1223 * has succeeded or failed, or after @weak_object has been destroyed
1224 * @weak_object: if not %NULL, a GObject which will be weakly referenced; if
1225 * it is destroyed, @callback will not be called at all
1226 *
1227 * Call the ListActivatableNames method on the bus daemon, asynchronously.
1228 * The @callback will be called from the main loop with a list of all the
1229 * well-known names that are available for service-activation on the bus.
1230 *
1231 * In versions of telepathy-glib that have it, this should be preferred
1232 * instead of calling tp_cli_dbus_daemon_call_list_activatable_names(), since
1233 * that function will result in wakeups for every NameOwnerChanged signal.
1234 *
1235 * Since: 0.7.35
1236 */
1237 void
tp_dbus_daemon_list_activatable_names(TpDBusDaemon * self,gint timeout_ms,TpDBusDaemonListNamesCb callback,gpointer user_data,GDestroyNotify destroy,GObject * weak_object)1238 tp_dbus_daemon_list_activatable_names (TpDBusDaemon *self,
1239 gint timeout_ms,
1240 TpDBusDaemonListNamesCb callback,
1241 gpointer user_data,
1242 GDestroyNotify destroy,
1243 GObject *weak_object)
1244 {
1245 _tp_dbus_daemon_list_names_common (self, "ListActivatableNames", timeout_ms,
1246 callback, user_data, destroy, weak_object);
1247 }
1248
1249 static void
free_daemon_list(gpointer p)1250 free_daemon_list (gpointer p)
1251 {
1252 GSList **slistp = p;
1253
1254 g_slist_free (*slistp);
1255 g_slice_free (GSList *, slistp);
1256 }
1257
1258 /* If you add more slice-allocation in this function, make the suppression
1259 * "tp_dbus_daemon_constructor @daemons once per DBusConnection" in
1260 * telepathy-glib.supp more specific. */
1261 static GObject *
tp_dbus_daemon_constructor(GType type,guint n_params,GObjectConstructParam * params)1262 tp_dbus_daemon_constructor (GType type,
1263 guint n_params,
1264 GObjectConstructParam *params)
1265 {
1266 GObjectClass *object_class =
1267 (GObjectClass *) tp_dbus_daemon_parent_class;
1268 TpDBusDaemon *self = TP_DBUS_DAEMON (object_class->constructor (type,
1269 n_params, params));
1270 TpProxy *as_proxy = (TpProxy *) self;
1271 GSList **daemons;
1272
1273 g_assert (!tp_strdiff (as_proxy->bus_name, DBUS_SERVICE_DBUS));
1274 g_assert (!tp_strdiff (as_proxy->object_path, DBUS_PATH_DBUS));
1275
1276 self->priv->libdbus = dbus_connection_ref (
1277 dbus_g_connection_get_connection (
1278 tp_proxy_get_dbus_connection (self)));
1279
1280 /* one ref per TpDBusDaemon, released in finalize */
1281 if (!dbus_connection_allocate_data_slot (&daemons_slot))
1282 ERROR ("Out of memory");
1283
1284 daemons = dbus_connection_get_data (self->priv->libdbus, daemons_slot);
1285
1286 if (daemons == NULL)
1287 {
1288 /* This slice is never freed; it's a one-per-DBusConnection leak. */
1289 daemons = g_slice_new (GSList *);
1290
1291 *daemons = NULL;
1292 dbus_connection_set_data (self->priv->libdbus, daemons_slot, daemons,
1293 free_daemon_list);
1294
1295 /* we add this filter at most once per DBusConnection */
1296 if (!dbus_connection_add_filter (self->priv->libdbus,
1297 _tp_dbus_daemon_name_owner_changed_filter, NULL, NULL))
1298 ERROR ("Out of memory");
1299 }
1300
1301 *daemons = g_slist_prepend (*daemons, self);
1302
1303 return (GObject *) self;
1304 }
1305
1306 static void
tp_dbus_daemon_init(TpDBusDaemon * self)1307 tp_dbus_daemon_init (TpDBusDaemon *self)
1308 {
1309 self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, TP_TYPE_DBUS_DAEMON,
1310 TpDBusDaemonPrivate);
1311
1312 self->priv->name_owner_watches = g_hash_table_new_full (g_str_hash,
1313 g_str_equal, g_free, NULL);
1314 }
1315
1316 static void
tp_dbus_daemon_dispose(GObject * object)1317 tp_dbus_daemon_dispose (GObject *object)
1318 {
1319 TpDBusDaemon *self = TP_DBUS_DAEMON (object);
1320 GSList **daemons;
1321
1322 if (self->priv->name_owner_watches != NULL)
1323 {
1324 GHashTable *tmp = self->priv->name_owner_watches;
1325 GHashTableIter iter;
1326 gpointer k, v;
1327
1328 self->priv->name_owner_watches = NULL;
1329 g_hash_table_iter_init (&iter, tmp);
1330
1331 while (g_hash_table_iter_next (&iter, &k, &v))
1332 {
1333 _NameOwnerWatch *watch = v;
1334
1335 /* it refs us while invoking stuff */
1336 g_assert (watch->invoking == 0);
1337 _tp_dbus_daemon_stop_watching (self, k, watch);
1338 g_hash_table_iter_remove (&iter);
1339 }
1340
1341 g_hash_table_unref (tmp);
1342 }
1343
1344 if (self->priv->libdbus != NULL)
1345 {
1346 /* remove myself from the list to be notified on NoC */
1347 daemons = dbus_connection_get_data (self->priv->libdbus, daemons_slot);
1348
1349 /* should always be non-NULL, barring bugs */
1350 if (G_LIKELY (daemons != NULL))
1351 {
1352 *daemons = g_slist_remove (*daemons, self);
1353
1354 if (*daemons == NULL)
1355 {
1356 /* this results in a call to free_daemon_list (daemons) */
1357 dbus_connection_set_data (self->priv->libdbus, daemons_slot,
1358 NULL, NULL);
1359 }
1360 }
1361
1362 dbus_connection_unref (self->priv->libdbus);
1363 self->priv->libdbus = NULL;
1364 }
1365
1366 G_OBJECT_CLASS (tp_dbus_daemon_parent_class)->dispose (object);
1367 }
1368
1369 static void
tp_dbus_daemon_finalize(GObject * object)1370 tp_dbus_daemon_finalize (GObject *object)
1371 {
1372 GObjectFinalizeFunc chain_up = G_OBJECT_CLASS (tp_dbus_daemon_parent_class)->finalize;
1373
1374 /* one ref per TpDBusDaemon, from constructor */
1375 dbus_connection_free_data_slot (&daemons_slot);
1376
1377 if (chain_up != NULL)
1378 chain_up (object);
1379 }
1380
1381 /**
1382 * tp_dbus_daemon_init_known_interfaces:
1383 *
1384 * Ensure that the known interfaces for TpDBusDaemon have been set up.
1385 * This is done automatically when necessary, but for correct
1386 * overriding of library interfaces by local extensions, you should
1387 * call this function before calling
1388 * tp_proxy_or_subclass_hook_on_interface_add() with first argument
1389 * %TP_TYPE_DBUS_DAEMON.
1390 *
1391 * Since: 0.7.32
1392 */
1393 void
tp_dbus_daemon_init_known_interfaces(void)1394 tp_dbus_daemon_init_known_interfaces (void)
1395 {
1396 static gsize once = 0;
1397
1398 if (g_once_init_enter (&once))
1399 {
1400 tp_proxy_init_known_interfaces ();
1401 tp_proxy_or_subclass_hook_on_interface_add (TP_TYPE_DBUS_DAEMON,
1402 tp_cli_dbus_daemon_add_signals);
1403
1404 g_once_init_leave (&once, 1);
1405 }
1406 }
1407
1408 static void
tp_dbus_daemon_class_init(TpDBusDaemonClass * klass)1409 tp_dbus_daemon_class_init (TpDBusDaemonClass *klass)
1410 {
1411 TpProxyClass *proxy_class = (TpProxyClass *) klass;
1412 GObjectClass *object_class = (GObjectClass *) klass;
1413
1414 tp_dbus_daemon_init_known_interfaces ();
1415
1416 g_type_class_add_private (klass, sizeof (TpDBusDaemonPrivate));
1417
1418 object_class->constructor = tp_dbus_daemon_constructor;
1419 object_class->dispose = tp_dbus_daemon_dispose;
1420 object_class->finalize = tp_dbus_daemon_finalize;
1421
1422 proxy_class->interface = TP_IFACE_QUARK_DBUS_DAEMON;
1423 }
1424
1425 gboolean
_tp_dbus_daemon_is_the_shared_one(TpDBusDaemon * self)1426 _tp_dbus_daemon_is_the_shared_one (TpDBusDaemon *self)
1427 {
1428 return (self != NULL && self == starter_bus_daemon);
1429 }
1430
1431 /* Auto-generated implementation of _tp_register_dbus_glib_marshallers */
1432 #include "_gen/register-dbus-glib-marshallers-body.h"
1433