diff options
author | Simon McVittie <smcv@collabora.com> | 2017-06-23 12:54:34 +0100 |
---|---|---|
committer | Simon McVittie <smcv@collabora.com> | 2017-12-11 16:03:21 +0000 |
commit | ee56dde7ea9d2243a33d3c7d1871d6fa493fc8e3 (patch) | |
tree | f124f760360e720223d32143994a95d1b70593b5 | |
parent | ec7f7f1755bcac6f33726d6a021cd08c3d441c72 (diff) |
bus/containers: Emit InstanceRemoved signal
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
-rw-r--r-- | bus/containers.c | 73 | ||||
-rw-r--r-- | bus/driver.c | 5 |
2 files changed, 77 insertions, 1 deletions
diff --git a/bus/containers.c b/bus/containers.c index eb2b89c6..aea9f78b 100644 --- a/bus/containers.c +++ b/bus/containers.c @@ -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); diff --git a/bus/driver.c b/bus/driver.c index bcf38d05..feac80ad 100644 --- a/bus/driver.c +++ b/bus/driver.c @@ -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, |