]> git.ipfire.org Git - thirdparty/dbus.git/commitdiff
bus/containers: Emit InstanceRemoved signal
authorSimon McVittie <smcv@collabora.com>
Fri, 23 Jun 2017 11:54:34 +0000 (12:54 +0100)
committerSimon McVittie <smcv@collabora.com>
Tue, 12 Dec 2017 16:22:34 +0000 (16:22 +0000)
Signed-off-by: Simon McVittie <smcv@collabora.com>
Reviewed-by: Philip Withnall <withnall@endlessm.com>
Bug: https://bugs.freedesktop.org/show_bug.cgi?id=101354

bus/containers.c
bus/driver.c

index eb2b89c6d812561911c6d749338e781018e9e215..aea9f78bdcbfe5cc6018ee9a6d644ee89fec1482 100644 (file)
@@ -38,6 +38,7 @@
 #include "dbus/dbus-sysdeps-unix.h"
 
 #include "connection.h"
+#include "dispatch.h"
 #include "driver.h"
 #include "utils.h"
 
@@ -60,6 +61,7 @@ typedef struct
    * removed from the bus */
   DBusList *connections;
   unsigned long uid;
+  unsigned announced:1;
 } BusContainerInstance;
 
 /* Data attached to a DBusConnection that has created container instances. */
@@ -209,6 +211,61 @@ bus_container_instance_ref (BusContainerInstance *self)
   return self;
 }
 
+static dbus_bool_t
+bus_container_instance_emit_removed (BusContainerInstance *self)
+{
+  BusTransaction *transaction = NULL;
+  DBusMessage *message = NULL;
+  DBusError error = DBUS_ERROR_INIT;
+
+  transaction = bus_transaction_new (self->context);
+
+  if (transaction == NULL)
+    goto oom;
+
+  message = dbus_message_new_signal (DBUS_PATH_DBUS,
+                                     DBUS_INTERFACE_CONTAINERS1,
+                                     "InstanceRemoved");
+
+  if (message == NULL ||
+      !dbus_message_set_sender (message, DBUS_SERVICE_DBUS) ||
+      !dbus_message_append_args (message,
+                                 DBUS_TYPE_OBJECT_PATH, &self->path,
+                                 DBUS_TYPE_INVALID) ||
+      !bus_transaction_capture (transaction, NULL, NULL, message))
+    goto oom;
+
+  if (!bus_dispatch_matches (transaction, NULL, NULL, message, &error))
+    {
+      if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
+        goto oom;
+
+      /* This can't actually happen, because all of the error cases in
+       * bus_dispatch_matches() are only if there is an addressed recipient
+       * (a unicast message), which there is not in this case. But if it
+       * somehow does happen, we don't want to stay in the OOM-retry loop,
+       * because waiting for more memory will not help; so continue to
+       * execute the transaction anyway. */
+      _dbus_warn ("Failed to send InstanceRemoved for a reason "
+                  "other than OOM: %s: %s", error.name, error.message);
+      dbus_error_free (&error);
+    }
+
+  bus_transaction_execute_and_free (transaction);
+  dbus_message_unref (message);
+  _DBUS_ASSERT_ERROR_IS_CLEAR (&error);
+  return TRUE;
+
+oom:
+  dbus_error_free (&error);
+  dbus_clear_message (&message);
+
+  if (transaction != NULL)
+    bus_transaction_cancel_and_free (transaction);
+
+  return FALSE;
+}
+
 static void
 bus_container_instance_unref (BusContainerInstance *self)
 {
@@ -218,6 +275,21 @@ bus_container_instance_unref (BusContainerInstance *self)
     {
       BusContainerCreatorData *creator_data;
 
+      /* If we announced the container instance in a reply from
+       * AddServer() (which is also the time at which it becomes
+       * available for the querying methods), then we have to emit
+       * InstanceRemoved for it.
+       *
+       * Similar to bus/connection.c dropping well-known name ownership,
+       * this isn't really a situation where we can "fail", because
+       * this last-unref is likely to be happening as a result of a
+       * connection disconnecting; so we use a retry loop on OOM. */
+      for (; self->announced; _dbus_wait_for_memory ())
+        {
+          if (bus_container_instance_emit_removed (self))
+            self->announced = FALSE;
+        }
+
       /* As long as the server is listening, the BusContainerInstance can't
        * be freed, because the DBusServer holds a reference to the
        * BusContainerInstance */
@@ -754,6 +826,7 @@ bus_containers_handle_add_server (DBusConnection *connection,
   if (! bus_transaction_send_from_driver (transaction, connection, reply))
     goto oom;
 
+  instance->announced = TRUE;
   dbus_message_unref (reply);
   bus_container_instance_unref (instance);
   dbus_address_entries_free (entries);
index bcf38d05cb10c58a250a70991264211d13441d7d..feac80ad8539646bf9826f00a8edf9c28aa9f309 100644 (file)
@@ -2639,7 +2639,10 @@ static InterfaceHandler interface_handlers[] = {
     INTERFACE_FLAG_NONE },
 #endif
 #ifdef DBUS_ENABLE_CONTAINERS
-  { DBUS_INTERFACE_CONTAINERS1, containers_message_handlers, NULL,
+  { DBUS_INTERFACE_CONTAINERS1, containers_message_handlers,
+    "    <signal name=\"InstanceRemoved\">\n"
+    "      <arg type=\"o\" name=\"path\"/>\n"
+    "    </signal>\n",
     INTERFACE_FLAG_NONE, containers_property_handlers },
 #endif
   { DBUS_INTERFACE_PEER, peer_message_handlers, NULL,