From 1a163e765c0d6a86d2aa2ffb18a1d7e29a052e7a Mon Sep 17 00:00:00 2001 From: "John (J5) Palmieri" Date: Tue, 22 Nov 2005 20:37:00 +0000 Subject: * configure.in: Add test/name-test/Makefile to the generated Makefile list * dbus/dbus-shared.h (#define DBUS_NAME_FLAG_ALLOW_REPLACEMENT): New flag which replaces DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT (#define DBUS_NAME_FLAG_DO_NOT_QUEUE): New flag for specifying not to queue an ower if it can't be the primary owner * bus/bus.h: Add new internal BusOwner struct * bus/driver.c (bus_driver_handle_hello): Send flags (0 for default) to bus_registry_ensure and don't set the prohibit_replacement flag since they are now set per BusOwner and not per name. (bus_driver_handle_list_queued_owners): bus method (ListQueuedOwners) that returns the list of connections in a name's connection queue * bus/services.c (struct BusService): remove prohibit_replacement field (struct BusOwner): new struct for keeping track of queued connections and their associated flags for the queue (struct BusRegistry): add a BusOwner memory pool (bus_registry_new): initialize the BusOwner memory pool (bus_registry_unref): free the BusOwner memory pool (_bus_service_find_owner_link): new internal method for searching the queue for a specific connection (bus_owner_set_flags): new method for adding setting the flags on a bus owner (bus_owner_new): new method that creates a BusOwner object from the pool and sets its flags (bus_owner_ref, bus_owner_unref): ref counting for BusOwner objects (bus_registry_ensure): Add the flags parameter (bus_registry_acquire_service): Switch from using raw connections to using the BusOwner struct Add new state machine for dealing with the new set of flags (bus_registry_set_service_context_table, struct OwnershipCancelData, cancel_ownership, free_ownership_cancel_data, add_cancel_ownership_to_transaction, struct OwnershipRestoreData, restore_ownership, free_ownership_restore_data, add_restore_ownership_to_transaction): Switch to using BusOwner instead of raw connections (bus_service_add_owner): Add flags parameter Switch to using BusOwner instead of raw connections Add state machine for dealing with the new set of flags (bus_service_swap_owner): Swaps the first and second owners in the queue. Used to make sure proper signals are sent when a service looses or gains primary ownership. We never insert an owner at the top of the queue. Instead we insert it in the second position and then swap. (bus_service_remove_owner): Remove the owner from the queue sending out the NameLost and NameOwnerChanged signals if the we were the primary owner (bus_service_get_primary_owners_connection): New method that extracts the connection from the primary owner (bus_service_get_primary_owner): Returns the BusOwner instead of the connection (bus_service_get_allow_replacement): Changed from the old bus_service_get_prohibit_replacement method. Checks the flags of the primary owner and returns if it can be replaced or not (bus_service_set_prohibit_replacement): removed (bus_service_has_owner): returns TRUE if and owner with the specified connection exists in the queue * dbus/dbus-bus.c (dbus_bus_connection_get_unique_name): New helper method that only compiles if tests are enabled. Allows us to get the unique name of a connection so we can check it against the queue when doing regression tests * bus/activation.c (bus_activation_send_pending_auto_activate), bus/dispatch.c (bus_dispatch), bus/driver.c (bus_driver_handle_get_service_owner, bus_driver_handle_get_connection_unix_user, bus_driver_handle_get_connection_unix_process_id, bus_driver_handle_get_connection_selinux_security_context), bus/signals.c (connection_is_primary_owner): use bus_service_get_primary_owners_connection instead of bus_service_get_primary_owner * dbus/dbus-sysdeps.c (_dbus_connect_unix_socket, _dbus_listen_unix_socket): Calculate the length of the socket path and use that instead of using a fixed length which was causing socket names to contain many trailing Nul bytes. * dbus/dbus-glib-lowlevel.h, glib/dbus-gobject.c (dbus_g_method_get_sender): New method for extracting the sender from a DBusGMethodInvocation (dbus_g_method_return_get_reply): changed name to dbus_g_method_get_reply (dbus_g_method_return_send_reply): changed name to dbus_g_method_send reply * doc/dbus-specification.xml: New docs that describe how the new queueing system works and talks about the changes to the how we specify socket names * glib/examples/example-service.c, glib/examples/example-signal-emitter.c, glib/examples/statemachine/statemachine-server.c: Changed the RequestName flags to the new system * test/name-test/ (test-names.c, run-test.sh, Makefile.am): New regression test suite for testing various states of the new queueing system --- bus/services.c | 538 ++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 439 insertions(+), 99 deletions(-) (limited to 'bus/services.c') diff --git a/bus/services.c b/bus/services.c index 87feab2f..52f522b4 100644 --- a/bus/services.c +++ b/bus/services.c @@ -42,8 +42,17 @@ struct BusService BusRegistry *registry; char *name; DBusList *owners; - - unsigned int prohibit_replacement : 1; +}; + +struct BusOwner +{ + int refcount; + + BusService *service; + DBusConnection *conn; + + unsigned int allow_replacement : 1; + unsigned int do_not_queue : 1; }; struct BusRegistry @@ -54,6 +63,7 @@ struct BusRegistry DBusHashTable *service_hash; DBusMemPool *service_pool; + DBusMemPool *owner_pool; DBusHashTable *service_sid_table; }; @@ -77,9 +87,16 @@ bus_registry_new (BusContext *context) registry->service_pool = _dbus_mem_pool_new (sizeof (BusService), TRUE); + if (registry->service_pool == NULL) goto failed; + registry->owner_pool = _dbus_mem_pool_new (sizeof (BusOwner), + TRUE); + + if (registry->owner_pool == NULL) + goto failed; + registry->service_sid_table = NULL; return registry; @@ -110,6 +127,8 @@ bus_registry_unref (BusRegistry *registry) _dbus_hash_table_unref (registry->service_hash); if (registry->service_pool) _dbus_mem_pool_free (registry->service_pool); + if (registry->owner_pool) + _dbus_mem_pool_free (registry->owner_pool); if (registry->service_sid_table) _dbus_hash_table_unref (registry->service_sid_table); @@ -129,10 +148,98 @@ bus_registry_lookup (BusRegistry *registry, return service; } +static DBusList * +_bus_service_find_owner_link (BusService *service, + DBusConnection *connection) +{ + DBusList *link; + + link = _dbus_list_get_first_link (&service->owners); + + while (link != NULL) + { + BusOwner *bus_owner; + + bus_owner = (BusOwner *) link->data; + if (bus_owner->conn == connection) + break; + + link = _dbus_list_get_next_link (&service->owners, link); + } + + return link; +} + +static void +bus_owner_set_flags (BusOwner *owner, + dbus_uint32_t flags) +{ + owner->allow_replacement = + (flags & DBUS_NAME_FLAG_ALLOW_REPLACEMENT) != FALSE; + + owner->do_not_queue = + (flags & DBUS_NAME_FLAG_DO_NOT_QUEUE) != FALSE; +} + +static BusOwner * +bus_owner_new (BusService *service, + DBusConnection *conn, + dbus_uint32_t flags) +{ + BusOwner *result; + + result = _dbus_mem_pool_alloc (service->registry->owner_pool); + if (result != NULL) + { + result->refcount = 1; + /* don't ref the connection because we don't want + to block the connection from going away. + transactions take care of reffing the connection + but we need to use refcounting on the owner + so that the owner does not get freed before + we can deref the connection in the transaction + */ + result->conn = conn; + result->service = service; + + if (!bus_connection_add_owned_service (conn, service)) + { + _dbus_mem_pool_dealloc (service->registry->owner_pool, result); + return NULL; + } + + bus_owner_set_flags (result, flags); + } + return result; +} + +static BusOwner * +bus_owner_ref (BusOwner *owner) +{ + _dbus_assert (owner->refcount > 0); + owner->refcount += 1; + + return owner; +} + +static void +bus_owner_unref (BusOwner *owner) +{ + _dbus_assert (owner->refcount > 0); + owner->refcount -= 1; + + if (owner->refcount == 0) + { + bus_connection_remove_owned_service (owner->conn, owner->service); + _dbus_mem_pool_dealloc (owner->service->registry->owner_pool, owner); + } +} + BusService* bus_registry_ensure (BusRegistry *registry, const DBusString *service_name, - DBusConnection *owner_if_created, + DBusConnection *owner_connection_if_created, + dbus_uint32_t flags, BusTransaction *transaction, DBusError *error) { @@ -140,7 +247,7 @@ bus_registry_ensure (BusRegistry *registry, _DBUS_ASSERT_ERROR_IS_CLEAR (error); - _dbus_assert (owner_if_created != NULL); + _dbus_assert (owner_connection_if_created != NULL); _dbus_assert (transaction != NULL); service = _dbus_hash_table_lookup_string (registry->service_hash, @@ -172,7 +279,7 @@ bus_registry_ensure (BusRegistry *registry, if (!bus_driver_send_service_owner_changed (service->name, NULL, - bus_connection_get_name (owner_if_created), + bus_connection_get_name (owner_connection_if_created), transaction, error)) { bus_service_unref (service); @@ -186,8 +293,8 @@ bus_registry_ensure (BusRegistry *registry, return NULL; } - if (!bus_service_add_owner (service, owner_if_created, - transaction, error)) + if (!bus_service_add_owner (service, owner_connection_if_created, flags, + transaction, error)) { bus_service_unref (service); return NULL; @@ -275,13 +382,14 @@ bus_registry_acquire_service (BusRegistry *registry, DBusError *error) { dbus_bool_t retval; - DBusConnection *old_owner; - DBusConnection *current_owner; + DBusConnection *old_owner_conn; + DBusConnection *current_owner_conn; BusClientPolicy *policy; BusService *service; BusActivation *activation; BusSELinuxID *sid; - + BusOwner *primary_owner; + retval = FALSE; if (!_dbus_validate_bus_name (service_name, 0, @@ -366,37 +474,70 @@ bus_registry_acquire_service (BusRegistry *registry, service = bus_registry_lookup (registry, service_name); if (service != NULL) - old_owner = bus_service_get_primary_owner (service); + { + primary_owner = bus_service_get_primary_owner (service); + if (primary_owner != NULL) + old_owner_conn = primary_owner->conn; + else + old_owner_conn = NULL; + } else - old_owner = NULL; + old_owner_conn = NULL; if (service == NULL) { service = bus_registry_ensure (registry, - service_name, connection, transaction, error); + service_name, connection, flags, + transaction, error); if (service == NULL) goto out; } - current_owner = bus_service_get_primary_owner (service); - - if (old_owner == NULL) + primary_owner = bus_service_get_primary_owner (service); + if (primary_owner == NULL) + goto out; + + current_owner_conn = primary_owner->conn; + + if (old_owner_conn == NULL) { - _dbus_assert (current_owner == connection); + _dbus_assert (current_owner_conn == connection); - bus_service_set_prohibit_replacement (service, - (flags & DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT)); - *result = DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER; } - else if (old_owner == connection) - *result = DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER; - else if (!((flags & DBUS_NAME_FLAG_REPLACE_EXISTING))) - *result = DBUS_REQUEST_NAME_REPLY_EXISTS; - else if (bus_service_get_prohibit_replacement (service)) + else if (old_owner_conn == connection) + { + bus_owner_set_flags (primary_owner, flags); + *result = DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER; + } + else if (((flags & DBUS_NAME_FLAG_DO_NOT_QUEUE) && + !(bus_service_get_allow_replacement (service))) || + ((flags & DBUS_NAME_FLAG_DO_NOT_QUEUE) && + !(flags & DBUS_NAME_FLAG_REPLACE_EXISTING))) + { + DBusList *link; + BusOwner *temp_owner; + /* Since we can't be queued if we are already in the queue + remove us */ + + link = _bus_service_find_owner_link (service, connection); + if (link != NULL) + { + _dbus_list_unlink (&service->owners, link); + temp_owner = (BusOwner *)link->data; + bus_owner_unref (temp_owner); + _dbus_list_free_link (link); + } + + *result = DBUS_REQUEST_NAME_REPLY_EXISTS; + } + else if (!(flags & DBUS_NAME_FLAG_DO_NOT_QUEUE) && + (!(flags & DBUS_NAME_FLAG_REPLACE_EXISTING) || + !(bus_service_get_allow_replacement (service)))) { /* Queue the connection */ - if (!bus_service_add_owner (service, connection, + if (!bus_service_add_owner (service, connection, + flags, transaction, error)) goto out; @@ -412,14 +553,25 @@ bus_registry_acquire_service (BusRegistry *registry, */ if (!bus_service_add_owner (service, connection, + flags, transaction, error)) goto out; - if (!bus_service_remove_owner (service, old_owner, - transaction, error)) - goto out; - - _dbus_assert (connection == bus_service_get_primary_owner (service)); + if (primary_owner->do_not_queue) + { + if (!bus_service_remove_owner (service, old_owner_conn, + transaction, error)) + goto out; + } + else + { + if (!bus_service_swap_owner (service, old_owner_conn, + transaction, error)) + goto out; + } + + + _dbus_assert (connection == bus_service_get_primary_owner (service)->conn); *result = DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER; } @@ -528,10 +680,10 @@ bus_registry_set_service_context_table (BusRegistry *registry, static void bus_service_unlink_owner (BusService *service, - DBusConnection *owner) + BusOwner *owner) { _dbus_list_remove_last (&service->owners, owner); - bus_connection_remove_owned_service (owner, service); + bus_owner_unref (owner); } static void @@ -570,7 +722,7 @@ bus_service_relink (BusService *service, */ typedef struct { - DBusConnection *connection; /**< the connection */ + BusOwner *owner; /**< the owner */ BusService *service; /**< service to cancel ownership of */ } OwnershipCancelData; @@ -583,7 +735,7 @@ cancel_ownership (void *data) * changes, since we're reverting something that was * cancelled (effectively never really happened) */ - bus_service_unlink_owner (d->service, d->connection); + bus_service_unlink_owner (d->service, d->owner); if (d->service->owners == NULL) bus_service_unlink (d->service); @@ -594,7 +746,8 @@ free_ownership_cancel_data (void *data) { OwnershipCancelData *d = data; - dbus_connection_unref (d->connection); + dbus_connection_unref (d->owner->conn); + bus_owner_unref (d->owner); bus_service_unref (d->service); dbus_free (d); @@ -603,7 +756,7 @@ free_ownership_cancel_data (void *data) static dbus_bool_t add_cancel_ownership_to_transaction (BusTransaction *transaction, BusService *service, - DBusConnection *connection) + BusOwner *owner) { OwnershipCancelData *d; @@ -612,7 +765,7 @@ add_cancel_ownership_to_transaction (BusTransaction *transaction, return FALSE; d->service = service; - d->connection = connection; + d->owner = owner; if (!bus_transaction_add_cancel_hook (transaction, cancel_ownership, d, free_ownership_cancel_data)) @@ -622,18 +775,23 @@ add_cancel_ownership_to_transaction (BusTransaction *transaction, } bus_service_ref (d->service); - dbus_connection_ref (d->connection); - + bus_owner_ref (owner); + dbus_connection_ref (d->owner->conn); + return TRUE; } /* this function is self-cancelling if you cancel the transaction */ dbus_bool_t bus_service_add_owner (BusService *service, - DBusConnection *owner, + DBusConnection *connection, + dbus_uint32_t flags, BusTransaction *transaction, DBusError *error) { + BusOwner *bus_owner; + DBusList *bus_owner_link; + _DBUS_ASSERT_ERROR_IS_CLEAR (error); /* Send service acquired message first, OOM will result @@ -641,42 +799,83 @@ bus_service_add_owner (BusService *service, */ if (service->owners == NULL) { - if (!bus_driver_send_service_acquired (owner, service->name, transaction, error)) + if (!bus_driver_send_service_acquired (connection, service->name, transaction, error)) return FALSE; } - if (!_dbus_list_append (&service->owners, - owner)) + bus_owner_link = _bus_service_find_owner_link (service, connection); + + if (bus_owner_link == NULL) { - BUS_SET_OOM (error); - return FALSE; - } + bus_owner = bus_owner_new (service, connection, flags); + if (bus_owner == NULL) + { + BUS_SET_OOM (error); + return FALSE; + } - if (!bus_connection_add_owned_service (owner, service)) + bus_owner_set_flags (bus_owner, flags); + if (!(flags & DBUS_NAME_FLAG_REPLACE_EXISTING) || service->owners == NULL) + { + if (!_dbus_list_append (&service->owners, + bus_owner)) + { + bus_owner_unref (bus_owner); + BUS_SET_OOM (error); + return FALSE; + } + } + else + { + if (!_dbus_list_insert_after (&service->owners, + _dbus_list_get_first_link (&service->owners), + bus_owner)) + { + bus_owner_unref (bus_owner); + BUS_SET_OOM (error); + return FALSE; + } + } + } + else { - _dbus_list_remove_last (&service->owners, owner); - BUS_SET_OOM (error); - return FALSE; + /* Update the link since we are already in the queue + * No need for operations that can produce OOM + */ + + bus_owner = (BusOwner *) bus_owner_link->data; + if (flags & DBUS_NAME_FLAG_REPLACE_EXISTING) + { + DBusList *link; + _dbus_list_unlink (&service->owners, bus_owner_link); + link = _dbus_list_get_first_link (&service->owners); + _dbus_assert (link != NULL); + + _dbus_list_insert_after_link (&service->owners, link, bus_owner_link); + } + + bus_owner_set_flags (bus_owner, flags); + return TRUE; } if (!add_cancel_ownership_to_transaction (transaction, service, - owner)) + bus_owner)) { - bus_service_unlink_owner (service, owner); + bus_service_unlink_owner (service, bus_owner); BUS_SET_OOM (error); return FALSE; } - + return TRUE; } typedef struct { - DBusConnection *connection; + BusOwner *owner; BusService *service; - DBusConnection *before_connection; /* restore to position before this connection in owners list */ - DBusList *connection_link; + BusOwner *before_owner; /* restore to position before this connection in owners list */ + DBusList *owner_link; DBusList *service_link; DBusPreallocatedHash *hash_entry; } OwnershipRestoreData; @@ -688,7 +887,7 @@ restore_ownership (void *data) DBusList *link; _dbus_assert (d->service_link != NULL); - _dbus_assert (d->connection_link != NULL); + _dbus_assert (d->owner_link != NULL); if (d->service->owners == NULL) { @@ -707,13 +906,13 @@ restore_ownership (void *data) link = _dbus_list_get_first_link (&d->service->owners); while (link != NULL) { - if (link->data == d->before_connection) + if (link->data == d->before_owner) break; link = _dbus_list_get_next_link (&d->service->owners, link); } - _dbus_list_insert_before_link (&d->service->owners, link, d->connection_link); + _dbus_list_insert_before_link (&d->service->owners, link, d->owner_link); /* Note that removing then restoring this changes the order in which * ServiceDeleted messages are sent on destruction of the @@ -721,11 +920,11 @@ restore_ownership (void *data) * that the base service is destroyed last, and we never even * tentatively remove the base service. */ - bus_connection_add_owned_service_link (d->connection, d->service_link); + bus_connection_add_owned_service_link (d->owner->conn, d->service_link); d->hash_entry = NULL; d->service_link = NULL; - d->connection_link = NULL; + d->owner_link = NULL; } static void @@ -735,13 +934,14 @@ free_ownership_restore_data (void *data) if (d->service_link) _dbus_list_free_link (d->service_link); - if (d->connection_link) - _dbus_list_free_link (d->connection_link); + if (d->owner_link) + _dbus_list_free_link (d->owner_link); if (d->hash_entry) _dbus_hash_table_free_preallocated_entry (d->service->registry->service_hash, d->hash_entry); - dbus_connection_unref (d->connection); + dbus_connection_unref (d->owner->conn); + bus_owner_unref (d->owner); bus_service_unref (d->service); dbus_free (d); @@ -750,7 +950,7 @@ free_ownership_restore_data (void *data) static dbus_bool_t add_restore_ownership_to_transaction (BusTransaction *transaction, BusService *service, - DBusConnection *connection) + BusOwner *owner) { OwnershipRestoreData *d; DBusList *link; @@ -760,24 +960,25 @@ add_restore_ownership_to_transaction (BusTransaction *transaction, return FALSE; d->service = service; - d->connection = connection; + d->owner = owner; d->service_link = _dbus_list_alloc_link (service); - d->connection_link = _dbus_list_alloc_link (connection); + d->owner_link = _dbus_list_alloc_link (owner); d->hash_entry = _dbus_hash_table_preallocate_entry (service->registry->service_hash); bus_service_ref (d->service); - dbus_connection_ref (d->connection); + bus_owner_ref (d->owner); + dbus_connection_ref (d->owner->conn); - d->before_connection = NULL; + d->before_owner = NULL; link = _dbus_list_get_first_link (&service->owners); while (link != NULL) { - if (link->data == connection) + if (link->data == owner) { link = _dbus_list_get_next_link (&service->owners, link); if (link) - d->before_connection = link->data; + d->before_owner = link->data; break; } @@ -786,7 +987,7 @@ add_restore_ownership_to_transaction (BusTransaction *transaction, } if (d->service_link == NULL || - d->connection_link == NULL || + d->owner_link == NULL || d->hash_entry == NULL || !bus_transaction_add_cancel_hook (transaction, restore_ownership, d, free_ownership_restore_data)) @@ -798,13 +999,92 @@ add_restore_ownership_to_transaction (BusTransaction *transaction, return TRUE; } +dbus_bool_t +bus_service_swap_owner (BusService *service, + DBusConnection *connection, + BusTransaction *transaction, + DBusError *error) +{ + DBusList *swap_link; + BusOwner *primary_owner; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + /* We send out notifications before we do any work we + * might have to undo if the notification-sending failed + */ + + /* Send service lost message */ + primary_owner = bus_service_get_primary_owner (service); + if (primary_owner == NULL || primary_owner->conn != connection) + _dbus_assert_not_reached ("Tried to swap a non primary owner"); + + + if (!bus_driver_send_service_lost (connection, service->name, + transaction, error)) + return FALSE; + + if (service->owners == NULL) + { + _dbus_assert_not_reached ("Tried to swap owner of a service that has no owners"); + } + else if (_dbus_list_length_is_one (&service->owners)) + { + _dbus_assert_not_reached ("Tried to swap owner of a service that has no other owners in the queue"); + } + else + { + DBusList *link; + BusOwner *new_owner; + DBusConnection *new_owner_conn; + link = _dbus_list_get_first_link (&service->owners); + _dbus_assert (link != NULL); + link = _dbus_list_get_next_link (&service->owners, link); + _dbus_assert (link != NULL); + + new_owner = (BusOwner *)link->data; + new_owner_conn = new_owner->conn; + + if (!bus_driver_send_service_owner_changed (service->name, + bus_connection_get_name (connection), + bus_connection_get_name (new_owner_conn), + transaction, error)) + return FALSE; + + /* This will be our new owner */ + if (!bus_driver_send_service_acquired (new_owner_conn, + service->name, + transaction, + error)) + return FALSE; + } + + if (!add_restore_ownership_to_transaction (transaction, service, primary_owner)) + { + BUS_SET_OOM (error); + return FALSE; + } + + /* unlink the primary and make it the second link */ + swap_link = _dbus_list_get_first_link (&service->owners); + _dbus_list_unlink (&service->owners, swap_link); + + _dbus_list_insert_after_link (&service->owners, + _dbus_list_get_first_link (&service->owners), + swap_link); + + return TRUE; +} + /* this function is self-cancelling if you cancel the transaction */ dbus_bool_t bus_service_remove_owner (BusService *service, - DBusConnection *owner, + DBusConnection *connection, BusTransaction *transaction, DBusError *error) { + BusOwner *primary_owner; + _DBUS_ASSERT_ERROR_IS_CLEAR (error); /* We send out notifications before we do any work we @@ -812,12 +1092,27 @@ bus_service_remove_owner (BusService *service, */ /* Send service lost message */ - if (bus_service_get_primary_owner (service) == owner) + primary_owner = bus_service_get_primary_owner (service); + if (primary_owner != NULL && primary_owner->conn == connection) { - if (!bus_driver_send_service_lost (owner, service->name, + if (!bus_driver_send_service_lost (connection, service->name, transaction, error)) return FALSE; } + else + { + /* if we are not the primary owner then just remove us from the queue */ + DBusList *link; + BusOwner *temp_owner; + + link = _bus_service_find_owner_link (service, connection); + _dbus_list_unlink (&service->owners, link); + temp_owner = (BusOwner *)link->data; + bus_owner_unref (temp_owner); + _dbus_list_free_link (link); + + return TRUE; + } if (service->owners == NULL) { @@ -826,7 +1121,7 @@ bus_service_remove_owner (BusService *service, else if (_dbus_list_length_is_one (&service->owners)) { if (!bus_driver_send_service_owner_changed (service->name, - bus_connection_get_name (owner), + bus_connection_get_name (connection), NULL, transaction, error)) return FALSE; @@ -834,35 +1129,37 @@ bus_service_remove_owner (BusService *service, else { DBusList *link; - DBusConnection *new_owner; + BusOwner *new_owner; + DBusConnection *new_owner_conn; link = _dbus_list_get_first_link (&service->owners); _dbus_assert (link != NULL); link = _dbus_list_get_next_link (&service->owners, link); _dbus_assert (link != NULL); - new_owner = link->data; + new_owner = (BusOwner *)link->data; + new_owner_conn = new_owner->conn; if (!bus_driver_send_service_owner_changed (service->name, - bus_connection_get_name (owner), - bus_connection_get_name (new_owner), + bus_connection_get_name (connection), + bus_connection_get_name (new_owner_conn), transaction, error)) return FALSE; /* This will be our new owner */ - if (!bus_driver_send_service_acquired (new_owner, + if (!bus_driver_send_service_acquired (new_owner_conn, service->name, transaction, error)) return FALSE; } - if (!add_restore_ownership_to_transaction (transaction, service, owner)) + if (!add_restore_ownership_to_transaction (transaction, service, primary_owner)) { BUS_SET_OOM (error); return FALSE; } - - bus_service_unlink_owner (service, owner); + + bus_service_unlink_owner (service, primary_owner); if (service->owners == NULL) bus_service_unlink (service); @@ -896,7 +1193,20 @@ bus_service_unref (BusService *service) } } -DBusConnection* +DBusConnection * +bus_service_get_primary_owners_connection (BusService *service) +{ + BusOwner *owner; + + owner = bus_service_get_primary_owner (service); + + if (owner != NULL) + return owner->conn; + else + return NULL; +} + +BusOwner* bus_service_get_primary_owner (BusService *service) { return _dbus_list_get_first (&service->owners); @@ -908,34 +1218,64 @@ bus_service_get_name (BusService *service) return service->name; } -void -bus_service_set_prohibit_replacement (BusService *service, - dbus_bool_t prohibit_replacement) +dbus_bool_t +bus_service_get_allow_replacement (BusService *service) { - service->prohibit_replacement = prohibit_replacement != FALSE; + BusOwner *owner; + DBusList *link; + + _dbus_assert (service->owners != NULL); + + link = _dbus_list_get_first_link (&service->owners); + owner = (BusOwner *) link->data; + + return owner->allow_replacement; } dbus_bool_t -bus_service_get_prohibit_replacement (BusService *service) +bus_service_has_owner (BusService *service, + DBusConnection *connection) { - return service->prohibit_replacement; + DBusList *link; + + link = _bus_service_find_owner_link (service, connection); + + if (link == NULL) + return FALSE; + else + return TRUE; } -dbus_bool_t -bus_service_has_owner (BusService *service, - DBusConnection *owner) +dbus_bool_t +bus_service_list_queued_owners (BusService *service, + DBusList **return_list, + DBusError *error) { DBusList *link; + _dbus_assert (*return_list == NULL); + link = _dbus_list_get_first_link (&service->owners); + _dbus_assert (link != NULL); while (link != NULL) { - if (link->data == owner) - return TRUE; - + BusOwner *owner; + const char *uname; + + owner = (BusOwner *) link->data; + uname = bus_connection_get_name (owner->conn); + + if (!_dbus_list_append (return_list, uname)) + goto oom; + link = _dbus_list_get_next_link (&service->owners, link); } - + + return TRUE; + + oom: + _dbus_list_clear (return_list); + BUS_SET_OOM (error); return FALSE; } -- cgit