• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1diff --git a/gio/gdbusconnection.c b/gio/gdbusconnection.c
2index 1169df2..b40813c 100644
3--- a/gio/gdbusconnection.c
4+++ b/gio/gdbusconnection.c
5@@ -95,6 +95,7 @@
6 #include <stdlib.h>
7 #include <string.h>
8
9+#include "glib-private.h"
10 #include "gdbusauth.h"
11 #include "gdbusutils.h"
12 #include "gdbusaddress.h"
13@@ -282,6 +283,153 @@ call_destroy_notify (GMainContext  *context,
14
15 /* ---------------------------------------------------------------------------------------------------- */
16
17+typedef struct
18+{
19+  /* All fields are immutable after construction. */
20+  gatomicrefcount ref_count;
21+  GDBusSignalCallback callback;
22+  gpointer user_data;
23+  GDestroyNotify user_data_free_func;
24+  guint id;
25+  GMainContext *context;
26+} SignalSubscriber;
27+
28+static SignalSubscriber *
29+signal_subscriber_ref (SignalSubscriber *subscriber)
30+{
31+  g_atomic_ref_count_inc (&subscriber->ref_count);
32+  return subscriber;
33+}
34+
35+static void
36+signal_subscriber_unref (SignalSubscriber *subscriber)
37+{
38+  if (g_atomic_ref_count_dec (&subscriber->ref_count))
39+    {
40+      /* Destroy the user data. It doesn't matter which thread
41+       * signal_subscriber_unref() is called in (or whether it's called with a
42+       * lock held), as call_destroy_notify() always defers to the next
43+       * #GMainContext iteration. */
44+      call_destroy_notify (subscriber->context,
45+                           subscriber->user_data_free_func,
46+                           subscriber->user_data);
47+
48+      g_main_context_unref (subscriber->context);
49+      g_free (subscriber);
50+    }
51+}
52+
53+typedef struct
54+{
55+  /*
56+   * 1 reference while waiting for GetNameOwner() to finish
57+   * 1 reference for each SignalData that points to this one as its
58+   *   shared_name_watcher
59+   */
60+  grefcount ref_count;
61+
62+  gchar *owner;
63+  guint32 get_name_owner_serial;
64+} WatchedName;
65+
66+static WatchedName *
67+watched_name_new (void)
68+{
69+  WatchedName *watched_name = g_new0 (WatchedName, 1);
70+
71+  g_ref_count_init (&watched_name->ref_count);
72+  watched_name->owner = NULL;
73+  return g_steal_pointer (&watched_name);
74+}
75+
76+typedef struct SignalData SignalData;
77+
78+struct SignalData
79+{
80+  gchar *rule;
81+  gchar *sender;
82+  gchar *interface_name;
83+  gchar *member;
84+  gchar *object_path;
85+  gchar *arg0;
86+  GDBusSignalFlags flags;
87+  GPtrArray *subscribers;  /* (owned) (element-type SignalSubscriber) */
88+
89+  /*
90+   * If the sender is a well-known name, this is an unowned SignalData
91+   * representing the NameOwnerChanged signal that tracks its owner.
92+   * NULL if sender is NULL.
93+   * NULL if sender is its own owner (a unique name or DBUS_SERVICE_DBUS).
94+   *
95+   * Invariants: if not NULL, then
96+   * shared_name_watcher->sender == DBUS_SERVICE_DBUS
97+   * shared_name_watcher->interface_name == DBUS_INTERFACE_DBUS
98+   * shared_name_watcher->member == "NameOwnerChanged"
99+   * shared_name_watcher->object_path == DBUS_PATH_DBUS
100+   * shared_name_watcher->arg0 == sender
101+   * shared_name_watcher->flags == NONE
102+   * shared_name_watcher->watched_name == NULL
103+   */
104+  SignalData *shared_name_watcher;
105+
106+  /*
107+   * Non-NULL if this SignalData is another SignalData's shared_name_watcher.
108+   * One reference for each SignalData that has this one as its
109+   * shared_name_watcher.
110+   * Otherwise NULL.
111+   */
112+  WatchedName *watched_name;
113+};
114+
115+static SignalData *
116+signal_data_new_take (gchar *rule,
117+                      gchar *sender,
118+                      gchar *interface_name,
119+                      gchar *member,
120+                      gchar *object_path,
121+                      gchar *arg0,
122+                      GDBusSignalFlags flags)
123+{
124+  SignalData *signal_data = g_new0 (SignalData, 1);
125+
126+  signal_data->rule = rule;
127+  signal_data->sender = sender;
128+  signal_data->interface_name = interface_name;
129+  signal_data->member = member;
130+  signal_data->object_path = object_path;
131+  signal_data->arg0 = arg0;
132+  signal_data->flags = flags;
133+  signal_data->subscribers = g_ptr_array_new_with_free_func ((GDestroyNotify) signal_subscriber_unref);
134+  return g_steal_pointer (&signal_data);
135+}
136+
137+static void
138+signal_data_free (SignalData *signal_data)
139+{
140+  /* The SignalData should not be freed while it still has subscribers */
141+  g_assert (signal_data->subscribers->len == 0);
142+
143+  /* The SignalData should not be freed while it is watching for
144+   * NameOwnerChanged on behalf of another SignalData */
145+  g_assert (signal_data->watched_name == NULL);
146+
147+  /* The SignalData should be detached from its name watcher, if any,
148+   * before it is freed */
149+  g_assert (signal_data->shared_name_watcher == NULL);
150+
151+  g_free (signal_data->rule);
152+  g_free (signal_data->sender);
153+  g_free (signal_data->interface_name);
154+  g_free (signal_data->member);
155+  g_free (signal_data->object_path);
156+  g_free (signal_data->arg0);
157+  g_ptr_array_unref (signal_data->subscribers);
158+
159+  g_free (signal_data);
160+}
161+
162+/* ---------------------------------------------------------------------------------------------------- */
163+
164 #ifdef G_OS_WIN32
165 #define CONNECTION_ENSURE_LOCK(obj) do { ; } while (FALSE)
166 #else
167@@ -408,6 +556,7 @@ struct _GDBusConnection
168
169   /* Map used for managing method replies, protected by @lock */
170   GHashTable *map_method_serial_to_task;  /* guint32 -> owned GTask* */
171+  GHashTable *map_method_serial_to_name_watcher;  /* guint32 -> unowned SignalData* */
172
173   /* Maps used for managing signal subscription, protected by @lock */
174   GHashTable *map_rule_to_signal_data;                      /* match rule (gchar*)    -> SignalData */
175@@ -656,6 +805,7 @@ g_dbus_connection_finalize (GObject *object)
176     g_error_free (connection->initialization_error);
177
178   g_hash_table_unref (connection->map_method_serial_to_task);
179+  g_hash_table_unref (connection->map_method_serial_to_name_watcher);
180
181   g_hash_table_unref (connection->map_rule_to_signal_data);
182   g_hash_table_unref (connection->map_id_to_signal_data);
183@@ -1060,6 +1210,7 @@ g_dbus_connection_init (GDBusConnection *connection)
184   g_mutex_init (&connection->init_lock);
185
186   connection->map_method_serial_to_task = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref);
187+  connection->map_method_serial_to_name_watcher = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, NULL);
188
189   connection->map_rule_to_signal_data = g_hash_table_new (g_str_hash,
190                                                           g_str_equal);
191@@ -2178,6 +2329,191 @@ g_dbus_connection_send_message_with_reply_sync (GDBusConnection        *connecti
192
193 /* ---------------------------------------------------------------------------------------------------- */
194
195+/*
196+ * Called in any thread.
197+ * Must hold the connection lock when calling this, unless
198+ * connection->finalizing is TRUE.
199+ */
200+static void
201+name_watcher_unref_watched_name (GDBusConnection *connection,
202+                                 SignalData *name_watcher)
203+{
204+  WatchedName *watched_name = name_watcher->watched_name;
205+
206+  g_assert (watched_name != NULL);
207+
208+  if (!g_ref_count_dec (&watched_name->ref_count))
209+    return;
210+
211+  /* Removing watched_name from the name_watcher may result in
212+   * name_watcher being freed, so we must make sure name_watcher is no
213+   * longer in map_method_serial_to_name_watcher.
214+   *
215+   * If we stop watching the name while our GetNameOwner call was still
216+   * in-flight, then when the reply eventually arrives, we will not find
217+   * its serial number in the map and harmlessly ignore it as a result. */
218+  if (watched_name->get_name_owner_serial != 0)
219+    g_hash_table_remove (connection->map_method_serial_to_name_watcher,
220+                         GUINT_TO_POINTER (watched_name->get_name_owner_serial));
221+
222+  name_watcher->watched_name = NULL;
223+  g_free (watched_name->owner);
224+  g_free (watched_name);
225+}
226+
227+/* called in GDBusWorker thread with lock held */
228+static void
229+name_watcher_set_name_owner_unlocked (SignalData *name_watcher,
230+                                      const char *new_owner)
231+{
232+  if (new_owner != NULL && new_owner[0] == '\0')
233+    new_owner = NULL;
234+
235+  g_assert (name_watcher->watched_name != NULL);
236+  g_set_str (&name_watcher->watched_name->owner, new_owner);
237+}
238+
239+/* called in GDBusWorker thread with lock held */
240+static void
241+name_watcher_deliver_name_owner_changed_unlocked (SignalData *name_watcher,
242+                                                  GDBusMessage *message)
243+{
244+  GVariant *body;
245+
246+  body = g_dbus_message_get_body (message);
247+
248+  if (G_LIKELY (body != NULL && g_variant_is_of_type (body, G_VARIANT_TYPE ("(sss)"))))
249+    {
250+      const char *name;
251+      const char *new_owner;
252+
253+      g_variant_get (body, "(&s&s&s)", &name, NULL, &new_owner);
254+
255+      /* Our caller already checked this */
256+      g_assert (g_strcmp0 (name_watcher->arg0, name) == 0);
257+
258+      if (G_LIKELY (new_owner[0] == '\0' || g_dbus_is_unique_name (new_owner)))
259+        name_watcher_set_name_owner_unlocked (name_watcher, new_owner);
260+      else
261+        g_warning ("Received NameOwnerChanged signal with invalid owner \"%s\" for \"%s\"",
262+                   new_owner, name);
263+    }
264+  else
265+    {
266+      g_warning ("Received NameOwnerChanged signal with unexpected "
267+                 "signature %s",
268+                 body == NULL ? "()" : g_variant_get_type_string (body));
269+
270+    }
271+}
272+
273+/* called in GDBusWorker thread with lock held */
274+static void
275+name_watcher_deliver_get_name_owner_reply_unlocked (SignalData *name_watcher,
276+                                                    GDBusConnection *connection,
277+                                                    GDBusMessage *message)
278+{
279+  GDBusMessageType type;
280+  GVariant *body;
281+  WatchedName *watched_name;
282+
283+  watched_name = name_watcher->watched_name;
284+  g_assert (watched_name != NULL);
285+  g_assert (watched_name->get_name_owner_serial != 0);
286+
287+  type = g_dbus_message_get_message_type (message);
288+  body = g_dbus_message_get_body (message);
289+
290+  if (type == G_DBUS_MESSAGE_TYPE_ERROR)
291+    {
292+      if (g_strcmp0 (g_dbus_message_get_error_name (message),
293+                     "org.freedesktop.DBus.Error.NameHasNoOwner"))
294+        name_watcher_set_name_owner_unlocked (name_watcher, NULL);
295+      /* else it's something like NoReply or AccessDenied, which tells
296+       * us nothing - leave the owner set to whatever we most recently
297+       * learned from NameOwnerChanged, or NULL */
298+    }
299+  else if (type != G_DBUS_MESSAGE_TYPE_METHOD_RETURN)
300+    {
301+      g_warning ("Received GetNameOwner reply with unexpected type %d",
302+                 type);
303+    }
304+  else if (G_LIKELY (body != NULL && g_variant_is_of_type (body, G_VARIANT_TYPE ("(s)"))))
305+    {
306+      const char *new_owner;
307+
308+      g_variant_get (body, "(&s)", &new_owner);
309+
310+      if (G_LIKELY (g_dbus_is_unique_name (new_owner)))
311+        name_watcher_set_name_owner_unlocked (name_watcher, new_owner);
312+      else
313+        g_warning ("Received GetNameOwner reply with invalid owner \"%s\" for \"%s\"",
314+                   new_owner, name_watcher->arg0);
315+    }
316+  else
317+    {
318+      g_warning ("Received GetNameOwner reply with unexpected signature %s",
319+                 body == NULL ? "()" : g_variant_get_type_string (body));
320+    }
321+
322+  g_hash_table_remove (connection->map_method_serial_to_name_watcher,
323+                       GUINT_TO_POINTER (watched_name->get_name_owner_serial));
324+  watched_name->get_name_owner_serial = 0;
325+}
326+
327+/* Called in a user thread, lock is held */
328+static void
329+name_watcher_call_get_name_owner_unlocked (GDBusConnection *connection,
330+                                           SignalData *name_watcher)
331+{
332+  GDBusMessage *message;
333+  GError *local_error = NULL;
334+  WatchedName *watched_name;
335+
336+  g_assert (g_strcmp0 (name_watcher->sender, DBUS_SERVICE_DBUS) == 0);
337+  g_assert (g_strcmp0 (name_watcher->interface_name, DBUS_INTERFACE_DBUS) == 0);
338+  g_assert (g_strcmp0 (name_watcher->member, "NameOwnerChanged") == 0);
339+  g_assert (g_strcmp0 (name_watcher->object_path, DBUS_PATH_DBUS) == 0);
340+  /* arg0 of the NameOwnerChanged message is the well-known name whose owner
341+   * we are interested in */
342+  g_assert (g_dbus_is_name (name_watcher->arg0));
343+  g_assert (name_watcher->flags == G_DBUS_SIGNAL_FLAGS_NONE);
344+
345+  watched_name = name_watcher->watched_name;
346+  g_assert (watched_name != NULL);
347+  g_assert (watched_name->owner == NULL);
348+  g_assert (watched_name->get_name_owner_serial == 0);
349+  g_assert (name_watcher->shared_name_watcher == NULL);
350+
351+  message = g_dbus_message_new_method_call (DBUS_SERVICE_DBUS,
352+                                            DBUS_PATH_DBUS,
353+                                            DBUS_INTERFACE_DBUS,
354+                                            "GetNameOwner");
355+  g_dbus_message_set_body (message, g_variant_new ("(s)", name_watcher->arg0));
356+
357+  if (g_dbus_connection_send_message_unlocked (connection, message,
358+                                               G_DBUS_SEND_MESSAGE_FLAGS_NONE,
359+                                               &watched_name->get_name_owner_serial,
360+                                               &local_error))
361+    {
362+      g_assert (watched_name->get_name_owner_serial != 0);
363+      g_hash_table_insert (connection->map_method_serial_to_name_watcher,
364+                           GUINT_TO_POINTER (watched_name->get_name_owner_serial),
365+                           name_watcher);
366+    }
367+  else
368+    {
369+      g_critical ("Error while sending GetNameOwner() message: %s",
370+                  local_error->message);
371+      g_clear_error (&local_error);
372+      g_assert (watched_name->get_name_owner_serial == 0);
373+    }
374+
375+  g_object_unref (message);
376+}
377+
378+/* ---------------------------------------------------------------------------------------------------- */
379+
380 typedef struct
381 {
382   guint                       id;
383@@ -3239,69 +3575,6 @@ g_dbus_connection_remove_filter (GDBusConnection *connection,
384
385 /* ---------------------------------------------------------------------------------------------------- */
386
387-typedef struct
388-{
389-  gchar *rule;
390-  gchar *sender;
391-  gchar *sender_unique_name; /* if sender is unique or org.freedesktop.DBus, then that name... otherwise blank */
392-  gchar *interface_name;
393-  gchar *member;
394-  gchar *object_path;
395-  gchar *arg0;
396-  GDBusSignalFlags flags;
397-  GPtrArray *subscribers;  /* (owned) (element-type SignalSubscriber) */
398-} SignalData;
399-
400-static void
401-signal_data_free (SignalData *signal_data)
402-{
403-  g_free (signal_data->rule);
404-  g_free (signal_data->sender);
405-  g_free (signal_data->sender_unique_name);
406-  g_free (signal_data->interface_name);
407-  g_free (signal_data->member);
408-  g_free (signal_data->object_path);
409-  g_free (signal_data->arg0);
410-  g_ptr_array_unref (signal_data->subscribers);
411-  g_free (signal_data);
412-}
413-
414-typedef struct
415-{
416-  /* All fields are immutable after construction. */
417-  gatomicrefcount ref_count;
418-  GDBusSignalCallback callback;
419-  gpointer user_data;
420-  GDestroyNotify user_data_free_func;
421-  guint id;
422-  GMainContext *context;
423-} SignalSubscriber;
424-
425-static SignalSubscriber *
426-signal_subscriber_ref (SignalSubscriber *subscriber)
427-{
428-  g_atomic_ref_count_inc (&subscriber->ref_count);
429-  return subscriber;
430-}
431-
432-static void
433-signal_subscriber_unref (SignalSubscriber *subscriber)
434-{
435-  if (g_atomic_ref_count_dec (&subscriber->ref_count))
436-    {
437-      /* Destroy the user data. It doesn’t matter which thread
438-       * signal_subscriber_unref() is called in (or whether it’s called with a
439-       * lock held), as call_destroy_notify() always defers to the next
440-       * #GMainContext iteration. */
441-      call_destroy_notify (subscriber->context,
442-                           subscriber->user_data_free_func,
443-                           subscriber->user_data);
444-
445-      g_main_context_unref (subscriber->context);
446-      g_free (subscriber);
447-    }
448-}
449-
450 static gchar *
451 args_to_rule (const gchar      *sender,
452               const gchar      *interface_name,
453@@ -3413,7 +3686,7 @@ remove_match_rule (GDBusConnection *connection,
454 static gboolean
455 is_signal_data_for_name_lost_or_acquired (SignalData *signal_data)
456 {
457-  return g_strcmp0 (signal_data->sender_unique_name, "org.freedesktop.DBus") == 0 &&
458+  return g_strcmp0 (signal_data->sender, "org.freedesktop.DBus") == 0 &&
459          g_strcmp0 (signal_data->interface_name, "org.freedesktop.DBus") == 0 &&
460          g_strcmp0 (signal_data->object_path, "/org/freedesktop/DBus") == 0 &&
461          (g_strcmp0 (signal_data->member, "NameLost") == 0 ||
462@@ -3422,6 +3695,43 @@ is_signal_data_for_name_lost_or_acquired (SignalData *signal_data)
463
464 /* ---------------------------------------------------------------------------------------------------- */
465
466+/* called in any thread, connection lock is held */
467+static void
468+add_signal_data (GDBusConnection *connection,
469+                 SignalData      *signal_data,
470+                 const char      *sender_unique_name)
471+{
472+  GPtrArray *signal_data_array;
473+
474+  g_hash_table_insert (connection->map_rule_to_signal_data,
475+                       signal_data->rule,
476+                       signal_data);
477+
478+  /* Add the match rule to the bus...
479+   *
480+   * Avoid adding match rules for NameLost and NameAcquired messages - the bus will
481+   * always send such messages to us.
482+   */
483+  if (connection->flags & G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION)
484+    {
485+      if (!is_signal_data_for_name_lost_or_acquired (signal_data))
486+        add_match_rule (connection, signal_data->rule);
487+    }
488+
489+  signal_data_array = g_hash_table_lookup (connection->map_sender_unique_name_to_signal_data_array,
490+                                           sender_unique_name);
491+  if (signal_data_array == NULL)
492+    {
493+      signal_data_array = g_ptr_array_new ();
494+      g_hash_table_insert (connection->map_sender_unique_name_to_signal_data_array,
495+                           g_strdup (sender_unique_name),
496+                           signal_data_array);
497+    }
498+  g_ptr_array_add (signal_data_array, signal_data);
499+}
500+
501+/* ---------------------------------------------------------------------------------------------------- */
502+
503 /**
504  * g_dbus_connection_signal_subscribe:
505  * @connection: a #GDBusConnection
506@@ -3510,8 +3820,9 @@ g_dbus_connection_signal_subscribe (GDBusConnection     *connection,
507 {
508   gchar *rule;
509   SignalData *signal_data;
510+  SignalData *name_watcher = NULL;
511   SignalSubscriber *subscriber;
512-  GPtrArray *signal_data_array;
513+  gboolean sender_is_its_own_owner;
514   const gchar *sender_unique_name;
515
516   /* Right now we abort if AddMatch() fails since it can only fail with the bus being in
517@@ -3547,6 +3858,11 @@ g_dbus_connection_signal_subscribe (GDBusConnection     *connection,
518   rule = args_to_rule (sender, interface_name, member, object_path, arg0, flags);
519
520   if (sender != NULL && (g_dbus_is_unique_name (sender) || g_strcmp0 (sender, "org.freedesktop.DBus") == 0))
521+    sender_is_its_own_owner = TRUE;
522+  else
523+    sender_is_its_own_owner = FALSE;
524+
525+  if (sender_is_its_own_owner)
526     sender_unique_name = sender;
527   else
528     sender_unique_name = "";
529@@ -3568,43 +3884,61 @@ g_dbus_connection_signal_subscribe (GDBusConnection     *connection,
530       goto out;
531     }
532
533-  signal_data = g_new0 (SignalData, 1);
534-  signal_data->rule                  = rule;
535-  signal_data->sender                = g_strdup (sender);
536-  signal_data->sender_unique_name    = g_strdup (sender_unique_name);
537-  signal_data->interface_name        = g_strdup (interface_name);
538-  signal_data->member                = g_strdup (member);
539-  signal_data->object_path           = g_strdup (object_path);
540-  signal_data->arg0                  = g_strdup (arg0);
541-  signal_data->flags                 = flags;
542-  signal_data->subscribers           = g_ptr_array_new_with_free_func ((GDestroyNotify) signal_subscriber_unref);
543+  signal_data = signal_data_new_take (g_steal_pointer (&rule),
544+                                      g_strdup (sender),
545+                                      g_strdup (interface_name),
546+                                      g_strdup (member),
547+                                      g_strdup (object_path),
548+                                      g_strdup (arg0),
549+                                      flags);
550   g_ptr_array_add (signal_data->subscribers, subscriber);
551
552-  g_hash_table_insert (connection->map_rule_to_signal_data,
553-                       signal_data->rule,
554-                       signal_data);
555+  /* If subscribing to a signal from a specific sender with a well-known
556+   * name, we must first subscribe to NameOwnerChanged signals for that
557+   * well-known name, so that we can match the current owner of the name
558+   * against the sender of each signal. */
559+  if (sender != NULL && !sender_is_its_own_owner)
560+    {
561+      gchar *name_owner_rule = NULL;
562+      /* We already checked that sender != NULL implies MESSAGE_BUS_CONNECTION */
563+      g_assert (connection->flags & G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION);
564+
565+      name_owner_rule = args_to_rule (DBUS_SERVICE_DBUS,
566+                                      DBUS_INTERFACE_DBUS,
567+                                      "NameOwnerChanged",
568+                                      DBUS_PATH_DBUS,
569+                                      sender,
570+                                      G_DBUS_SIGNAL_FLAGS_NONE);
571+      name_watcher = g_hash_table_lookup (connection->map_rule_to_signal_data, name_owner_rule);
572+
573+      if (name_watcher == NULL)
574+        {
575+          name_watcher = signal_data_new_take (g_steal_pointer (&name_owner_rule),
576+                                               g_strdup (DBUS_SERVICE_DBUS),
577+                                               g_strdup (DBUS_INTERFACE_DBUS),
578+                                               g_strdup ("NameOwnerChanged"),
579+                                               g_strdup (DBUS_PATH_DBUS),
580+                                               g_strdup (sender),
581+                                               G_DBUS_SIGNAL_FLAGS_NONE);
582+          add_signal_data (connection, name_watcher, DBUS_SERVICE_DBUS);
583+        }
584
585-  /* Add the match rule to the bus...
586-   *
587-   * Avoid adding match rules for NameLost and NameAcquired messages - the bus will
588-   * always send such messages to us.
589-   */
590-  if (connection->flags & G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION)
591-    {
592-      if (!is_signal_data_for_name_lost_or_acquired (signal_data))
593-        add_match_rule (connection, signal_data->rule);
594-    }
595+      if (name_watcher->watched_name == NULL)
596+        {
597+          name_watcher->watched_name = watched_name_new ();
598+          name_watcher_call_get_name_owner_unlocked (connection, name_watcher);
599+        }
600+      else
601+        {
602+          g_ref_count_inc (&name_watcher->watched_name->ref_count);
603+        }
604
605-  signal_data_array = g_hash_table_lookup (connection->map_sender_unique_name_to_signal_data_array,
606-                                           signal_data->sender_unique_name);
607-  if (signal_data_array == NULL)
608-    {
609-      signal_data_array = g_ptr_array_new ();
610-      g_hash_table_insert (connection->map_sender_unique_name_to_signal_data_array,
611-                           g_strdup (signal_data->sender_unique_name),
612-                           signal_data_array);
613+      signal_data->shared_name_watcher = name_watcher;
614+
615+      g_clear_pointer (&name_owner_rule, g_free);
616     }
617-  g_ptr_array_add (signal_data_array, signal_data);
618+
619+  add_signal_data (connection, signal_data, sender_unique_name);
620
621  out:
622   g_hash_table_insert (connection->map_id_to_signal_data,
623@@ -3618,6 +3952,75 @@ g_dbus_connection_signal_subscribe (GDBusConnection     *connection,
624
625 /* ---------------------------------------------------------------------------------------------------- */
626
627+/*
628+ * Called in any thread.
629+ * Must hold the connection lock when calling this, unless
630+ * connection->finalizing is TRUE.
631+ * May free signal_data, so do not dereference it after this.
632+ */
633+static void
634+remove_signal_data_if_unused (GDBusConnection *connection,
635+                              SignalData *signal_data)
636+{
637+  const gchar *sender_unique_name;
638+  GPtrArray *signal_data_array;
639+
640+  /* Cannot remove while there are still subscribers */
641+  if (signal_data->subscribers->len != 0)
642+    return;
643+
644+  /* Cannot remove while another SignalData is still using this one
645+   * as its shared_name_watcher, which holds watched_name->ref_count > 0 */
646+  if (signal_data->watched_name != NULL)
647+    return;
648+
649+  /* Point of no return: we have committed to removing it */
650+
651+  if (signal_data->sender != NULL && signal_data->shared_name_watcher == NULL)
652+    sender_unique_name = signal_data->sender;
653+  else
654+    sender_unique_name = "";
655+
656+  g_warn_if_fail (g_hash_table_remove (connection->map_rule_to_signal_data, signal_data->rule));
657+
658+  signal_data_array = g_hash_table_lookup (connection->map_sender_unique_name_to_signal_data_array,
659+                                           sender_unique_name);
660+  g_warn_if_fail (signal_data_array != NULL);
661+  g_warn_if_fail (g_ptr_array_remove (signal_data_array, signal_data));
662+
663+  if (signal_data_array->len == 0)
664+    {
665+      g_warn_if_fail (g_hash_table_remove (connection->map_sender_unique_name_to_signal_data_array,
666+                                           sender_unique_name));
667+    }
668+
669+  /* remove the match rule from the bus unless NameLost or NameAcquired (see subscribe()) */
670+  if ((connection->flags & G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION) &&
671+      !is_signal_data_for_name_lost_or_acquired (signal_data) &&
672+      !g_dbus_connection_is_closed (connection) &&
673+      !connection->finalizing)
674+    {
675+      /* The check for g_dbus_connection_is_closed() means that
676+       * sending the RemoveMatch message can't fail with
677+       * G_IO_ERROR_CLOSED, because we're holding the lock,
678+       * so on_worker_closed() can't happen between the check we just
679+       * did, and releasing the lock later.
680+       */
681+      remove_match_rule (connection, signal_data->rule);
682+    }
683+
684+  if (signal_data->shared_name_watcher != NULL)
685+    {
686+      SignalData *name_watcher = g_steal_pointer (&signal_data->shared_name_watcher);
687+
688+      name_watcher_unref_watched_name (connection, name_watcher);
689+      /* May free signal_data */
690+      remove_signal_data_if_unused (connection, name_watcher);
691+    }
692+
693+  signal_data_free (signal_data);
694+}
695+
696 /* called in any thread */
697 /* must hold lock when calling this (except if connection->finalizing is TRUE)
698  * returns the number of removed subscribers */
699@@ -3626,7 +4029,6 @@ unsubscribe_id_internal (GDBusConnection *connection,
700                          guint            subscription_id)
701 {
702   SignalData *signal_data;
703-  GPtrArray *signal_data_array;
704   guint n;
705   guint n_removed = 0;
706
707@@ -3654,39 +4056,8 @@ unsubscribe_id_internal (GDBusConnection *connection,
708       n_removed++;
709       g_ptr_array_remove_index_fast (signal_data->subscribers, n);
710
711-      if (signal_data->subscribers->len == 0)
712-        {
713-          g_warn_if_fail (g_hash_table_remove (connection->map_rule_to_signal_data, signal_data->rule));
714-
715-          signal_data_array = g_hash_table_lookup (connection->map_sender_unique_name_to_signal_data_array,
716-                                                   signal_data->sender_unique_name);
717-          g_warn_if_fail (signal_data_array != NULL);
718-          g_warn_if_fail (g_ptr_array_remove (signal_data_array, signal_data));
719-
720-          if (signal_data_array->len == 0)
721-            {
722-              g_warn_if_fail (g_hash_table_remove (connection->map_sender_unique_name_to_signal_data_array,
723-                                                   signal_data->sender_unique_name));
724-            }
725-
726-          /* remove the match rule from the bus unless NameLost or NameAcquired (see subscribe()) */
727-          if ((connection->flags & G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION) &&
728-              !is_signal_data_for_name_lost_or_acquired (signal_data) &&
729-              !g_dbus_connection_is_closed (connection) &&
730-              !connection->finalizing)
731-            {
732-              /* The check for g_dbus_connection_is_closed() means that
733-               * sending the RemoveMatch message can't fail with
734-               * G_IO_ERROR_CLOSED, because we're holding the lock,
735-               * so on_worker_closed() can't happen between the check we just
736-               * did, and releasing the lock later.
737-               */
738-              remove_match_rule (connection, signal_data->rule);
739-            }
740-
741-          signal_data_free (signal_data);
742-        }
743-
744+      /* May free signal_data */
745+      remove_signal_data_if_unused (connection, signal_data);
746       goto out;
747     }
748
749@@ -3901,6 +4272,46 @@ schedule_callbacks (GDBusConnection *connection,
750       if (signal_data->object_path != NULL && g_strcmp0 (signal_data->object_path, path) != 0)
751         continue;
752
753+      if (signal_data->shared_name_watcher != NULL)
754+        {
755+          /* We want signals from a specified well-known name, which means
756+           * the signal's sender needs to be the unique name that currently
757+           * owns that well-known name, and we will have found this
758+           * SignalData in
759+           * connection->map_sender_unique_name_to_signal_data_array[""]. */
760+          const WatchedName *watched_name;
761+          const char *current_owner;
762+
763+          g_assert (signal_data->sender != NULL);
764+          /* Invariant: We never need to watch for the owner of a unique
765+           * name, or for the owner of DBUS_SERVICE_DBUS, either of which
766+           * is always its own owner */
767+          g_assert (!g_dbus_is_unique_name (signal_data->sender));
768+          g_assert (g_strcmp0 (signal_data->sender, DBUS_SERVICE_DBUS) != 0);
769+
770+          watched_name = signal_data->shared_name_watcher->watched_name;
771+          g_assert (watched_name != NULL);
772+          current_owner = watched_name->owner;
773+
774+          /* Skip the signal if the actual sender is not known to own
775+           * the required name */
776+          if (current_owner == NULL || g_strcmp0 (current_owner, sender) != 0)
777+            continue;
778+        }
779+      else if (signal_data->sender != NULL)
780+        {
781+          /* We want signals from a unique name or o.fd.DBus... */
782+          g_assert (g_dbus_is_unique_name (signal_data->sender)
783+                    || g_str_equal (signal_data->sender, DBUS_SERVICE_DBUS));
784+
785+          /* ... which means we must have found this SignalData in
786+           * connection->map_sender_unique_name_to_signal_data_array[signal_data->sender],
787+           * therefore we would only have found it if the signal's
788+           * actual sender matches the required signal_data->sender */
789+          g_assert (g_strcmp0 (signal_data->sender, sender) == 0);
790+        }
791+      /* else the sender is unspecified and we will accept anything */
792+
793       if (signal_data->arg0 != NULL)
794         {
795           if (arg0 == NULL)
796@@ -3920,6 +4331,17 @@ schedule_callbacks (GDBusConnection *connection,
797             continue;
798         }
799
800+      if (signal_data->watched_name != NULL)
801+        {
802+          /* Invariant: SignalData should only have a watched_name if it
803+           * represents the NameOwnerChanged signal */
804+          g_assert (g_strcmp0 (sender, DBUS_SERVICE_DBUS) == 0);
805+          g_assert (g_strcmp0 (interface, DBUS_INTERFACE_DBUS) == 0);
806+          g_assert (g_strcmp0 (path, DBUS_PATH_DBUS) == 0);
807+          g_assert (g_strcmp0 (member, "NameOwnerChanged") == 0);
808+          name_watcher_deliver_name_owner_changed_unlocked (signal_data, message);
809+        }
810+
811       for (m = 0; m < signal_data->subscribers->len; m++)
812         {
813           SignalSubscriber *subscriber = signal_data->subscribers->pdata[m];
814@@ -3981,7 +4403,7 @@ distribute_signals (GDBusConnection *connection,
815         schedule_callbacks (connection, signal_data_array, message, sender);
816     }
817
818-  /* collect subscribers not matching on sender */
819+  /* collect subscribers not matching on sender, or matching a well-known name */
820   signal_data_array = g_hash_table_lookup (connection->map_sender_unique_name_to_signal_data_array, "");
821   if (signal_data_array != NULL)
822     schedule_callbacks (connection, signal_data_array, message, sender);
823diff --git a/gio/gdbusmessage.c b/gio/gdbusmessage.c
824index ecef6cd..d4d0cd9 100644
825--- a/gio/gdbusmessage.c
826+++ b/gio/gdbusmessage.c
827@@ -506,6 +506,7 @@ struct _GDBusMessage
828   guint32 serial;
829   GHashTable *headers;
830   GVariant *body;
831+  GVariant *arg0_cache;  /* (nullable) (owned) */
832 #ifdef G_OS_UNIX
833   GUnixFDList *fd_list;
834 #endif
835@@ -528,6 +529,7 @@ g_dbus_message_finalize (GObject *object)
836     g_hash_table_unref (message->headers);
837   if (message->body != NULL)
838     g_variant_unref (message->body);
839+  g_clear_pointer (&message->arg0_cache, g_variant_unref);
840 #ifdef G_OS_UNIX
841   if (message->fd_list != NULL)
842     g_object_unref (message->fd_list);
843@@ -1163,6 +1165,7 @@ g_dbus_message_set_body (GDBusMessage  *message,
844   if (body == NULL)
845     {
846       message->body = NULL;
847+      message->arg0_cache = NULL;
848       g_dbus_message_set_signature (message, NULL);
849     }
850   else
851@@ -1173,6 +1176,12 @@ g_dbus_message_set_body (GDBusMessage  *message,
852
853       message->body = g_variant_ref_sink (body);
854
855+      if (g_variant_is_of_type (message->body, G_VARIANT_TYPE_TUPLE) &&
856+          g_variant_n_children (message->body) > 0)
857+        message->arg0_cache = g_variant_get_child_value (message->body, 0);
858+      else
859+        message->arg0_cache = NULL;
860+
861       type_string = g_variant_get_type_string (body);
862       type_string_len = strlen (type_string);
863       g_assert (type_string_len >= 2);
864@@ -2325,6 +2334,14 @@ g_dbus_message_new_from_blob (guchar                *blob,
865                                                  2,
866                                                  &local_error);
867           g_variant_type_free (variant_type);
868+
869+          if (message->body != NULL &&
870+              g_variant_is_of_type (message->body, G_VARIANT_TYPE_TUPLE) &&
871+              g_variant_n_children (message->body) > 0)
872+            message->arg0_cache = g_variant_get_child_value (message->body, 0);
873+          else
874+            message->arg0_cache = NULL;
875+
876           if (message->body == NULL)
877             goto fail;
878         }
879@@ -3364,22 +3381,12 @@ g_dbus_message_set_signature (GDBusMessage  *message,
880 const gchar *
881 g_dbus_message_get_arg0 (GDBusMessage  *message)
882 {
883-  const gchar *ret;
884-
885   g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), NULL);
886
887-  ret = NULL;
888-
889-  if (message->body != NULL && g_variant_is_of_type (message->body, G_VARIANT_TYPE_TUPLE))
890-    {
891-      GVariant *item;
892-      item = g_variant_get_child_value (message->body, 0);
893-      if (g_variant_is_of_type (item, G_VARIANT_TYPE_STRING))
894-        ret = g_variant_get_string (item, NULL);
895-      g_variant_unref (item);
896-    }
897-
898-  return ret;
899+  if (message->arg0_cache != NULL &&
900+      g_variant_is_of_type (message->arg0_cache, G_VARIANT_TYPE_STRING))
901+    return g_variant_get_string (message->arg0_cache, NULL);
902+  return NULL;
903 }
904
905 /* ---------------------------------------------------------------------------------------------------- */
906@@ -3822,6 +3829,8 @@ g_dbus_message_copy (GDBusMessage  *message,
907    * to just ref (as opposed to deep-copying) the GVariant instances
908    */
909   ret->body = message->body != NULL ? g_variant_ref (message->body) : NULL;
910+
911+  ret->arg0_cache = message->arg0_cache != NULL ? g_variant_ref (message->arg0_cache) : NULL;
912   g_hash_table_iter_init (&iter, message->headers);
913   while (g_hash_table_iter_next (&iter, &header_key, (gpointer) &header_value))
914     g_hash_table_insert (ret->headers, header_key, g_variant_ref (header_value));
915diff --git a/gio/gdbusprivate.h b/gio/gdbusprivate.h
916index 72d2c32..ac737bd 100644
917--- a/gio/gdbusprivate.h
918+++ b/gio/gdbusprivate.h
919@@ -29,6 +29,11 @@
920
921 G_BEGIN_DECLS
922
923+/* Bus name, interface and object path of the message bus itself */
924+#define DBUS_SERVICE_DBUS "org.freedesktop.DBus"
925+#define DBUS_INTERFACE_DBUS DBUS_SERVICE_DBUS
926+#define DBUS_PATH_DBUS "/org/freedesktop/DBus"
927+
928 /* ---------------------------------------------------------------------------------------------------- */
929
930 typedef struct GDBusWorker GDBusWorker;
931diff --git a/gio/tests/gdbus-proxy.c b/gio/tests/gdbus-proxy.c
932index eed75ac..9303d00 100644
933--- a/gio/tests/gdbus-proxy.c
934+++ b/gio/tests/gdbus-proxy.c
935@@ -778,6 +778,12 @@ kill_test_service (GDBusConnection *connection)
936   while (!name_disappeared)
937     g_main_context_iteration (NULL, TRUE);
938
939+  /* GDBusConnection doesn't guarantee that different subscriptions to the
940+   * same signal will get their callbacks scheduled in any particular order,
941+   * so make sure they have all happened */
942+  while (g_main_context_iteration (NULL, FALSE))
943+    continue;
944+
945   g_bus_unwatch_name (watch_id);
946 #else
947   g_warning ("Can't kill com.example.TestService");
948diff --git a/gio/tests/gdbus-subscribe.c b/gio/tests/gdbus-subscribe.c
949new file mode 100644
950index 0000000..4487a92
951--- /dev/null
952+++ b/gio/tests/gdbus-subscribe.c
953@@ -0,0 +1,1342 @@
954+/*
955+ * Copyright 2024 Collabora Ltd.
956+ * SPDX-License-Identifier: LGPL-2.1-or-later
957+ */
958+
959+#include <gio/gio.h>
960+
961+#include "gdbus-tests.h"
962+
963+/* From the D-Bus Specification */
964+#define DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER 1
965+
966+#define DBUS_SERVICE_DBUS "org.freedesktop.DBus"
967+#define DBUS_PATH_DBUS "/org/freedesktop/DBus"
968+#define DBUS_INTERFACE_DBUS DBUS_SERVICE_DBUS
969+#define NAME_OWNER_CHANGED "NameOwnerChanged"
970+
971+/* A signal that each connection emits to indicate that it has finished
972+ * emitting other signals */
973+#define FINISHED_PATH "/org/gtk/Test/Finished"
974+#define FINISHED_INTERFACE "org.gtk.Test.Finished"
975+#define FINISHED_SIGNAL "Finished"
976+
977+/* A signal emitted during testing */
978+#define EXAMPLE_PATH "/org/gtk/GDBus/ExampleInterface"
979+#define EXAMPLE_INTERFACE "org.gtk.GDBus.ExampleInterface"
980+#define FOO_SIGNAL "Foo"
981+
982+#define ALREADY_OWNED_NAME "org.gtk.Test.AlreadyOwned"
983+#define OWNED_LATER_NAME "org.gtk.Test.OwnedLater"
984+
985+/* Log @s in a debug message. */
986+static inline const char *
987+nonnull (const char *s,
988+         const char *if_null)
989+{
990+  return (s == NULL) ? if_null : s;
991+}
992+
993+typedef enum
994+{
995+  TEST_CONN_NONE,
996+  TEST_CONN_FIRST,
997+  /* A connection that subscribes to signals */
998+  TEST_CONN_SUBSCRIBER = TEST_CONN_FIRST,
999+  /* A mockup of a legitimate service */
1000+  TEST_CONN_SERVICE,
1001+  /* A mockup of a second legitimate service */
1002+  TEST_CONN_SERVICE2,
1003+  /* A connection that tries to trick @subscriber into processing its signals
1004+   * as if they came from @service */
1005+  TEST_CONN_ATTACKER,
1006+  NUM_TEST_CONNS
1007+} TestConn;
1008+
1009+static const char * const test_conn_descriptions[NUM_TEST_CONNS] =
1010+{
1011+  "(unused)",
1012+  "subscriber",
1013+  "service",
1014+  "service 2",
1015+  "attacker"
1016+};
1017+
1018+typedef enum
1019+{
1020+  SUBSCRIPTION_MODE_CONN,
1021+  SUBSCRIPTION_MODE_PROXY,
1022+  SUBSCRIPTION_MODE_PARALLEL
1023+} SubscriptionMode;
1024+
1025+typedef struct
1026+{
1027+  GDBusProxy *received_by_proxy;
1028+  TestConn sender;
1029+  char *path;
1030+  char *iface;
1031+  char *member;
1032+  GVariant *parameters;
1033+  char *arg0;
1034+  guint32 step;
1035+} ReceivedMessage;
1036+
1037+static void
1038+received_message_free (ReceivedMessage *self)
1039+{
1040+
1041+  g_clear_object (&self->received_by_proxy);
1042+  g_free (self->path);
1043+  g_free (self->iface);
1044+  g_free (self->member);
1045+  g_clear_pointer (&self->parameters, g_variant_unref);
1046+  g_free (self->arg0);
1047+  g_free (self);
1048+}
1049+
1050+typedef struct
1051+{
1052+  TestConn sender;
1053+  TestConn unicast_to;
1054+  const char *path;
1055+  const char *iface;
1056+  const char *member;
1057+  const char *arg0;
1058+  const char *args;
1059+  guint received_by_conn;
1060+  guint received_by_proxy;
1061+} TestEmitSignal;
1062+
1063+typedef struct
1064+{
1065+  const char *string_sender;
1066+  TestConn unique_sender;
1067+  const char *path;
1068+  const char *iface;
1069+  const char *member;
1070+  const char *arg0;
1071+  GDBusSignalFlags flags;
1072+  gboolean unsubscribe_immediately;
1073+} TestSubscribe;
1074+
1075+typedef struct
1076+{
1077+  const char *name;
1078+  TestConn owner;
1079+  guint received_by_conn;
1080+  guint received_by_proxy;
1081+} TestOwnName;
1082+
1083+typedef enum
1084+{
1085+  TEST_ACTION_NONE = 0,
1086+  TEST_ACTION_SUBSCRIBE,
1087+  TEST_ACTION_EMIT_SIGNAL,
1088+  TEST_ACTION_OWN_NAME,
1089+} TestAction;
1090+
1091+typedef struct
1092+{
1093+  TestAction action;
1094+  union {
1095+    TestEmitSignal signal;
1096+    TestSubscribe subscribe;
1097+    TestOwnName own_name;
1098+    guint unsubscribe_undo_step;
1099+  } u;
1100+} TestStep;
1101+
1102+/* Arbitrary, extend as necessary to accommodate the longest test */
1103+#define MAX_TEST_STEPS 10
1104+
1105+typedef struct
1106+{
1107+  const char *description;
1108+  TestStep steps[MAX_TEST_STEPS];
1109+} TestPlan;
1110+
1111+static const TestPlan plan_simple =
1112+{
1113+  .description = "A broadcast is only received after subscribing to it",
1114+  .steps = {
1115+    {
1116+      /* We don't receive a signal if we haven't subscribed yet */
1117+      .action = TEST_ACTION_EMIT_SIGNAL,
1118+      .u.signal = {
1119+        .sender = TEST_CONN_SERVICE,
1120+        .path = EXAMPLE_PATH,
1121+        .iface = EXAMPLE_INTERFACE,
1122+        .member = FOO_SIGNAL,
1123+        .received_by_conn = 0,
1124+        .received_by_proxy = 0
1125+      },
1126+    },
1127+    {
1128+      .action = TEST_ACTION_SUBSCRIBE,
1129+      .u.subscribe = {
1130+        .path = EXAMPLE_PATH,
1131+        .iface = EXAMPLE_INTERFACE,
1132+      },
1133+    },
1134+    {
1135+      /* Now it works */
1136+      .action = TEST_ACTION_EMIT_SIGNAL,
1137+      .u.signal = {
1138+        .sender = TEST_CONN_SERVICE,
1139+        .path = EXAMPLE_PATH,
1140+        .iface = EXAMPLE_INTERFACE,
1141+        .member = FOO_SIGNAL,
1142+        .received_by_conn = 1,
1143+        /* The proxy can't be used in this case, because it needs
1144+         * a bus name to subscribe to */
1145+        .received_by_proxy = 0
1146+      },
1147+    },
1148+  },
1149+};
1150+
1151+static const TestPlan plan_broadcast_from_anyone =
1152+{
1153+  .description = "A subscription with NULL sender accepts broadcast and unicast",
1154+  .steps = {
1155+    {
1156+      /* Subscriber wants to receive signals from anyone */
1157+      .action = TEST_ACTION_SUBSCRIBE,
1158+      .u.subscribe = {
1159+        .path = EXAMPLE_PATH,
1160+        .iface = EXAMPLE_INTERFACE,
1161+      },
1162+    },
1163+    {
1164+      /* First service sends a broadcast */
1165+      .action = TEST_ACTION_EMIT_SIGNAL,
1166+      .u.signal = {
1167+        .sender = TEST_CONN_SERVICE,
1168+        .path = EXAMPLE_PATH,
1169+        .iface = EXAMPLE_INTERFACE,
1170+        .member = FOO_SIGNAL,
1171+        .received_by_conn = 1,
1172+        .received_by_proxy = 0
1173+      },
1174+    },
1175+    {
1176+      /* Second service also sends a broadcast */
1177+      .action = TEST_ACTION_EMIT_SIGNAL,
1178+      .u.signal = {
1179+        .sender = TEST_CONN_SERVICE2,
1180+        .path = EXAMPLE_PATH,
1181+        .iface = EXAMPLE_INTERFACE,
1182+        .member = FOO_SIGNAL,
1183+        .received_by_conn = 1,
1184+        .received_by_proxy = 0
1185+      },
1186+    },
1187+    {
1188+      /* First service sends a unicast signal */
1189+      .action = TEST_ACTION_EMIT_SIGNAL,
1190+      .u.signal = {
1191+        .sender = TEST_CONN_SERVICE,
1192+        .unicast_to = TEST_CONN_SUBSCRIBER,
1193+        .path = EXAMPLE_PATH,
1194+        .iface = EXAMPLE_INTERFACE,
1195+        .member = FOO_SIGNAL,
1196+        .received_by_conn = 1,
1197+        .received_by_proxy = 0
1198+      },
1199+    },
1200+    {
1201+      /* Second service also sends a unicast signal */
1202+      .action = TEST_ACTION_EMIT_SIGNAL,
1203+      .u.signal = {
1204+        .sender = TEST_CONN_SERVICE2,
1205+        .unicast_to = TEST_CONN_SUBSCRIBER,
1206+        .path = EXAMPLE_PATH,
1207+        .iface = EXAMPLE_INTERFACE,
1208+        .member = FOO_SIGNAL,
1209+        .received_by_conn = 1,
1210+        .received_by_proxy = 0
1211+      },
1212+    },
1213+  },
1214+};
1215+
1216+static const TestPlan plan_match_twice =
1217+{
1218+  .description = "A message matching more than one subscription is received "
1219+                 "once per subscription",
1220+  .steps = {
1221+    {
1222+      .action = TEST_ACTION_SUBSCRIBE,
1223+      .u.subscribe = {
1224+        .unique_sender = TEST_CONN_SERVICE,
1225+        .path = EXAMPLE_PATH,
1226+        .iface = EXAMPLE_INTERFACE,
1227+      },
1228+    },
1229+    {
1230+      .action = TEST_ACTION_SUBSCRIBE,
1231+      .u.subscribe = {
1232+        .path = EXAMPLE_PATH,
1233+      },
1234+    },
1235+    {
1236+      .action = TEST_ACTION_SUBSCRIBE,
1237+      .u.subscribe = {
1238+        .iface = EXAMPLE_INTERFACE,
1239+      },
1240+    },
1241+    {
1242+      .action = TEST_ACTION_SUBSCRIBE,
1243+      .u.subscribe = {
1244+        .unique_sender = TEST_CONN_SERVICE,
1245+        .path = EXAMPLE_PATH,
1246+        .iface = EXAMPLE_INTERFACE,
1247+      },
1248+    },
1249+    {
1250+      .action = TEST_ACTION_EMIT_SIGNAL,
1251+      .u.signal = {
1252+        .sender = TEST_CONN_SERVICE,
1253+        .path = EXAMPLE_PATH,
1254+        .iface = EXAMPLE_INTERFACE,
1255+        .member = FOO_SIGNAL,
1256+        .received_by_conn = 4,
1257+        /* Only the first and last work with GDBusProxy */
1258+        .received_by_proxy = 2
1259+      },
1260+    },
1261+  },
1262+};
1263+
1264+static const TestPlan plan_limit_by_unique_name =
1265+{
1266+  .description = "A subscription via a unique name only accepts messages "
1267+                 "sent by that same unique name",
1268+  .steps = {
1269+    {
1270+      /* Subscriber wants to receive signals from service */
1271+      .action = TEST_ACTION_SUBSCRIBE,
1272+      .u.subscribe = {
1273+        .unique_sender = TEST_CONN_SERVICE,
1274+        .path = EXAMPLE_PATH,
1275+        .iface = EXAMPLE_INTERFACE,
1276+      },
1277+    },
1278+    {
1279+      /* Attacker wants to trick subscriber into thinking that service
1280+       * sent a signal */
1281+      .action = TEST_ACTION_EMIT_SIGNAL,
1282+      .u.signal = {
1283+        .sender = TEST_CONN_ATTACKER,
1284+        .path = EXAMPLE_PATH,
1285+        .iface = EXAMPLE_INTERFACE,
1286+        .member = FOO_SIGNAL,
1287+        .received_by_conn = 0,
1288+        .received_by_proxy = 0
1289+      },
1290+    },
1291+    {
1292+      /* Attacker tries harder, by sending a signal unicast directly to
1293+       * the subscriber */
1294+      .action = TEST_ACTION_EMIT_SIGNAL,
1295+      .u.signal = {
1296+        .sender = TEST_CONN_ATTACKER,
1297+        .unicast_to = TEST_CONN_SUBSCRIBER,
1298+        .path = EXAMPLE_PATH,
1299+        .iface = EXAMPLE_INTERFACE,
1300+        .member = FOO_SIGNAL,
1301+        .received_by_conn = 0,
1302+        .received_by_proxy = 0
1303+      },
1304+    },
1305+    {
1306+      /* When the real service sends a signal, it should still get through */
1307+      .action = TEST_ACTION_EMIT_SIGNAL,
1308+      .u.signal = {
1309+        .sender = TEST_CONN_SERVICE,
1310+        .path = EXAMPLE_PATH,
1311+        .iface = EXAMPLE_INTERFACE,
1312+        .member = FOO_SIGNAL,
1313+        .received_by_conn = 1,
1314+        .received_by_proxy = 1
1315+      },
1316+    },
1317+  },
1318+};
1319+
1320+static const TestPlan plan_nonexistent_unique_name =
1321+{
1322+  .description = "A subscription via a unique name that doesn't exist "
1323+                 "accepts no messages",
1324+  .steps = {
1325+    {
1326+      /* Subscriber wants to receive signals from service */
1327+      .action = TEST_ACTION_SUBSCRIBE,
1328+      .u.subscribe = {
1329+        /* This relies on the implementation detail that the dbus-daemon
1330+         * (and presumably other bus implementations) never actually generates
1331+         * a unique name in this format */
1332+        .string_sender = ":0.this.had.better.not.exist",
1333+        .path = EXAMPLE_PATH,
1334+        .iface = EXAMPLE_INTERFACE,
1335+      },
1336+    },
1337+    {
1338+      /* Attacker wants to trick subscriber into thinking that service
1339+       * sent a signal */
1340+      .action = TEST_ACTION_EMIT_SIGNAL,
1341+      .u.signal = {
1342+        .sender = TEST_CONN_ATTACKER,
1343+        .path = EXAMPLE_PATH,
1344+        .iface = EXAMPLE_INTERFACE,
1345+        .member = FOO_SIGNAL,
1346+        .received_by_conn = 0,
1347+        .received_by_proxy = 0
1348+      },
1349+    },
1350+    {
1351+      /* Attacker tries harder, by sending a signal unicast directly to
1352+       * the subscriber */
1353+      .action = TEST_ACTION_EMIT_SIGNAL,
1354+      .u.signal = {
1355+        .sender = TEST_CONN_ATTACKER,
1356+        .unicast_to = TEST_CONN_SUBSCRIBER,
1357+        .path = EXAMPLE_PATH,
1358+        .iface = EXAMPLE_INTERFACE,
1359+        .member = FOO_SIGNAL,
1360+        .received_by_conn = 0,
1361+        .received_by_proxy = 0
1362+      },
1363+    },
1364+  },
1365+};
1366+
1367+static const TestPlan plan_limit_by_well_known_name =
1368+{
1369+  .description = "A subscription via a well-known name only accepts messages "
1370+                 "sent by the owner of that well-known name",
1371+  .steps = {
1372+    {
1373+      /* Service already owns one name */
1374+      .action = TEST_ACTION_OWN_NAME,
1375+      .u.own_name = {
1376+        .name = ALREADY_OWNED_NAME,
1377+        .owner = TEST_CONN_SERVICE
1378+      },
1379+    },
1380+    {
1381+      /* Subscriber wants to receive signals from service */
1382+      .action = TEST_ACTION_SUBSCRIBE,
1383+      .u.subscribe = {
1384+        .string_sender = ALREADY_OWNED_NAME,
1385+        .path = EXAMPLE_PATH,
1386+        .iface = EXAMPLE_INTERFACE,
1387+      },
1388+    },
1389+    {
1390+      /* Subscriber wants to receive signals from service by another name */
1391+      .action = TEST_ACTION_SUBSCRIBE,
1392+      .u.subscribe = {
1393+        .string_sender = OWNED_LATER_NAME,
1394+        .path = EXAMPLE_PATH,
1395+        .iface = EXAMPLE_INTERFACE,
1396+      },
1397+    },
1398+    {
1399+      /* Attacker wants to trick subscriber into thinking that service
1400+       * sent a signal */
1401+      .action = TEST_ACTION_EMIT_SIGNAL,
1402+      .u.signal = {
1403+        .sender = TEST_CONN_ATTACKER,
1404+        .path = EXAMPLE_PATH,
1405+        .iface = EXAMPLE_INTERFACE,
1406+        .member = FOO_SIGNAL,
1407+        .received_by_conn = 0,
1408+        .received_by_proxy = 0
1409+      },
1410+    },
1411+    {
1412+      /* Attacker tries harder, by sending a signal unicast directly to
1413+       * the subscriber */
1414+      .action = TEST_ACTION_EMIT_SIGNAL,
1415+      .u.signal = {
1416+        .sender = TEST_CONN_ATTACKER,
1417+        .unicast_to = TEST_CONN_SUBSCRIBER,
1418+        .path = EXAMPLE_PATH,
1419+        .iface = EXAMPLE_INTERFACE,
1420+        .member = FOO_SIGNAL,
1421+        .received_by_conn = 0,
1422+        .received_by_proxy = 0
1423+      },
1424+    },
1425+    {
1426+      /* When the service sends a signal with the name it already owns,
1427+       * it should get through */
1428+      .action = TEST_ACTION_EMIT_SIGNAL,
1429+      .u.signal = {
1430+        .sender = TEST_CONN_SERVICE,
1431+        .path = EXAMPLE_PATH,
1432+        .iface = EXAMPLE_INTERFACE,
1433+        .member = FOO_SIGNAL,
1434+        .received_by_conn = 1,
1435+        .received_by_proxy = 1
1436+      },
1437+    },
1438+    {
1439+      /* Service claims another name */
1440+      .action = TEST_ACTION_OWN_NAME,
1441+      .u.own_name = {
1442+        .name = OWNED_LATER_NAME,
1443+        .owner = TEST_CONN_SERVICE
1444+      },
1445+    },
1446+    {
1447+      /* Now the subscriber gets this signal twice, once for each
1448+       * subscription; and similarly each of the two proxies gets this
1449+       * signal twice */
1450+      .action = TEST_ACTION_EMIT_SIGNAL,
1451+      .u.signal = {
1452+        .sender = TEST_CONN_SERVICE,
1453+        .path = EXAMPLE_PATH,
1454+        .iface = EXAMPLE_INTERFACE,
1455+        .member = FOO_SIGNAL,
1456+        .received_by_conn = 2,
1457+        .received_by_proxy = 2
1458+      },
1459+    },
1460+  },
1461+};
1462+
1463+static const TestPlan plan_unsubscribe_immediately =
1464+{
1465+  .description = "Unsubscribing before GetNameOwner can return doesn't result in a crash",
1466+  .steps = {
1467+    {
1468+      /* Service already owns one name */
1469+      .action = TEST_ACTION_OWN_NAME,
1470+      .u.own_name = {
1471+        .name = ALREADY_OWNED_NAME,
1472+        .owner = TEST_CONN_SERVICE
1473+      },
1474+    },
1475+    {
1476+      .action = TEST_ACTION_SUBSCRIBE,
1477+      .u.subscribe = {
1478+        .string_sender = ALREADY_OWNED_NAME,
1479+        .path = EXAMPLE_PATH,
1480+        .iface = EXAMPLE_INTERFACE,
1481+        .unsubscribe_immediately = TRUE
1482+      },
1483+    },
1484+    {
1485+      .action = TEST_ACTION_EMIT_SIGNAL,
1486+      .u.signal = {
1487+        .sender = TEST_CONN_SERVICE,
1488+        .path = EXAMPLE_PATH,
1489+        .iface = EXAMPLE_INTERFACE,
1490+        .member = FOO_SIGNAL,
1491+        .received_by_conn = 0,
1492+        /* The proxy can't unsubscribe, except by destroying the proxy
1493+         * completely, which we don't currently implement in this test */
1494+        .received_by_proxy = 1
1495+      },
1496+    },
1497+  },
1498+};
1499+
1500+static const TestPlan plan_limit_to_message_bus =
1501+{
1502+  .description = "A subscription to the message bus only accepts messages "
1503+                 "from the message bus",
1504+  .steps = {
1505+    {
1506+      /* Subscriber wants to receive signals from the message bus itself */
1507+      .action = TEST_ACTION_SUBSCRIBE,
1508+      .u.subscribe = {
1509+        .string_sender = DBUS_SERVICE_DBUS,
1510+        .path = DBUS_PATH_DBUS,
1511+        .iface = DBUS_INTERFACE_DBUS,
1512+      },
1513+    },
1514+    {
1515+      /* Attacker wants to trick subscriber into thinking that the message
1516+       * bus sent a signal */
1517+      .action = TEST_ACTION_EMIT_SIGNAL,
1518+      .u.signal = {
1519+        .sender = TEST_CONN_ATTACKER,
1520+        .path = DBUS_PATH_DBUS,
1521+        .iface = DBUS_INTERFACE_DBUS,
1522+        .member = NAME_OWNER_CHANGED,
1523+        .arg0 = "would I lie to you?",
1524+        .received_by_conn = 0,
1525+        .received_by_proxy = 0
1526+      },
1527+    },
1528+    {
1529+      /* Attacker tries harder, by sending a signal unicast directly to
1530+       * the subscriber, and using more realistic arguments */
1531+      .action = TEST_ACTION_EMIT_SIGNAL,
1532+      .u.signal = {
1533+        .unicast_to = TEST_CONN_SUBSCRIBER,
1534+        .sender = TEST_CONN_ATTACKER,
1535+        .path = DBUS_PATH_DBUS,
1536+        .iface = DBUS_INTERFACE_DBUS,
1537+        .member = NAME_OWNER_CHANGED,
1538+        .args = "('com.example.Name', '', ':1.12')",
1539+        .received_by_conn = 0,
1540+        .received_by_proxy = 0
1541+      },
1542+    },
1543+    {
1544+      /* When the message bus sends a signal (in this case triggered by
1545+       * owning a name), it should still get through */
1546+      .action = TEST_ACTION_OWN_NAME,
1547+      .u.own_name = {
1548+        .name = OWNED_LATER_NAME,
1549+        .owner = TEST_CONN_SERVICE,
1550+        .received_by_conn = 1,
1551+        .received_by_proxy = 1
1552+      },
1553+    },
1554+  },
1555+};
1556+
1557+typedef struct
1558+{
1559+  const TestPlan *plan;
1560+  SubscriptionMode mode;
1561+  GError *error;
1562+  /* (element-type ReceivedMessage) */
1563+  GPtrArray *received;
1564+  /* conns[TEST_CONN_NONE] is unused and remains NULL */
1565+  GDBusConnection *conns[NUM_TEST_CONNS];
1566+  /* Proxies on conns[TEST_CONN_SUBSCRIBER] */
1567+  GPtrArray *proxies;
1568+  /* unique_names[TEST_CONN_NONE] is unused and remains NULL */
1569+  const char *unique_names[NUM_TEST_CONNS];
1570+  /* finished[TEST_CONN_NONE] is unused and remains FALSE */
1571+  gboolean finished[NUM_TEST_CONNS];
1572+  /* Remains 0 for any step that is not a subscription */
1573+  guint subscriptions[MAX_TEST_STEPS];
1574+  /* Number of times the signal from step n was received */
1575+  guint received_by_conn[MAX_TEST_STEPS];
1576+  /* Number of times the signal from step n was received */
1577+  guint received_by_proxy[MAX_TEST_STEPS];
1578+  guint finished_subscription;
1579+} Fixture;
1580+
1581+/* Wait for asynchronous messages from @conn to have been processed
1582+ * by the message bus, as a sequence point so that we can make
1583+ * "happens before" and "happens after" assertions relative to this.
1584+ * The easiest way to achieve this is to call a message bus method that has
1585+ * no arguments and wait for it to return: because the message bus processes
1586+ * messages in-order, anything we sent before this must have been processed
1587+ * by the time this call arrives. */
1588+static void
1589+connection_wait_for_bus (GDBusConnection *conn)
1590+{
1591+  GError *error = NULL;
1592+  GVariant *call_result;
1593+
1594+  call_result = g_dbus_connection_call_sync (conn,
1595+                                             DBUS_SERVICE_DBUS,
1596+                                             DBUS_PATH_DBUS,
1597+                                             DBUS_INTERFACE_DBUS,
1598+                                             "GetId",
1599+                                             NULL,   /* arguments */
1600+                                             NULL,   /* result type */
1601+                                             G_DBUS_CALL_FLAGS_NONE,
1602+                                             -1,
1603+                                             NULL,
1604+                                             &error);
1605+  g_assert_no_error (error);
1606+  g_assert_nonnull (call_result);
1607+  g_variant_unref (call_result);
1608+}
1609+
1610+/*
1611+ * Called when the subscriber receives a message from any connection
1612+ * announcing that it has emitted all the signals that it plans to emit.
1613+ */
1614+static void
1615+subscriber_finished_cb (GDBusConnection *conn,
1616+                        const char      *sender_name,
1617+                        const char      *path,
1618+                        const char      *iface,
1619+                        const char      *member,
1620+                        GVariant        *parameters,
1621+                        void            *user_data)
1622+{
1623+  Fixture *f = user_data;
1624+  GDBusConnection *subscriber = f->conns[TEST_CONN_SUBSCRIBER];
1625+  guint i;
1626+
1627+  g_assert_true (conn == subscriber);
1628+
1629+  for (i = TEST_CONN_FIRST; i < G_N_ELEMENTS (f->conns); i++)
1630+    {
1631+      if (g_str_equal (sender_name, f->unique_names[i]))
1632+        {
1633+          g_assert_false (f->finished[i]);
1634+          f->finished[i] = TRUE;
1635+
1636+          g_test_message ("Received Finished signal from %s %s",
1637+                          test_conn_descriptions[i], sender_name);
1638+          return;
1639+        }
1640+    }
1641+
1642+  g_error ("Received Finished signal from unknown sender %s", sender_name);
1643+}
1644+
1645+/*
1646+ * Called when we receive a signal, either via the GDBusProxy (proxy != NULL)
1647+ * or via the GDBusConnection (proxy == NULL).
1648+ */
1649+static void
1650+fixture_received_signal (Fixture    *f,
1651+                         GDBusProxy *proxy,
1652+                         const char *sender_name,
1653+                         const char *path,
1654+                         const char *iface,
1655+                         const char *member,
1656+                         GVariant   *parameters)
1657+{
1658+  guint i;
1659+  ReceivedMessage *received;
1660+
1661+  /* Ignore the Finished signal if it matches a wildcard subscription */
1662+  if (g_str_equal (member, FINISHED_SIGNAL))
1663+    return;
1664+
1665+  received = g_new0 (ReceivedMessage, 1);
1666+
1667+  if (proxy != NULL)
1668+    received->received_by_proxy = g_object_ref (proxy);
1669+  else
1670+    received->received_by_proxy = NULL;
1671+
1672+  received->path = g_strdup (path);
1673+  received->iface = g_strdup (iface);
1674+  received->member = g_strdup (member);
1675+  received->parameters = g_variant_ref (parameters);
1676+
1677+  for (i = TEST_CONN_FIRST; i < G_N_ELEMENTS (f->conns); i++)
1678+    {
1679+      if (g_str_equal (sender_name, f->unique_names[i]))
1680+        {
1681+          received->sender = i;
1682+          g_assert_false (f->finished[i]);
1683+          break;
1684+        }
1685+    }
1686+
1687+  if (g_str_equal (sender_name, DBUS_SERVICE_DBUS))
1688+    {
1689+      g_test_message ("Signal received from message bus %s",
1690+                      sender_name);
1691+    }
1692+  else
1693+    {
1694+      g_test_message ("Signal received from %s %s",
1695+                      test_conn_descriptions[received->sender],
1696+                      sender_name);
1697+      g_assert_cmpint (received->sender, !=, TEST_CONN_NONE);
1698+    }
1699+
1700+  g_test_message ("Signal received from %s %s via %s",
1701+                  test_conn_descriptions[received->sender],
1702+                  sender_name,
1703+                  proxy != NULL ? "proxy" : "connection");
1704+  g_test_message ("\tPath: %s", path);
1705+  g_test_message ("\tInterface: %s", iface);
1706+  g_test_message ("\tMember: %s", member);
1707+
1708+  if (g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(su)")))
1709+    {
1710+      g_variant_get (parameters, "(su)", &received->arg0, &received->step);
1711+      g_test_message ("\tString argument 0: %s", received->arg0);
1712+      g_test_message ("\tSent in step: %u", received->step);
1713+    }
1714+  else if (g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(uu)")))
1715+    {
1716+      g_variant_get (parameters, "(uu)", NULL, &received->step);
1717+      g_test_message ("\tArgument 0: (not a string)");
1718+      g_test_message ("\tSent in step: %u", received->step);
1719+    }
1720+  else if (g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(sss)")))
1721+    {
1722+      const char *name;
1723+      const char *old_owner;
1724+      const char *new_owner;
1725+
1726+      /* The only signal of this signature that we legitimately receive
1727+       * during this test is NameOwnerChanged, so just assert that it
1728+       * is from the message bus and can be matched to a plausible step.
1729+       * (This is less thorough than the above, and will not work if we
1730+       * add a test scenario where a name's ownership is repeatedly
1731+       * changed while watching NameOwnerChanged - so don't do that.) */
1732+      g_assert_cmpstr (sender_name, ==, DBUS_SERVICE_DBUS);
1733+      g_assert_cmpstr (path, ==, DBUS_PATH_DBUS);
1734+      g_assert_cmpstr (iface, ==, DBUS_INTERFACE_DBUS);
1735+      g_assert_cmpstr (member, ==, NAME_OWNER_CHANGED);
1736+
1737+      g_variant_get (parameters, "(&s&s&s)", &name, &old_owner, &new_owner);
1738+
1739+      for (i = 0; i < G_N_ELEMENTS (f->plan->steps); i++)
1740+        {
1741+          const TestStep *step = &f->plan->steps[i];
1742+
1743+          if (step->action == TEST_ACTION_OWN_NAME)
1744+            {
1745+              const TestOwnName *own_name = &step->u.own_name;
1746+
1747+              if (g_str_equal (name, own_name->name)
1748+                  && g_str_equal (new_owner, f->unique_names[own_name->owner])
1749+                  && own_name->received_by_conn > 0)
1750+                {
1751+                  received->step = i;
1752+                  break;
1753+                }
1754+            }
1755+
1756+          if (i >= G_N_ELEMENTS (f->plan->steps))
1757+            g_error ("Could not match message to a test step");
1758+        }
1759+    }
1760+  else
1761+    {
1762+      g_error ("Unexpected message received");
1763+    }
1764+
1765+  g_ptr_array_add (f->received, g_steal_pointer (&received));
1766+}
1767+
1768+static void
1769+proxy_signal_cb (GDBusProxy *proxy,
1770+                 const char *sender_name,
1771+                 const char *member,
1772+                 GVariant   *parameters,
1773+                 void       *user_data)
1774+{
1775+  Fixture *f = user_data;
1776+
1777+  fixture_received_signal (f, proxy, sender_name,
1778+                           g_dbus_proxy_get_object_path (proxy),
1779+                           g_dbus_proxy_get_interface_name (proxy),
1780+                           member, parameters);
1781+}
1782+
1783+static void
1784+subscribed_signal_cb (GDBusConnection *conn,
1785+                      const char      *sender_name,
1786+                      const char      *path,
1787+                      const char      *iface,
1788+                      const char      *member,
1789+                      GVariant        *parameters,
1790+                      void            *user_data)
1791+{
1792+  Fixture *f = user_data;
1793+  GDBusConnection *subscriber = f->conns[TEST_CONN_SUBSCRIBER];
1794+
1795+  g_assert_true (conn == subscriber);
1796+
1797+  fixture_received_signal (f, NULL, sender_name, path, iface, member, parameters);
1798+}
1799+
1800+static void
1801+fixture_subscribe (Fixture             *f,
1802+                   const TestSubscribe *subscribe,
1803+                   guint                step_number)
1804+{
1805+  GDBusConnection *subscriber = f->conns[TEST_CONN_SUBSCRIBER];
1806+  const char *sender;
1807+
1808+  if (subscribe->string_sender != NULL)
1809+    {
1810+      sender = subscribe->string_sender;
1811+      g_test_message ("\tSender: %s", sender);
1812+    }
1813+  else if (subscribe->unique_sender != TEST_CONN_NONE)
1814+    {
1815+      sender = f->unique_names[subscribe->unique_sender];
1816+      g_test_message ("\tSender: %s %s",
1817+                      test_conn_descriptions[subscribe->unique_sender],
1818+                      sender);
1819+    }
1820+  else
1821+    {
1822+      sender = NULL;
1823+      g_test_message ("\tSender: (any)");
1824+    }
1825+
1826+  g_test_message ("\tPath: %s", nonnull (subscribe->path, "(any)"));
1827+  g_test_message ("\tInterface: %s",
1828+                  nonnull (subscribe->iface, "(any)"));
1829+  g_test_message ("\tMember: %s",
1830+                  nonnull (subscribe->member, "(any)"));
1831+  g_test_message ("\tString argument 0: %s",
1832+                  nonnull (subscribe->arg0, "(any)"));
1833+  g_test_message ("\tFlags: %x", subscribe->flags);
1834+
1835+  if (f->mode != SUBSCRIPTION_MODE_PROXY)
1836+    {
1837+      /* CONN or PARALLEL */
1838+      guint id;
1839+
1840+      g_test_message ("\tSubscribing via connection");
1841+      id = g_dbus_connection_signal_subscribe (subscriber,
1842+                                               sender,
1843+                                               subscribe->iface,
1844+                                               subscribe->member,
1845+                                               subscribe->path,
1846+                                               subscribe->arg0,
1847+                                               subscribe->flags,
1848+                                               subscribed_signal_cb,
1849+                                               f, NULL);
1850+
1851+      g_assert_cmpuint (id, !=, 0);
1852+
1853+      if (subscribe->unsubscribe_immediately)
1854+        {
1855+          g_test_message ("\tImmediately unsubscribing");
1856+          g_dbus_connection_signal_unsubscribe (subscriber, id);
1857+        }
1858+      else
1859+        {
1860+          f->subscriptions[step_number] = id;
1861+        }
1862+    }
1863+
1864+  if (f->mode != SUBSCRIPTION_MODE_CONN)
1865+    {
1866+      /* PROXY or PARALLEL */
1867+
1868+      if (sender == NULL)
1869+        {
1870+          g_test_message ("\tCannot subscribe via proxy: no bus name");
1871+        }
1872+      else if (subscribe->path == NULL)
1873+        {
1874+          g_test_message ("\tCannot subscribe via proxy: no path");
1875+        }
1876+      else if (subscribe->iface == NULL)
1877+        {
1878+          g_test_message ("\tCannot subscribe via proxy: no interface");
1879+        }
1880+      else
1881+        {
1882+          GDBusProxy *proxy;
1883+
1884+          g_test_message ("\tSubscribing via proxy");
1885+          proxy = g_dbus_proxy_new_sync (subscriber,
1886+                                         (G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES
1887+                                          | G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START),
1888+                                         NULL,    /* GDBusInterfaceInfo */
1889+                                         sender,
1890+                                         subscribe->path,
1891+                                         subscribe->iface,
1892+                                         NULL,    /* GCancellable */
1893+                                         &f->error);
1894+          g_assert_no_error (f->error);
1895+          g_assert_nonnull (proxy);
1896+          g_signal_connect (proxy, "g-signal", G_CALLBACK (proxy_signal_cb), f);
1897+          g_ptr_array_add (f->proxies, g_steal_pointer (&proxy));
1898+        }
1899+    }
1900+
1901+  /* As in setup(), we need to wait for AddMatch to happen. */
1902+  g_test_message ("Waiting for AddMatch to be processed");
1903+  connection_wait_for_bus (subscriber);
1904+}
1905+
1906+static void
1907+fixture_emit_signal (Fixture              *f,
1908+                     const TestEmitSignal *signal,
1909+                     guint                 step_number)
1910+{
1911+  GVariant *body;
1912+  const char *destination;
1913+  gboolean ok;
1914+
1915+  g_test_message ("\tSender: %s",
1916+                  test_conn_descriptions[signal->sender]);
1917+
1918+  if (signal->unicast_to != TEST_CONN_NONE)
1919+    {
1920+      destination = f->unique_names[signal->unicast_to];
1921+      g_test_message ("\tDestination: %s %s",
1922+                      test_conn_descriptions[signal->unicast_to],
1923+                      destination);
1924+    }
1925+  else
1926+    {
1927+      destination = NULL;
1928+      g_test_message ("\tDestination: (broadcast)");
1929+    }
1930+
1931+  g_assert_nonnull (signal->path);
1932+  g_test_message ("\tPath: %s", signal->path);
1933+  g_assert_nonnull (signal->iface);
1934+  g_test_message ("\tInterface: %s", signal->iface);
1935+  g_assert_nonnull (signal->member);
1936+  g_test_message ("\tMember: %s", signal->member);
1937+
1938+  /* If arg0 is non-NULL, put it in the message's argument 0.
1939+   * Otherwise put something that will not match any arg0.
1940+   * Either way, put the sequence number in argument 1 so we can
1941+   * correlate sent messages with received messages later. */
1942+  if (signal->args != NULL)
1943+    {
1944+      /* floating */
1945+      body = g_variant_new_parsed (signal->args);
1946+      g_assert_nonnull (body);
1947+    }
1948+  else if (signal->arg0 != NULL)
1949+    {
1950+      g_test_message ("\tString argument 0: %s", signal->arg0);
1951+      body = g_variant_new ("(su)", signal->arg0, (guint32) step_number);
1952+    }
1953+  else
1954+    {
1955+      g_test_message ("\tArgument 0: (not a string)");
1956+      body = g_variant_new ("(uu)", (guint32) 0, (guint32) step_number);
1957+    }
1958+
1959+  ok = g_dbus_connection_emit_signal (f->conns[signal->sender],
1960+                                      destination,
1961+                                      signal->path,
1962+                                      signal->iface,
1963+                                      signal->member,
1964+                                      /* steals floating reference */
1965+                                      g_steal_pointer (&body),
1966+                                      &f->error);
1967+  g_assert_no_error (f->error);
1968+  g_assert_true (ok);
1969+
1970+  /* Emitting the signal is asynchronous, so if we want subsequent steps
1971+   * to be guaranteed to happen after the signal from the message bus's
1972+   * perspective, we have to do a round-trip to the message bus to sync up. */
1973+  g_test_message ("Waiting for signal to reach message bus");
1974+  connection_wait_for_bus (f->conns[signal->sender]);
1975+}
1976+
1977+static void
1978+fixture_own_name (Fixture *f,
1979+                  const TestOwnName *own_name)
1980+{
1981+  GVariant *call_result;
1982+  guint32 flags;
1983+  guint32 result_code;
1984+
1985+  g_test_message ("\tName: %s", own_name->name);
1986+  g_test_message ("\tOwner: %s",
1987+                  test_conn_descriptions[own_name->owner]);
1988+
1989+  /* For simplicity, we do this via a direct bus call rather than
1990+   * using g_bus_own_name_on_connection(). The flags in
1991+   * GBusNameOwnerFlags are numerically equal to those in the
1992+   * D-Bus wire protocol. */
1993+  flags = G_BUS_NAME_OWNER_FLAGS_DO_NOT_QUEUE;
1994+  call_result = g_dbus_connection_call_sync (f->conns[own_name->owner],
1995+                                             DBUS_SERVICE_DBUS,
1996+                                             DBUS_PATH_DBUS,
1997+                                             DBUS_INTERFACE_DBUS,
1998+                                             "RequestName",
1999+                                             g_variant_new ("(su)",
2000+                                                           own_name->name,
2001+                                                           flags),
2002+                                             G_VARIANT_TYPE ("(u)"),
2003+                                             G_DBUS_CALL_FLAGS_NONE,
2004+                                             -1,
2005+                                             NULL,
2006+                                             &f->error);
2007+  g_assert_no_error (f->error);
2008+  g_assert_nonnull (call_result);
2009+  g_variant_get (call_result, "(u)", &result_code);
2010+  g_assert_cmpuint (result_code, ==, DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER);
2011+  g_variant_unref (call_result);
2012+}
2013+
2014+static void
2015+fixture_run_plan (Fixture          *f,
2016+                  const TestPlan   *plan,
2017+                  SubscriptionMode  mode)
2018+{
2019+  guint i;
2020+
2021+  G_STATIC_ASSERT (G_N_ELEMENTS (plan->steps) == G_N_ELEMENTS (f->subscriptions));
2022+  G_STATIC_ASSERT (G_N_ELEMENTS (plan->steps) == G_N_ELEMENTS (f->received_by_conn));
2023+  G_STATIC_ASSERT (G_N_ELEMENTS (plan->steps) == G_N_ELEMENTS (f->received_by_proxy));
2024+
2025+  f->mode = mode;
2026+  f->plan = plan;
2027+
2028+  g_test_summary (plan->description);
2029+
2030+  for (i = 0; i < G_N_ELEMENTS (plan->steps); i++)
2031+    {
2032+      const TestStep *step = &plan->steps[i];
2033+
2034+      switch (step->action)
2035+        {
2036+          case TEST_ACTION_SUBSCRIBE:
2037+            g_test_message ("Step %u: adding subscription", i);
2038+            fixture_subscribe (f, &step->u.subscribe, i);
2039+            break;
2040+
2041+          case TEST_ACTION_EMIT_SIGNAL:
2042+            g_test_message ("Step %u: emitting signal", i);
2043+            fixture_emit_signal (f, &step->u.signal, i);
2044+            break;
2045+
2046+          case TEST_ACTION_OWN_NAME:
2047+            g_test_message ("Step %u: claiming bus name", i);
2048+            fixture_own_name (f, &step->u.own_name);
2049+            break;
2050+
2051+          case TEST_ACTION_NONE:
2052+            /* Padding to fill the rest of the array, do nothing */
2053+            break;
2054+
2055+          default:
2056+            g_return_if_reached ();
2057+        }
2058+    }
2059+
2060+  /* Now that we have done everything we wanted to do, emit Finished
2061+   * from each connection. */
2062+  for (i = TEST_CONN_FIRST; i < G_N_ELEMENTS (f->conns); i++)
2063+    {
2064+      gboolean ok;
2065+
2066+      ok = g_dbus_connection_emit_signal (f->conns[i],
2067+                                          NULL,
2068+                                          FINISHED_PATH,
2069+                                          FINISHED_INTERFACE,
2070+                                          FINISHED_SIGNAL,
2071+                                          NULL,
2072+                                          &f->error);
2073+      g_assert_no_error (f->error);
2074+      g_assert_true (ok);
2075+    }
2076+
2077+  /* Wait until we have seen the Finished signal from each sender */
2078+  while (TRUE)
2079+    {
2080+      gboolean all_finished = TRUE;
2081+
2082+      for (i = TEST_CONN_FIRST; i < G_N_ELEMENTS (f->conns); i++)
2083+        all_finished = all_finished && f->finished[i];
2084+
2085+      if (all_finished)
2086+        break;
2087+
2088+      g_main_context_iteration (NULL, TRUE);
2089+    }
2090+
2091+  /* Assert that the correct things happened before each Finished signal */
2092+  for (i = 0; i < f->received->len; i++)
2093+    {
2094+      const ReceivedMessage *received = g_ptr_array_index (f->received, i);
2095+
2096+      g_assert_cmpuint (received->step, <, G_N_ELEMENTS (f->received_by_conn));
2097+      g_assert_cmpuint (received->step, <, G_N_ELEMENTS (f->received_by_proxy));
2098+
2099+      if (received->received_by_proxy != NULL)
2100+        f->received_by_proxy[received->step] += 1;
2101+      else
2102+        f->received_by_conn[received->step] += 1;
2103+    }
2104+
2105+  for (i = 0; i < G_N_ELEMENTS (plan->steps); i++)
2106+    {
2107+      const TestStep *step = &plan->steps[i];
2108+
2109+      if (step->action == TEST_ACTION_EMIT_SIGNAL)
2110+        {
2111+          const TestEmitSignal *signal = &plan->steps[i].u.signal;
2112+
2113+          if (mode != SUBSCRIPTION_MODE_PROXY)
2114+            {
2115+              g_test_message ("Signal from step %u was received %u times by "
2116+                              "GDBusConnection, expected %u",
2117+                              i, f->received_by_conn[i], signal->received_by_conn);
2118+              g_assert_cmpuint (f->received_by_conn[i], ==, signal->received_by_conn);
2119+            }
2120+          else
2121+            {
2122+              g_assert_cmpuint (f->received_by_conn[i], ==, 0);
2123+            }
2124+
2125+          if (mode != SUBSCRIPTION_MODE_CONN)
2126+            {
2127+              g_test_message ("Signal from step %u was received %u times by "
2128+                              "GDBusProxy, expected %u",
2129+                              i, f->received_by_proxy[i], signal->received_by_proxy);
2130+              g_assert_cmpuint (f->received_by_proxy[i], ==, signal->received_by_proxy);
2131+            }
2132+          else
2133+            {
2134+              g_assert_cmpuint (f->received_by_proxy[i], ==, 0);
2135+            }
2136+        }
2137+      else if (step->action == TEST_ACTION_OWN_NAME)
2138+        {
2139+          const TestOwnName *own_name = &plan->steps[i].u.own_name;
2140+
2141+          if (mode != SUBSCRIPTION_MODE_PROXY)
2142+            {
2143+              g_test_message ("NameOwnerChanged from step %u was received %u "
2144+                              "times by GDBusConnection, expected %u",
2145+                              i, f->received_by_conn[i], own_name->received_by_conn);
2146+              g_assert_cmpuint (f->received_by_conn[i], ==, own_name->received_by_conn);
2147+            }
2148+          else
2149+            {
2150+              g_assert_cmpuint (f->received_by_conn[i], ==, 0);
2151+            }
2152+
2153+          if (mode != SUBSCRIPTION_MODE_CONN)
2154+            {
2155+              g_test_message ("NameOwnerChanged from step %u was received %u "
2156+                              "times by GDBusProxy, expected %u",
2157+                              i, f->received_by_proxy[i], own_name->received_by_proxy);
2158+              g_assert_cmpuint (f->received_by_proxy[i], ==, own_name->received_by_proxy);
2159+            }
2160+          else
2161+            {
2162+              g_assert_cmpuint (f->received_by_proxy[i], ==, 0);
2163+            }
2164+        }
2165+    }
2166+}
2167+
2168+static void
2169+setup (Fixture *f,
2170+       G_GNUC_UNUSED const void *context)
2171+{
2172+  GDBusConnection *subscriber;
2173+  guint i;
2174+
2175+  session_bus_up ();
2176+
2177+  f->proxies = g_ptr_array_new_full (MAX_TEST_STEPS, g_object_unref);
2178+  f->received = g_ptr_array_new_full (MAX_TEST_STEPS,
2179+                                      (GDestroyNotify) received_message_free);
2180+
2181+  for (i = TEST_CONN_FIRST; i < G_N_ELEMENTS (f->conns); i++)
2182+    {
2183+      f->conns[i] = _g_bus_get_priv (G_BUS_TYPE_SESSION, NULL, &f->error);
2184+      g_assert_no_error (f->error);
2185+      g_assert_nonnull (f->conns[i]);
2186+
2187+      f->unique_names[i] = g_dbus_connection_get_unique_name (f->conns[i]);
2188+      g_assert_nonnull (f->unique_names[i]);
2189+      g_test_message ("%s is %s",
2190+                      test_conn_descriptions[i],
2191+                      f->unique_names[i]);
2192+    }
2193+
2194+  subscriber = f->conns[TEST_CONN_SUBSCRIBER];
2195+
2196+  /* Used to wait for all connections to finish sending whatever they
2197+   * wanted to send */
2198+  f->finished_subscription = g_dbus_connection_signal_subscribe (subscriber,
2199+                                                                 NULL,
2200+                                                                 FINISHED_INTERFACE,
2201+                                                                 FINISHED_SIGNAL,
2202+                                                                 FINISHED_PATH,
2203+                                                                 NULL,
2204+                                                                 G_DBUS_SIGNAL_FLAGS_NONE,
2205+                                                                 subscriber_finished_cb,
2206+                                                                 f, NULL);
2207+  /* AddMatch is sent asynchronously, so we don't know how
2208+   * soon it will be processed. Before emitting signals, we
2209+   * need to wait for the message bus to get as far as processing
2210+   * AddMatch. */
2211+  g_test_message ("Waiting for AddMatch to be processed");
2212+  connection_wait_for_bus (subscriber);
2213+}
2214+
2215+static void
2216+test_conn_subscribe (Fixture *f,
2217+                     const void *context)
2218+{
2219+  fixture_run_plan (f, context, SUBSCRIPTION_MODE_CONN);
2220+}
2221+
2222+static void
2223+test_proxy_subscribe (Fixture *f,
2224+                      const void *context)
2225+{
2226+  fixture_run_plan (f, context, SUBSCRIPTION_MODE_PROXY);
2227+}
2228+
2229+static void
2230+test_parallel_subscribe (Fixture *f,
2231+                         const void *context)
2232+{
2233+  fixture_run_plan (f, context, SUBSCRIPTION_MODE_PARALLEL);
2234+}
2235+
2236+static void
2237+teardown (Fixture *f,
2238+          G_GNUC_UNUSED const void *context)
2239+{
2240+  GDBusConnection *subscriber = f->conns[TEST_CONN_SUBSCRIBER];
2241+  guint i;
2242+
2243+  g_ptr_array_unref (f->proxies);
2244+
2245+  if (f->finished_subscription != 0)
2246+    g_dbus_connection_signal_unsubscribe (subscriber, f->finished_subscription);
2247+
2248+  for (i = 0; i < G_N_ELEMENTS (f->subscriptions); i++)
2249+    {
2250+      if (f->subscriptions[i] != 0)
2251+        g_dbus_connection_signal_unsubscribe (subscriber, f->subscriptions[i]);
2252+    }
2253+
2254+  g_ptr_array_unref (f->received);
2255+
2256+  for (i = TEST_CONN_FIRST; i < G_N_ELEMENTS (f->conns); i++)
2257+    g_clear_object (&f->conns[i]);
2258+
2259+  g_clear_error (&f->error);
2260+
2261+  session_bus_down ();
2262+}
2263+
2264+int
2265+main (int   argc,
2266+      char *argv[])
2267+{
2268+  g_test_init (&argc, &argv, G_TEST_OPTION_ISOLATE_DIRS, NULL);
2269+
2270+  g_test_dbus_unset ();
2271+
2272+#define ADD_SUBSCRIBE_TEST(name) \
2273+  do { \
2274+    g_test_add ("/gdbus/subscribe/conn/" #name, \
2275+                Fixture, &plan_ ## name, \
2276+                setup, test_conn_subscribe, teardown); \
2277+    g_test_add ("/gdbus/subscribe/proxy/" #name, \
2278+                Fixture, &plan_ ## name, \
2279+                setup, test_proxy_subscribe, teardown); \
2280+    g_test_add ("/gdbus/subscribe/parallel/" #name, \
2281+                Fixture, &plan_ ## name, \
2282+                setup, test_parallel_subscribe, teardown); \
2283+  } while (0)
2284+
2285+  ADD_SUBSCRIBE_TEST (simple);
2286+  ADD_SUBSCRIBE_TEST (broadcast_from_anyone);
2287+  ADD_SUBSCRIBE_TEST (match_twice);
2288+  ADD_SUBSCRIBE_TEST (limit_by_unique_name);
2289+  ADD_SUBSCRIBE_TEST (nonexistent_unique_name);
2290+  ADD_SUBSCRIBE_TEST (limit_by_well_known_name);
2291+  ADD_SUBSCRIBE_TEST (limit_to_message_bus);
2292+  ADD_SUBSCRIBE_TEST (unsubscribe_immediately);
2293+
2294+  return g_test_run();
2295+}
2296+
2297diff --git a/gio/tests/meson.build b/gio/tests/meson.build
2298index 3ed23a5..fd826cf 100644
2299--- a/gio/tests/meson.build
2300+++ b/gio/tests/meson.build
2301@@ -347,6 +347,7 @@ if host_machine.system() != 'windows'
2302       },
2303       'gdbus-proxy-unique-name' : {'extra_sources' : extra_sources},
2304       'gdbus-proxy-well-known-name' : {'extra_sources' : extra_sources},
2305+      'gdbus-subscribe' : {'extra_sources' : extra_sources},
2306       'gdbus-test-codegen' : {
2307         'extra_sources' : [extra_sources, gdbus_test_codegen_generated, gdbus_test_codegen_generated_interface_info],
2308         'c_args' : ['-DGLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_2_32'],
2309diff --git a/glib/glib-private.h b/glib/glib-private.h
2310index 943252f..f02828f 100644
2311--- a/glib/glib-private.h
2312+++ b/glib/glib-private.h
2313@@ -201,4 +201,22 @@ GLibPrivateVTable *glib__private__ (void);
2314 # define GLIB_DEFAULT_LOCALE ""
2315 #endif
2316
2317+/* Backported from GLib 2.78.x, where it is public API in gstrfuncs.h */
2318+static inline gboolean
2319+g_set_str (char       **str_pointer,
2320+           const char  *new_str)
2321+{
2322+  char *copy;
2323+
2324+  if (*str_pointer == new_str ||
2325+      (*str_pointer && new_str && strcmp (*str_pointer, new_str) == 0))
2326+    return FALSE;
2327+
2328+  copy = g_strdup (new_str);
2329+  g_free (*str_pointer);
2330+  *str_pointer = copy;
2331+
2332+  return TRUE;
2333+}
2334+
2335 #endif /* __GLIB_PRIVATE_H__ */
2336
2337