diff options
Diffstat (limited to 'src/3rd_party/dbus-1.7.8/bus/services.c')
-rw-r--r-- | src/3rd_party/dbus-1.7.8/bus/services.c | 1304 |
1 files changed, 0 insertions, 1304 deletions
diff --git a/src/3rd_party/dbus-1.7.8/bus/services.c b/src/3rd_party/dbus-1.7.8/bus/services.c deleted file mode 100644 index 6f380fac7d..0000000000 --- a/src/3rd_party/dbus-1.7.8/bus/services.c +++ /dev/null @@ -1,1304 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ -/* services.c Service management - * - * Copyright (C) 2003 Red Hat, Inc. - * Copyright (C) 2003 CodeFactory AB - * - * Licensed under the Academic Free License version 2.1 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#include <config.h> -#include <dbus/dbus-hash.h> -#include <dbus/dbus-list.h> -#include <dbus/dbus-mempool.h> -#include <dbus/dbus-marshal-validate.h> - -#include "driver.h" -#include "services.h" -#include "connection.h" -#include "utils.h" -#include "activation.h" -#include "policy.h" -#include "bus.h" -#include "selinux.h" - -struct BusService -{ - int refcount; - - BusRegistry *registry; - char *name; - DBusList *owners; -}; - -struct BusOwner -{ - int refcount; - - BusService *service; - DBusConnection *conn; - - unsigned int allow_replacement : 1; - unsigned int do_not_queue : 1; -}; - -struct BusRegistry -{ - int refcount; - - BusContext *context; - - DBusHashTable *service_hash; - DBusMemPool *service_pool; - DBusMemPool *owner_pool; - - DBusHashTable *service_sid_table; -}; - -BusRegistry* -bus_registry_new (BusContext *context) -{ - BusRegistry *registry; - - registry = dbus_new0 (BusRegistry, 1); - if (registry == NULL) - return NULL; - - registry->refcount = 1; - registry->context = context; - - registry->service_hash = _dbus_hash_table_new (DBUS_HASH_STRING, - NULL, NULL); - if (registry->service_hash == NULL) - goto failed; - - 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; - - failed: - bus_registry_unref (registry); - return NULL; -} - -BusRegistry * -bus_registry_ref (BusRegistry *registry) -{ - _dbus_assert (registry->refcount > 0); - registry->refcount += 1; - - return registry; -} - -void -bus_registry_unref (BusRegistry *registry) -{ - _dbus_assert (registry->refcount > 0); - registry->refcount -= 1; - - if (registry->refcount == 0) - { - if (registry->service_hash) - _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); - - dbus_free (registry); - } -} - -BusService* -bus_registry_lookup (BusRegistry *registry, - const DBusString *service_name) -{ - BusService *service; - - service = _dbus_hash_table_lookup_string (registry->service_hash, - _dbus_string_get_const_data (service_name)); - - 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_connection_if_created, - dbus_uint32_t flags, - BusTransaction *transaction, - DBusError *error) -{ - BusService *service; - - _DBUS_ASSERT_ERROR_IS_CLEAR (error); - - _dbus_assert (owner_connection_if_created != NULL); - _dbus_assert (transaction != NULL); - - service = _dbus_hash_table_lookup_string (registry->service_hash, - _dbus_string_get_const_data (service_name)); - if (service != NULL) - return service; - - service = _dbus_mem_pool_alloc (registry->service_pool); - if (service == NULL) - { - BUS_SET_OOM (error); - return NULL; - } - - service->registry = registry; - service->refcount = 1; - - _dbus_verbose ("copying string %p '%s' to service->name\n", - service_name, _dbus_string_get_const_data (service_name)); - if (!_dbus_string_copy_data (service_name, &service->name)) - { - _dbus_mem_pool_dealloc (registry->service_pool, service); - BUS_SET_OOM (error); - return NULL; - } - _dbus_verbose ("copied string %p '%s' to '%s'\n", - service_name, _dbus_string_get_const_data (service_name), - service->name); - - if (!bus_driver_send_service_owner_changed (service->name, - NULL, - bus_connection_get_name (owner_connection_if_created), - transaction, error)) - { - bus_service_unref (service); - return NULL; - } - - if (!bus_activation_service_created (bus_context_get_activation (registry->context), - service->name, transaction, error)) - { - bus_service_unref (service); - return NULL; - } - - if (!bus_service_add_owner (service, owner_connection_if_created, flags, - transaction, error)) - { - bus_service_unref (service); - return NULL; - } - - if (!_dbus_hash_table_insert_string (registry->service_hash, - service->name, - service)) - { - /* The add_owner gets reverted on transaction cancel */ - BUS_SET_OOM (error); - return NULL; - } - - return service; -} - -void -bus_registry_foreach (BusRegistry *registry, - BusServiceForeachFunction function, - void *data) -{ - DBusHashIter iter; - - _dbus_hash_iter_init (registry->service_hash, &iter); - while (_dbus_hash_iter_next (&iter)) - { - BusService *service = _dbus_hash_iter_get_value (&iter); - - (* function) (service, data); - } -} - -dbus_bool_t -bus_registry_list_services (BusRegistry *registry, - char ***listp, - int *array_len) -{ - int i, j, len; - char **retval; - DBusHashIter iter; - - len = _dbus_hash_table_get_n_entries (registry->service_hash); - retval = dbus_new (char *, len + 1); - - if (retval == NULL) - return FALSE; - - _dbus_hash_iter_init (registry->service_hash, &iter); - i = 0; - while (_dbus_hash_iter_next (&iter)) - { - BusService *service = _dbus_hash_iter_get_value (&iter); - - retval[i] = _dbus_strdup (service->name); - if (retval[i] == NULL) - goto error; - - i++; - } - - retval[i] = NULL; - - if (array_len) - *array_len = len; - - *listp = retval; - return TRUE; - - error: - for (j = 0; j < i; j++) - dbus_free (retval[i]); - dbus_free (retval); - - return FALSE; -} - -dbus_bool_t -bus_registry_acquire_service (BusRegistry *registry, - DBusConnection *connection, - const DBusString *service_name, - dbus_uint32_t flags, - dbus_uint32_t *result, - BusTransaction *transaction, - DBusError *error) -{ - dbus_bool_t retval; - DBusConnection *old_owner_conn; - BusClientPolicy *policy; - BusService *service; - BusActivation *activation; - BusSELinuxID *sid; - BusOwner *primary_owner; - - retval = FALSE; - - if (!_dbus_validate_bus_name (service_name, 0, - _dbus_string_get_length (service_name))) - { - dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, - "Requested bus name \"%s\" is not valid", - _dbus_string_get_const_data (service_name)); - - _dbus_verbose ("Attempt to acquire invalid service name\n"); - - goto out; - } - - if (_dbus_string_get_byte (service_name, 0) == ':') - { - /* Not allowed; only base services can start with ':' */ - dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, - "Cannot acquire a service starting with ':' such as \"%s\"", - _dbus_string_get_const_data (service_name)); - - _dbus_verbose ("Attempt to acquire invalid base service name \"%s\"", - _dbus_string_get_const_data (service_name)); - - goto out; - } - - if (_dbus_string_equal_c_str (service_name, DBUS_SERVICE_DBUS)) - { - dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, - "Connection \"%s\" is not allowed to own the service \"%s\"because " - "it is reserved for D-Bus' use only", - bus_connection_is_active (connection) ? - bus_connection_get_name (connection) : - "(inactive)", - DBUS_SERVICE_DBUS); - goto out; - } - - policy = bus_connection_get_policy (connection); - _dbus_assert (policy != NULL); - - /* Note that if sid is #NULL then the bus's own context gets used - * in bus_connection_selinux_allows_acquire_service() - */ - sid = bus_selinux_id_table_lookup (registry->service_sid_table, - service_name); - - if (!bus_selinux_allows_acquire_service (connection, sid, - _dbus_string_get_const_data (service_name), error)) - { - - if (dbus_error_is_set (error) && - dbus_error_has_name (error, DBUS_ERROR_NO_MEMORY)) - { - goto out; - } - - dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED, - "Connection \"%s\" is not allowed to own the service \"%s\" due " - "to SELinux policy", - bus_connection_is_active (connection) ? - bus_connection_get_name (connection) : - "(inactive)", - _dbus_string_get_const_data (service_name)); - goto out; - } - - if (!bus_client_policy_check_can_own (policy, service_name)) - { - dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED, - "Connection \"%s\" is not allowed to own the service \"%s\" due " - "to security policies in the configuration file", - bus_connection_is_active (connection) ? - bus_connection_get_name (connection) : - "(inactive)", - _dbus_string_get_const_data (service_name)); - goto out; - } - - if (bus_connection_get_n_services_owned (connection) >= - bus_context_get_max_services_per_connection (registry->context)) - { - dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED, - "Connection \"%s\" is not allowed to own more services " - "(increase limits in configuration file if required)", - bus_connection_is_active (connection) ? - bus_connection_get_name (connection) : - "(inactive)"); - goto out; - } - - service = bus_registry_lookup (registry, service_name); - - if (service != NULL) - { - 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_conn = NULL; - - if (service == NULL) - { - service = bus_registry_ensure (registry, - service_name, connection, flags, - transaction, error); - if (service == NULL) - goto out; - } - - primary_owner = bus_service_get_primary_owner (service); - if (primary_owner == NULL) - goto out; - - if (old_owner_conn == NULL) - { - _dbus_assert (primary_owner->conn == connection); - - *result = DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER; - } - 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, - flags, - transaction, error)) - goto out; - - *result = DBUS_REQUEST_NAME_REPLY_IN_QUEUE; - } - else - { - /* Replace the current owner */ - - /* We enqueue the new owner and remove the first one because - * that will cause NameAcquired and NameLost messages to - * be sent. - */ - - if (!bus_service_add_owner (service, connection, - flags, - transaction, error)) - goto out; - - 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; - } - - activation = bus_context_get_activation (registry->context); - retval = bus_activation_send_pending_auto_activation_messages (activation, - service, - transaction, - error); - - out: - return retval; -} - -dbus_bool_t -bus_registry_release_service (BusRegistry *registry, - DBusConnection *connection, - const DBusString *service_name, - dbus_uint32_t *result, - BusTransaction *transaction, - DBusError *error) -{ - dbus_bool_t retval; - BusService *service; - - retval = FALSE; - - if (!_dbus_validate_bus_name (service_name, 0, - _dbus_string_get_length (service_name))) - { - dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, - "Given bus name \"%s\" is not valid", - _dbus_string_get_const_data (service_name)); - - _dbus_verbose ("Attempt to release invalid service name\n"); - - goto out; - } - - if (_dbus_string_get_byte (service_name, 0) == ':') - { - /* Not allowed; the base service name cannot be created or released */ - dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, - "Cannot release a service starting with ':' such as \"%s\"", - _dbus_string_get_const_data (service_name)); - - _dbus_verbose ("Attempt to release invalid base service name \"%s\"", - _dbus_string_get_const_data (service_name)); - - goto out; - } - - if (_dbus_string_equal_c_str (service_name, DBUS_SERVICE_DBUS)) - { - /* Not allowed; the base service name cannot be created or released */ - dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, - "Cannot release the %s service because it is owned by the bus", - DBUS_SERVICE_DBUS); - - _dbus_verbose ("Attempt to release service name \"%s\"", - DBUS_SERVICE_DBUS); - - goto out; - } - - service = bus_registry_lookup (registry, service_name); - - if (service == NULL) - { - *result = DBUS_RELEASE_NAME_REPLY_NON_EXISTENT; - } - else if (!bus_service_has_owner (service, connection)) - { - *result = DBUS_RELEASE_NAME_REPLY_NOT_OWNER; - } - else - { - if (!bus_service_remove_owner (service, connection, - transaction, error)) - goto out; - - _dbus_assert (!bus_service_has_owner (service, connection)); - *result = DBUS_RELEASE_NAME_REPLY_RELEASED; - } - - retval = TRUE; - - out: - return retval; -} - -dbus_bool_t -bus_registry_set_service_context_table (BusRegistry *registry, - DBusHashTable *table) -{ - DBusHashTable *new_table; - DBusHashIter iter; - - new_table = bus_selinux_id_table_new (); - if (!new_table) - return FALSE; - - _dbus_hash_iter_init (table, &iter); - while (_dbus_hash_iter_next (&iter)) - { - const char *service = _dbus_hash_iter_get_string_key (&iter); - const char *context = _dbus_hash_iter_get_value (&iter); - - if (!bus_selinux_id_table_insert (new_table, - service, - context)) - return FALSE; - } - - if (registry->service_sid_table) - _dbus_hash_table_unref (registry->service_sid_table); - registry->service_sid_table = new_table; - return TRUE; -} - -static void -bus_service_unlink_owner (BusService *service, - BusOwner *owner) -{ - _dbus_list_remove_last (&service->owners, owner); - bus_owner_unref (owner); -} - -static void -bus_service_unlink (BusService *service) -{ - _dbus_assert (service->owners == NULL); - - /* the service may not be in the hash, if - * the failure causing transaction cancel - * was in the right place, but that's OK - */ - _dbus_hash_table_remove_string (service->registry->service_hash, - service->name); - - bus_service_unref (service); -} - -static void -bus_service_relink (BusService *service, - DBusPreallocatedHash *preallocated) -{ - _dbus_assert (service->owners == NULL); - _dbus_assert (preallocated != NULL); - - _dbus_hash_table_insert_string_preallocated (service->registry->service_hash, - preallocated, - service->name, - service); - - bus_service_ref (service); -} - -/** - * Data used to represent an ownership cancellation in - * a bus transaction. - */ -typedef struct -{ - BusOwner *owner; /**< the owner */ - BusService *service; /**< service to cancel ownership of */ -} OwnershipCancelData; - -static void -cancel_ownership (void *data) -{ - OwnershipCancelData *d = data; - - /* We don't need to send messages notifying of these - * changes, since we're reverting something that was - * cancelled (effectively never really happened) - */ - bus_service_unlink_owner (d->service, d->owner); - - if (d->service->owners == NULL) - bus_service_unlink (d->service); -} - -static void -free_ownership_cancel_data (void *data) -{ - OwnershipCancelData *d = data; - - dbus_connection_unref (d->owner->conn); - bus_owner_unref (d->owner); - bus_service_unref (d->service); - - dbus_free (d); -} - -static dbus_bool_t -add_cancel_ownership_to_transaction (BusTransaction *transaction, - BusService *service, - BusOwner *owner) -{ - OwnershipCancelData *d; - - d = dbus_new (OwnershipCancelData, 1); - if (d == NULL) - return FALSE; - - d->service = service; - d->owner = owner; - - if (!bus_transaction_add_cancel_hook (transaction, cancel_ownership, d, - free_ownership_cancel_data)) - { - dbus_free (d); - return FALSE; - } - - bus_service_ref (d->service); - 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 *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 - * in cancelling the transaction - */ - if (service->owners == NULL) - { - if (!bus_driver_send_service_acquired (connection, service->name, transaction, error)) - return FALSE; - } - - bus_owner_link = _bus_service_find_owner_link (service, connection); - - if (bus_owner_link == NULL) - { - bus_owner = bus_owner_new (service, connection, flags); - if (bus_owner == NULL) - { - BUS_SET_OOM (error); - return FALSE; - } - - 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 - { - /* 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, - bus_owner)) - { - bus_service_unlink_owner (service, bus_owner); - BUS_SET_OOM (error); - return FALSE; - } - - return TRUE; -} - -typedef struct -{ - BusOwner *owner; - BusService *service; - BusOwner *before_owner; /* restore to position before this connection in owners list */ - DBusList *owner_link; - DBusList *service_link; - DBusPreallocatedHash *hash_entry; -} OwnershipRestoreData; - -static void -restore_ownership (void *data) -{ - OwnershipRestoreData *d = data; - DBusList *link; - - _dbus_assert (d->service_link != NULL); - _dbus_assert (d->owner_link != NULL); - - if (d->service->owners == NULL) - { - _dbus_assert (d->hash_entry != NULL); - bus_service_relink (d->service, d->hash_entry); - } - else - { - _dbus_assert (d->hash_entry == NULL); - } - - /* We don't need to send messages notifying of these - * changes, since we're reverting something that was - * cancelled (effectively never really happened) - */ - link = _dbus_list_get_first_link (&d->service->owners); - while (link != NULL) - { - 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->owner_link); - - /* Note that removing then restoring this changes the order in which - * ServiceDeleted messages are sent on destruction of the - * connection. This should be OK as the only guarantee there is - * that the base service is destroyed last, and we never even - * tentatively remove the base service. - */ - bus_connection_add_owned_service_link (d->owner->conn, d->service_link); - - d->hash_entry = NULL; - d->service_link = NULL; - d->owner_link = NULL; -} - -static void -free_ownership_restore_data (void *data) -{ - OwnershipRestoreData *d = data; - - if (d->service_link) - _dbus_list_free_link (d->service_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->owner->conn); - bus_owner_unref (d->owner); - bus_service_unref (d->service); - - dbus_free (d); -} - -static dbus_bool_t -add_restore_ownership_to_transaction (BusTransaction *transaction, - BusService *service, - BusOwner *owner) -{ - OwnershipRestoreData *d; - DBusList *link; - - d = dbus_new (OwnershipRestoreData, 1); - if (d == NULL) - return FALSE; - - d->service = service; - d->owner = owner; - d->service_link = _dbus_list_alloc_link (service); - 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); - bus_owner_ref (d->owner); - dbus_connection_ref (d->owner->conn); - - d->before_owner = NULL; - link = _dbus_list_get_first_link (&service->owners); - while (link != NULL) - { - if (link->data == owner) - { - link = _dbus_list_get_next_link (&service->owners, link); - - if (link) - d->before_owner = link->data; - - break; - } - - link = _dbus_list_get_next_link (&service->owners, link); - } - - if (d->service_link == NULL || - d->owner_link == NULL || - d->hash_entry == NULL || - !bus_transaction_add_cancel_hook (transaction, restore_ownership, d, - free_ownership_restore_data)) - { - free_ownership_restore_data (d); - return FALSE; - } - - 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 *connection, - BusTransaction *transaction, - DBusError *error) -{ - 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) - { - 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) - { - _dbus_assert_not_reached ("Tried to remove owner of a service that has no owners"); - } - else if (_dbus_list_length_is_one (&service->owners)) - { - if (!bus_driver_send_service_owner_changed (service->name, - bus_connection_get_name (connection), - NULL, - transaction, error)) - return FALSE; - } - 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; - } - - bus_service_unlink_owner (service, primary_owner); - - if (service->owners == NULL) - bus_service_unlink (service); - - return TRUE; -} - -BusService * -bus_service_ref (BusService *service) -{ - _dbus_assert (service->refcount > 0); - - service->refcount += 1; - - return service; -} - -void -bus_service_unref (BusService *service) -{ - _dbus_assert (service->refcount > 0); - - service->refcount -= 1; - - if (service->refcount == 0) - { - _dbus_assert (service->owners == NULL); - - dbus_free (service->name); - _dbus_mem_pool_dealloc (service->registry->service_pool, service); - } -} - -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); -} - -const char* -bus_service_get_name (BusService *service) -{ - return service->name; -} - -dbus_bool_t -bus_service_get_allow_replacement (BusService *service) -{ - 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_has_owner (BusService *service, - DBusConnection *connection) -{ - DBusList *link; - - link = _bus_service_find_owner_link (service, connection); - - if (link == NULL) - return FALSE; - else - return TRUE; -} - -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) - { - BusOwner *owner; - const char *uname; - - owner = (BusOwner *) link->data; - uname = bus_connection_get_name (owner->conn); - - if (!_dbus_list_append (return_list, (char *)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; -} |