* 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
This commit is contained in:
John (J5) Palmieri 2005-11-22 20:37:00 +00:00
parent c33af17b93
commit 1a163e765c
23 changed files with 1585 additions and 187 deletions

103
ChangeLog
View file

@ -1,3 +1,106 @@
2005-11-22 John (J5) Palmieri <johnp@redhat.com>
* 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
2005-11-15 Robert McQueen <robot101@debian.org>
* dbus/dbus-glib-lowlevel.h, glib/dbus-gobject.c: Patch from Rob

View file

@ -980,7 +980,7 @@ bus_activation_send_pending_auto_activation_messages (BusActivation *activation
{
DBusConnection *addressed_recipient;
addressed_recipient = bus_service_get_primary_owner (service);
addressed_recipient = bus_service_get_primary_owners_connection (service);
/* Check the security policy, which has the side-effect of adding an
* expected pending reply.

View file

@ -40,6 +40,7 @@ typedef struct BusPolicyRule BusPolicyRule;
typedef struct BusRegistry BusRegistry;
typedef struct BusSELinuxID BusSELinuxID;
typedef struct BusService BusService;
typedef struct BusOwner BusOwner;
typedef struct BusTransaction BusTransaction;
typedef struct BusMatchmaker BusMatchmaker;
typedef struct BusMatchRule BusMatchRule;

View file

@ -287,7 +287,7 @@ bus_dispatch (DBusConnection *connection,
}
else
{
addressed_recipient = bus_service_get_primary_owner (service);
addressed_recipient = bus_service_get_primary_owners_connection (service);
_dbus_assert (addressed_recipient != NULL);
if (!bus_context_check_security_policy (context, transaction,

View file

@ -308,12 +308,10 @@ bus_driver_handle_hello (DBusConnection *connection,
/* Create the service */
service = bus_registry_ensure (registry,
&unique_name, connection, transaction, error);
&unique_name, connection, 0, transaction, error);
if (service == NULL)
goto out_0;
bus_service_set_prohibit_replacement (service, TRUE);
_dbus_assert (bus_connection_is_active (connection));
retval = TRUE;
@ -883,7 +881,7 @@ bus_driver_handle_get_service_owner (DBusConnection *connection,
}
else
{
base_name = bus_connection_get_name (bus_service_get_primary_owner (service));
base_name = bus_connection_get_name (bus_service_get_primary_owners_connection (service));
if (base_name == NULL)
{
/* FIXME - how is this error possible? */
@ -923,6 +921,113 @@ bus_driver_handle_get_service_owner (DBusConnection *connection,
return FALSE;
}
static dbus_bool_t
bus_driver_handle_list_queued_owners (DBusConnection *connection,
BusTransaction *transaction,
DBusMessage *message,
DBusError *error)
{
const char *text;
DBusList *base_names;
DBusList *link;
DBusString str;
BusRegistry *registry;
BusService *service;
DBusMessage *reply;
DBusMessageIter iter, array_iter;
char *dbus_service_name = DBUS_SERVICE_DBUS;
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
registry = bus_connection_get_registry (connection);
base_names = NULL;
text = NULL;
reply = NULL;
if (! dbus_message_get_args (message, error,
DBUS_TYPE_STRING, &text,
DBUS_TYPE_INVALID))
goto failed;
_dbus_string_init_const (&str, text);
service = bus_registry_lookup (registry, &str);
if (service == NULL &&
_dbus_string_equal_c_str (&str, DBUS_SERVICE_DBUS))
{
/* ORG_FREEDESKTOP_DBUS owns itself */
if (! _dbus_list_append (&base_names, dbus_service_name))
goto oom;
}
else if (service == NULL)
{
dbus_set_error (error,
DBUS_ERROR_NAME_HAS_NO_OWNER,
"Could not get owners of name '%s': no such name", text);
goto failed;
}
else
{
if (!bus_service_list_queued_owners (service,
&base_names,
error))
goto failed;
}
_dbus_assert (base_names != NULL);
reply = dbus_message_new_method_return (message);
if (reply == NULL)
goto oom;
dbus_message_iter_init_append (reply, &iter);
if (!dbus_message_iter_open_container (&iter,
DBUS_TYPE_ARRAY,
DBUS_TYPE_STRING_AS_STRING,
&array_iter))
goto oom;
link = _dbus_list_get_first_link (&base_names);
while (link != NULL)
{
char *uname;
_dbus_assert (link->data != NULL);
uname = (char *)link->data;
if (!dbus_message_iter_append_basic (&array_iter,
DBUS_TYPE_STRING,
&uname))
goto oom;
link = _dbus_list_get_next_link (&base_names, link);
}
if (! dbus_message_iter_close_container (&iter, &array_iter))
goto oom;
if (! bus_transaction_send_from_driver (transaction, connection, reply))
goto oom;
dbus_message_unref (reply);
return TRUE;
oom:
BUS_SET_OOM (error);
failed:
_DBUS_ASSERT_ERROR_IS_SET (error);
if (reply)
dbus_message_unref (reply);
if (base_names)
_dbus_list_clear (&base_names);
return FALSE;
}
static dbus_bool_t
bus_driver_handle_get_connection_unix_user (DBusConnection *connection,
BusTransaction *transaction,
@ -962,7 +1067,7 @@ bus_driver_handle_get_connection_unix_user (DBusConnection *connection,
goto failed;
}
conn = bus_service_get_primary_owner (serv);
conn = bus_service_get_primary_owners_connection (serv);
reply = dbus_message_new_method_return (message);
if (reply == NULL)
@ -1038,7 +1143,7 @@ bus_driver_handle_get_connection_unix_process_id (DBusConnection *connection,
goto failed;
}
conn = bus_service_get_primary_owner (serv);
conn = bus_service_get_primary_owners_connection (serv);
reply = dbus_message_new_method_return (message);
if (reply == NULL)
@ -1113,7 +1218,7 @@ bus_driver_handle_get_connection_selinux_security_context (DBusConnection *conne
goto failed;
}
conn = bus_service_get_primary_owner (serv);
conn = bus_service_get_primary_owners_connection (serv);
reply = dbus_message_new_method_return (message);
if (reply == NULL)
@ -1235,6 +1340,10 @@ struct
DBUS_TYPE_STRING_AS_STRING,
DBUS_TYPE_STRING_AS_STRING,
bus_driver_handle_get_service_owner },
{ "ListQueuedOwners",
DBUS_TYPE_STRING_AS_STRING,
DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING,
bus_driver_handle_list_queued_owners },
{ "GetConnectionUnixUser",
DBUS_TYPE_STRING_AS_STRING,
DBUS_TYPE_UINT32_AS_STRING,

View file

@ -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)
{
service->prohibit_replacement = prohibit_replacement != FALSE;
}
dbus_bool_t
bus_service_get_prohibit_replacement (BusService *service)
bus_service_get_allow_replacement (BusService *service)
{
return service->prohibit_replacement;
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 *owner)
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)
{
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;
}

View file

@ -40,7 +40,8 @@ BusService* bus_registry_lookup (BusRegistry *registry
const DBusString *service_name);
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);
void bus_registry_foreach (BusRegistry *registry,
@ -65,23 +66,29 @@ dbus_bool_t bus_registry_release_service (BusRegistry *registry
dbus_bool_t bus_registry_set_service_context_table (BusRegistry *registry,
DBusHashTable *table);
BusService* bus_service_ref (BusService *service);
void bus_service_unref (BusService *service);
dbus_bool_t bus_service_add_owner (BusService *service,
DBusConnection *owner,
BusTransaction *transaction,
DBusError *error);
dbus_bool_t bus_service_remove_owner (BusService *service,
DBusConnection *owner,
BusTransaction *transaction,
DBusError *error);
dbus_bool_t bus_service_has_owner (BusService *service,
DBusConnection *owner);
DBusConnection* bus_service_get_primary_owner (BusService *service);
void bus_service_set_prohibit_replacement (BusService *service,
dbus_bool_t prohibit_replacement);
dbus_bool_t bus_service_get_prohibit_replacement (BusService *service);
const char* bus_service_get_name (BusService *service);
BusService* bus_service_ref (BusService *service);
void bus_service_unref (BusService *service);
dbus_bool_t bus_service_add_owner (BusService *service,
DBusConnection *connection,
dbus_uint32_t flags,
BusTransaction *transaction,
DBusError *error);
dbus_bool_t bus_service_swap_owner (BusService *service,
DBusConnection *connection,
BusTransaction *transaction,
DBusError *error);
dbus_bool_t bus_service_remove_owner (BusService *service,
DBusConnection *connection,
BusTransaction *transaction,
DBusError *error);
dbus_bool_t bus_service_has_owner (BusService *service,
DBusConnection *connection);
BusOwner* bus_service_get_primary_owner (BusService *service);
dbus_bool_t bus_service_get_allow_replacement (BusService *service);
const char* bus_service_get_name (BusService *service);
dbus_bool_t bus_service_list_queued_owners (BusService *service,
DBusList **return_list,
DBusError *error);
DBusConnection* bus_service_get_primary_owners_connection (BusService *service);
#endif /* BUS_SERVICES_H */

View file

@ -1274,7 +1274,7 @@ connection_is_primary_owner (DBusConnection *connection,
if (service == NULL)
return FALSE; /* Service doesn't exist so connection can't own it. */
return bus_service_get_primary_owner (service) == connection;
return bus_service_get_primary_owners_connection (service) == connection;
}
static dbus_bool_t

View file

@ -1349,6 +1349,7 @@ test/Makefile
test/glib/Makefile
test/python/Makefile
test/qt/Makefile
test/name-test/Makefile
doc/Makefile
dbus-1.pc
dbus-glib-1.pc

View file

@ -655,20 +655,17 @@ dbus_bus_get_unix_user (DBusConnection *connection,
* result codes are discussed here, but the specification is the
* canonical version of this information.
*
* The #DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT flag indicates that
* if the name is successfully requested, other applications
* will not be able to take over the name. i.e. the name's
* owner (the application calling this function) must let go of
* the name, it will not lose it involuntarily.
* The #DBUS_NAME_FLAG_ALLOW_REPLACEMENT flag indicates that the caller
* will allow other services to take over the name from the current owner.
*
* The #DBUS_NAME_FLAG_REPLACE_EXISTING flag indicates that the caller
* would like to take over the name from the current owner.
* If the current name owner used #DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT
* If the current name owner did not use #DBUS_NAME_FLAG_ALLOW_REPLACEMENT
* then this flag indicates that the caller would like to be placed
* in the queue to own the name when the current owner lets go.
*
* If no flags are given, an application will receive the requested
* name only if the name is currently unowned; and it will give
* name only if the name is currently unowned; it will NOT give
* up the name if another application asks to take it over using
* #DBUS_NAME_FLAG_REPLACE_EXISTING.
*
@ -678,27 +675,31 @@ dbus_bus_get_unix_user (DBusConnection *connection,
* #DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER means that the name had no
* existing owner, and the caller is now the primary owner; or that
* the name had an owner, and the caller specified
* #DBUS_NAME_FLAG_REPLACE_EXISTING, and the current owner did not
* specify #DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT.
* #DBUS_NAME_FLAG_REPLACE_EXISTING, and the current owner
* specified #DBUS_NAME_FLAG_ALLOW_REPLACEMENT.
*
* #DBUS_REQUEST_NAME_REPLY_IN_QUEUE happens only if the current owner
* specified #DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT and the caller specified
* #DBUS_NAME_FLAG_REPLACE_EXISTING. In this case the caller ends up in
* a queue to own the name after the current owner gives it up.
* #DBUS_REQUEST_NAME_REPLY_IN_QUEUE happens only if the caller does NOT
* specify #DBUS_NAME_FLAG_DO_NOT_QUEUE and either the current owner
* did NOT specify #DBUS_NAME_FLAG_ALLOW_REPLACEMENT or the caller did NOT
* specify #DBUS_NAME_FLAG_REPLACE_EXISTING. In this case the caller ends up
* in a queue to own the name after the current owner gives it up.
*
* #DBUS_REQUEST_NAME_REPLY_EXISTS happens if the name has an owner
* #already and DBUS_NAME_FLAG_REPLACE_EXISTING was not specified.
* already and the caller specifies #DBUS_NAME_FLAG_DO_NOT_QUEUE
* and either the current owner has NOT specified
* #DBUS_NAME_FLAG_ALLOW_REPLACEMENT or the caller did NOT specify
* #DBUS_NAME_FLAG_REPLACE_EXISTING.
*
* #DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER happens if an application
* requests a name it already owns.
*
* When a service represents an application, say "text editor," then
* it should specify #DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT if it wants
* the first editor started to be the user's editor vs. the last one
* it should specify #DBUS_NAME_FLAG_ALLOW_REPLACEMENT if it wants
* the last editor started to be the user's editor vs. the first one
* started. Then any editor that can be the user's editor should
* specify #DBUS_NAME_FLAG_REPLACE_EXISTING to either take over
* (last-started-wins) or be queued up (first-started-wins) according
* to whether #DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT was given.
* to whether #DBUS_NAME_FLAG_ALLOW_REPLACEMENT was given.
*
* @todo this all seems sort of broken. Shouldn't the flags be a property
* of the name, not the app requesting the name? What are the use-cases
@ -1097,4 +1098,16 @@ dbus_bus_remove_match (DBusConnection *connection,
dbus_message_unref (msg);
}
#ifdef DBUS_BUILD_TESTS
const char *
dbus_bus_connection_get_unique_name (DBusConnection *connection)
{
BusData *bd;
bd = dbus_connection_get_data (connection, bus_data_slot);
return bd->unique_name;
}
#endif /* DBUS_BUILD_TESTS */
/** @} */

View file

@ -57,9 +57,12 @@ DBusMessage* dbus_g_message_get_message (DBusGMessage *gmessage);
* g-functions anyhow)
*/
DBusMessage * dbus_g_method_return_get_reply (DBusGMethodInvocation *context);
gchar* dbus_g_method_get_sender (DBusGMethodInvocation *context);
void dbus_g_method_return_send_reply (DBusGMethodInvocation *context, DBusMessage *reply);
DBusMessage* dbus_g_method_get_reply (DBusGMethodInvocation *context);
void dbus_g_method_send_reply (DBusGMethodInvocation *context,
DBusMessage *reply);
G_END_DECLS

View file

@ -68,8 +68,9 @@ typedef enum
#define DBUS_INTERFACE_LOCAL "org.freedesktop.DBus.Local"
/* Owner flags */
#define DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT 0x1
#define DBUS_NAME_FLAG_REPLACE_EXISTING 0x2
#define DBUS_NAME_FLAG_ALLOW_REPLACEMENT 0x1
#define DBUS_NAME_FLAG_REPLACE_EXISTING 0x2
#define DBUS_NAME_FLAG_DO_NOT_QUEUE 0x4
/* Replies to request for a name */
#define DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER 1

View file

@ -398,6 +398,7 @@ _dbus_connect_unix_socket (const char *path,
DBusError *error)
{
int fd;
size_t path_len;
struct sockaddr_un addr;
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
@ -419,15 +420,23 @@ _dbus_connect_unix_socket (const char *path,
_DBUS_ZERO (addr);
addr.sun_family = AF_UNIX;
path_len = strlen (path);
if (abstract)
{
#ifdef HAVE_ABSTRACT_SOCKETS
/* remember that abstract names aren't nul-terminated so we rely
* on sun_path being filled in with zeroes above.
*/
addr.sun_path[0] = '\0'; /* this is what says "use abstract" */
strncpy (&addr.sun_path[1], path, _DBUS_MAX_SUN_PATH_LENGTH - 2);
path_len++; /* Account for the extra nul byte added to the start of sun_path */
if (path_len > _DBUS_MAX_SUN_PATH_LENGTH)
{
dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
"Abstract socket name too long\n");
close (fd);
return -1;
}
strncpy (&addr.sun_path[1], path, path_len);
/* _dbus_verbose_bytes (addr.sun_path, sizeof (addr.sun_path)); */
#else /* HAVE_ABSTRACT_SOCKETS */
dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED,
@ -438,10 +447,18 @@ _dbus_connect_unix_socket (const char *path,
}
else
{
strncpy (addr.sun_path, path, _DBUS_MAX_SUN_PATH_LENGTH - 1);
if (path_len > _DBUS_MAX_SUN_PATH_LENGTH)
{
dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
"Socket name too long\n");
close (fd);
return -1;
}
strncpy (addr.sun_path, path, path_len);
}
if (connect (fd, (struct sockaddr*) &addr, sizeof (addr)) < 0)
if (connect (fd, (struct sockaddr*) &addr, _DBUS_STRUCT_OFFSET (struct sockaddr_un, sun_path) + path_len) < 0)
{
dbus_set_error (error,
_dbus_error_from_errno (errno),
@ -489,6 +506,7 @@ _dbus_listen_unix_socket (const char *path,
{
int listen_fd;
struct sockaddr_un addr;
size_t path_len;
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
@ -507,6 +525,7 @@ _dbus_listen_unix_socket (const char *path,
_DBUS_ZERO (addr);
addr.sun_family = AF_UNIX;
path_len = strlen (path);
if (abstract)
{
@ -515,7 +534,17 @@ _dbus_listen_unix_socket (const char *path,
* on sun_path being filled in with zeroes above.
*/
addr.sun_path[0] = '\0'; /* this is what says "use abstract" */
strncpy (&addr.sun_path[1], path, _DBUS_MAX_SUN_PATH_LENGTH - 2);
path_len++; /* Account for the extra nul byte added to the start of sun_path */
if (path_len > _DBUS_MAX_SUN_PATH_LENGTH)
{
dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
"Abstract socket name too long\n");
close (listen_fd);
return -1;
}
strncpy (&addr.sun_path[1], path, path_len);
/* _dbus_verbose_bytes (addr.sun_path, sizeof (addr.sun_path)); */
#else /* HAVE_ABSTRACT_SOCKETS */
dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED,
@ -544,10 +573,18 @@ _dbus_listen_unix_socket (const char *path,
unlink (path);
}
strncpy (addr.sun_path, path, _DBUS_MAX_SUN_PATH_LENGTH - 1);
if (path_len > _DBUS_MAX_SUN_PATH_LENGTH)
{
dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
"Abstract socket name too long\n");
close (listen_fd);
return -1;
}
strncpy (addr.sun_path, path, path_len);
}
if (bind (listen_fd, (struct sockaddr*) &addr, sizeof (addr)) < 0)
if (bind (listen_fd, (struct sockaddr*) &addr, _DBUS_STRUCT_OFFSET (struct sockaddr_un, sun_path) + path_len) < 0)
{
dbus_set_error (error, _dbus_error_from_errno (errno),
"Failed to bind socket \"%s\": %s",

View file

@ -28,11 +28,6 @@ Important for 1.0
Kind of a major API change, but seems high-value.
- figure out what the deal is with trailing nul bytes in
abstract socket names
http://lists.freedesktop.org/archives/dbus/2005-August/003179.html
Important for 1.0 GLib Bindings
===

View file

@ -2229,13 +2229,37 @@
the next one specified, and so forth. For example
<programlisting>unix:path=/tmp/dbus-test;unix:path=/tmp/dbus-test2</programlisting>
</para>
</sect1>
<sect1 id="transports">
<title>Transports</title>
<para>
[FIXME we need to specify in detail each transport and its possible arguments]
Current transports include: unix domain sockets (including
abstract namespace on linux), TCP/IP, and a debug/testing transport using
in-process pipes. Future possible transports include one that
tunnels over X11 protocol.
</para>
<sect2 id="transports-unix-domain-sockets">
<title>Unix Domain Sockets</title>
<para>
Unix domain sockets can be either paths in the file system or on Linux
kernels, they can be abstract which are similar to paths but i
do not show up in the file system.
</para>
<para>
When a socket is opened by the D-Bus library it truncates the path
name right befor the first trailing Nul byte. This is true for both
normal paths and abstract paths. Note that this is a departure from
previous versions of D-Bus that would create sockets with a fixed
length path name. Names which were shorter than the fixed length
would be padded by Nul bytes.
</para>
</sect2>
</sect1>
<sect1 id="naming-conventions">
@ -2625,8 +2649,79 @@
<para>
This method call should be sent to
<literal>org.freedesktop.DBus</literal> and asks the message bus to
assign the given name to the method caller. The flags argument
contains any of the following values logically ORed together:
assign the given name to the method caller. Each name maintains a
queue of possible owners, where the head of the queue is the primary
or current owner of the name. Each potential owner in the queue
maintains the DBUS_NAME_FLAG_ALLOW_REPLACEMENT and
DBUS_NAME_FLAG_DO_NOT_QUEUE settings from its latest RequestName
call. When RequestName is invoked the following occurs:
<itemizedlist>
<listitem>
<para>
If the method caller is currently the primary owner of the name,
the DBUS_NAME_FLAG_ALLOW_REPLACEMENT and DBUS_NAME_FLAG_DO_NOT_QUEUE
values are updated with the values from the new RequestName call,
and nothing further happens.
</para>
</listitem>
<listitem>
<para>
If the current primary owner (head of the queue) has
DBUS_NAME_FLAG_ALLOW_REPLACEMENT set, and the RequestName
invocation has the DBUS_NAME_FLAG_REPLACE_EXISTING flag, then
the caller of RequestName replaces the current primary owner at
the head of the queue and the current primary owner moves to the
second position in the queue. If the caller of RequestName was
in the queue previously its flags are updated with the values from
the new RequestName in addition to moving it to the head of the queue.
</para>
</listitem>
<listitem>
<para>
If replacement is not possible, and the method caller is
currently in the queue but not the primary owner, its flags are
updated with the values from the new RequestName call.
</para>
</listitem>
<listitem>
<para>
If replacement is not possible, and the method caller is
currently not in the queue, the method caller is appended to the
queue.
</para>
</listitem>
<listitem>
<para>
If any connection in the queue has DBUS_NAME_FLAG_DO_NOT_QUEUE
set and is not the primary owner, it is removed from the
queue. This can apply to the previous primary owner (if it
was replaced) or the method caller (if it updated the
DBUS_NAME_FLAG_DO_NOT_QUEUE flag while still stuck in the
queue, or if it was just added to the queue with that flag set).
</para>
</listitem>
</itemizedlist>
</para>
<para>
Note that DBUS_NAME_FLAG_REPLACE_EXISTING results in "jumping the
queue," even if another application already in the queue had specified
DBUS_NAME_FLAG_REPLACE_EXISTING. This comes up if a primary owner
that does not allow replacement goes away, and the next primary owner
does allow replacement. In this case, queued items that specified
DBUS_NAME_FLAG_REPLACE_EXISTING <emphasis>do not</emphasis>
automatically replace the new primary owner. In other words,
DBUS_NAME_FLAG_REPLACE_EXISTING is not saved, it is only used at the
time RequestName is called. This is deliberate to avoid an infinite loop
anytime two applications are both DBUS_NAME_FLAG_ALLOW_REPLACEMENT
and DBUS_NAME_FLAG_REPLACE_EXISTING.
</para>
<para>
The flags argument contains any of the following values logically ORed
together:
<informaltable>
<tgroup cols="3">
@ -2639,23 +2734,51 @@
</thead>
<tbody>
<row>
<entry>DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT</entry>
<entry>DBUS_NAME_FLAG_ALLOW_REPLACEMENT</entry>
<entry>0x1</entry>
<entry>
If the application succeeds in becoming the owner of the specified name,
then ownership of the name can't be transferred until the application
disconnects. If this flag is not set, then any application trying to become
the owner of the name will succeed and the previous owner will be
sent a <literal>org.freedesktop.DBus.NameLost</literal> signal.
If an application A specifies this flag and succeeds in
becoming the owner of the name, and another application B
later calls RequestName with the
DBUS_NAME_FLAG_REPLACE_EXISTING flag, then application A
will lose ownership and receive a
<literal>org.freedesktop.DBus.NameLost</literal> signal, and
application B will become the new owner. If DBUS_NAME_FLAG_ALLOW_REPLACEMENT
is not specified by application A, or DBUS_NAME_FLAG_REPLACE_EXISTING
is not specified by application B, then application B will not replace
application A as the owner.
</entry>
</row>
<row>
<entry>DBUS_NAME_FLAG_REPLACE_EXISTING</entry>
<entry>0x2</entry>
<entry>
Try to replace the current owner if there is one. If this
flag is not set the application will only become the owner of
the name if there is no current owner.
the name if there is no current owner. If this flag is set,
the application will replace the current owner if
the current owner specified DBUS_NAME_FLAG_ALLOW_REPLACEMENT.
</entry>
</row>
<row>
<entry>DBUS_NAME_FLAG_DO_NOT_QUEUE</entry>
<entry>0x4</entry>
<entry>
Without this flag, if an application requests a name that is
already owned, the application will be placed in a queue to
own the name when the current owner gives it up. If this
flag is given, the application will not be placed in the
queue, the request for the name will simply fail. This flag
also affects behavior when an application is replaced as
name owner; by default the application moves back into the
waiting queue, unless this flag was provided when the application
became the name owner.
</entry>
</row>
</tbody>
@ -2679,18 +2802,27 @@
<entry>1</entry> <entry>The caller is now the primary owner of
the name, replacing any previous owner. Either the name had no
owner before, or the caller specified
DBUS_NAME_FLAG_REPLACE_EXISTING and the current owner did not
specify DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT.</entry>
DBUS_NAME_FLAG_REPLACE_EXISTING and the current owner specified
DBUS_NAME_FLAG_ALLOW_REPLACEMENT.</entry>
</row>
<row>
<entry>DBUS_REQUEST_NAME_REPLY_IN_QUEUE</entry>
<entry>2</entry>
<entry>The name already had an owner, DBUS_NAME_FLAG_REPLACE_EXISTING was not specified, and the current owner specified DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT.</entry>
<entry>The name already had an owner,
DBUS_NAME_FLAG_DO_NOT_QUEUE was not specified, and either
the current owner did not specify
DBUS_NAME_FLAG_ALLOW_REPLACEMENT or the requesting
application did not specify DBUS_NAME_FLAG_REPLACE_EXISTING.
</entry>
</row>
<row>
<entry>DBUS_REQUEST_NAME_REPLY_EXISTS</entry>
<entry>3</entry>
<entry>The name already has an owner, and DBUS_NAME_FLAG_REPLACE_EXISTING was not specified.</entry>
<entry>DBUS_REQUEST_NAME_REPLY_EXISTS</entry> <entry>3</entry>
<entry>The name already has an owner,
DBUS_NAME_FLAG_DO_NOT_QUEUE was specified, and either
DBUS_NAME_FLAG_ALLOW_REPLACEMENT was not specified by the
current owner, or DBUS_NAME_FLAG_REPLACE_EXISTING was not
specified by the requesting application.</entry>
</row>
<row>
<entry>DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER</entry>

View file

@ -1858,6 +1858,28 @@ dbus_g_object_register_marshaller_array (GClosureMarshal marshaller,
g_static_rw_lock_writer_unlock (&globals_lock);
}
/**
* Get the sender of a message so we can send a
* "reply" later (i.e. send a message directly
* to a service which invoked the method at a
* later time).
*
* @param context the method context
*
* @return the unique name of teh sender
*/
gchar *
dbus_g_method_get_sender (DBusGMethodInvocation *context)
{
const gchar *sender;
sender = dbus_message_get_sender (dbus_g_message_get_message (context->message));
if (sender == NULL)
return NULL;
return strdup (sender);
}
/**
* Get the reply message to append reply values
@ -1867,9 +1889,9 @@ dbus_g_object_register_marshaller_array (GClosureMarshal marshaller,
* @param context the method context
*/
DBusMessage *
dbus_g_method_return_get_reply (DBusGMethodInvocation *context)
dbus_g_method_get_reply (DBusGMethodInvocation *context)
{
return dbus_message_new_method_return (dbus_g_message_get_message (context->message));
return dbus_message_new_method_return (dbus_g_message_get_message (context->message));
}
/**
@ -1881,7 +1903,7 @@ dbus_g_method_return_get_reply (DBusGMethodInvocation *context)
* @param reply the reply message, will be unreffed
*/
void
dbus_g_method_return_send_reply (DBusGMethodInvocation *context, DBusMessage *reply)
dbus_g_method_send_reply (DBusGMethodInvocation *context, DBusMessage *reply)
{
dbus_connection_send (dbus_g_connection_get_connection (context->connection), reply, NULL);
dbus_message_unref (reply);

View file

@ -135,7 +135,7 @@ main (int argc, char **argv)
if (!dbus_g_proxy_call (bus_proxy, "RequestName", &error,
G_TYPE_STRING, "org.designfu.SampleService",
G_TYPE_UINT, DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT,
G_TYPE_UINT, 0,
G_TYPE_INVALID,
G_TYPE_UINT, &request_name_result,
G_TYPE_INVALID))

View file

@ -114,7 +114,7 @@ main (int argc, char **argv)
if (!dbus_g_proxy_call (bus_proxy, "RequestName", &error,
G_TYPE_STRING, "org.designfu.TestService",
G_TYPE_UINT, DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT,
G_TYPE_UINT, 0,
G_TYPE_INVALID,
G_TYPE_UINT, &request_name_result,
G_TYPE_INVALID))

View file

@ -211,7 +211,7 @@ main (int argc, char **argv)
if (!dbus_g_proxy_call (bus_proxy, "RequestName", &error,
G_TYPE_STRING, "com.example.StateServer",
G_TYPE_UINT, DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT,
G_TYPE_UINT, 0,
G_TYPE_INVALID,
G_TYPE_UINT, &request_name_result,
G_TYPE_INVALID))

View file

@ -9,8 +9,8 @@ if HAVE_QTESTLIB
QT_SUBDIR=qt
endif
SUBDIRS=$(GLIB_SUBDIR) $(PYTHON_SUBDIR) $(QT_SUBDIR)
DIST_SUBDIRS=glib python qt
SUBDIRS=name-test $(GLIB_SUBDIR) $(PYTHON_SUBDIR) $(QT_SUBDIR)
DIST_SUBDIRS=glib python qt name-test
INCLUDES=-I$(top_srcdir) $(DBUS_TEST_CFLAGS)

View file

@ -0,0 +1,26 @@
INCLUDES=-I$(top_srcdir) $(DBUS_CLIENT_CFLAGS) $(DBUS_GLIB_CFLAGS) -DDBUS_COMPILATION
## note that TESTS has special meaning (stuff to use in make check)
## so if adding tests not to be run in make check, don't add them to
## TESTS
if DBUS_BUILD_TESTS
TESTS_ENVIRONMENT=DBUS_TOP_BUILDDIR=$(ABSOLUTE_TOP_BUILDDIR)
TESTS=run-test.sh
else
TESTS=
endif
EXTRA_DIST=run-test.sh
if DBUS_BUILD_TESTS
## we use noinst_PROGRAMS not check_PROGRAMS for TESTS so that we
## build even when not doing "make check"
noinst_PROGRAMS=test-names
test_names_SOURCES= \
test-names.c
test_names_LDADD=$(top_builddir)/dbus/libdbus-1.la $(top_builddir)/dbus/libdbus-convenience.la
endif

30
test/name-test/run-test.sh Executable file
View file

@ -0,0 +1,30 @@
#! /bin/bash
function die()
{
if ! test -z "$DBUS_SESSION_BUS_PID" ; then
echo "killing message bus "$DBUS_SESSION_BUS_PID >&2
kill -9 $DBUS_SESSION_BUS_PID
fi
echo $SCRIPTNAME: $* >&2
rm $DBUS_TOP_BUILDDIR/python/dbus
exit 1
}
SCRIPTNAME=$0
MODE=$1
## so the tests can complain if you fail to use the script to launch them
export DBUS_TEST_NAME_RUN_TEST_SCRIPT=1
# Rerun ourselves with tmp session bus if we're not already
if test -z "$DBUS_TEST_NAME_IN_RUN_TEST"; then
DBUS_TEST_NAME_IN_RUN_TEST=1
export DBUS_TEST_NAME_IN_RUN_TEST
exec $DBUS_TOP_BUILDDIR/tools/run-with-tmp-session-bus.sh $SCRIPTNAME $MODE
fi
echo "running test-names"
libtool --mode=execute $DEBUG $DBUS_TOP_BUILDDIR/test/name-test/test-names || die "test-client failed"

578
test/name-test/test-names.c Normal file
View file

@ -0,0 +1,578 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <dbus/dbus.h>
#include <dbus/dbus-connection-internal.h>
#define REMOVE_CONNECTION 0
#define ADD_CONNECTION 1
#define ALLOW_REPLACEMENT DBUS_NAME_FLAG_ALLOW_REPLACEMENT
#define REPLACE_EXISTING DBUS_NAME_FLAG_REPLACE_EXISTING
#define DO_NOT_QUEUE DBUS_NAME_FLAG_DO_NOT_QUEUE
#define PRIMARY_OWNER DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER
#define IN_QUEUE DBUS_REQUEST_NAME_REPLY_IN_QUEUE
#define EXISTS DBUS_REQUEST_NAME_REPLY_EXISTS
#define ALREADY_OWNER DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER
#define RELEASED DBUS_RELEASE_NAME_REPLY_RELEASED
#define NON_EXISTANT DBUS_RELEASE_NAME_REPLY_NON_EXISTENT
#define NOT_OWNER DBUS_RELEASE_NAME_REPLY_NOT_OWNER
#define NUM_CONN 4
#define TEST_NAME "org.freedesktop.DBus.TestSuite.NameTest"
#define NUM_TRIES_TIL_FAIL 15
extern const char *dbus_bus_connection_get_unique_name (DBusConnection *connection);
typedef struct {
int command;
int connection_number;
dbus_uint32_t flags;
dbus_uint32_t expected_result;
int expected_queue[NUM_CONN];
} CommandAndResult;
CommandAndResult test_data[] = {
{ADD_CONNECTION, 0, ALLOW_REPLACEMENT | REPLACE_EXISTING,
PRIMARY_OWNER, {0,-1,-1,-1}},
{ADD_CONNECTION, 0, REPLACE_EXISTING,
ALREADY_OWNER, {0,-1,-1,-1}},
{ADD_CONNECTION, 1, ALLOW_REPLACEMENT | REPLACE_EXISTING,
IN_QUEUE, {0,1,-1,-1}},
{REMOVE_CONNECTION, 0, 0,
RELEASED, {1,-1,-1,-1}},
{ADD_CONNECTION, 0, REPLACE_EXISTING | DO_NOT_QUEUE,
PRIMARY_OWNER, {0,1,-1,-1}},
{ADD_CONNECTION, 2, ALLOW_REPLACEMENT,
IN_QUEUE, {0,1,2,-1}},
{ADD_CONNECTION, 2, ALLOW_REPLACEMENT | REPLACE_EXISTING,
IN_QUEUE, {0,2,1,-1}},
{ADD_CONNECTION, 0, ALLOW_REPLACEMENT | DO_NOT_QUEUE,
ALREADY_OWNER, {0,2,1,-1}},
{ADD_CONNECTION, 1, ALLOW_REPLACEMENT | REPLACE_EXISTING,
PRIMARY_OWNER, {1,2,-1,-1}},
{ADD_CONNECTION, 0, REPLACE_EXISTING,
PRIMARY_OWNER, {0,1,2,-1}},
{ADD_CONNECTION, 2, DO_NOT_QUEUE,
EXISTS, {0,1,-1,-1}},
{REMOVE_CONNECTION, 2, 0,
NOT_OWNER, {0,1,-1,-1}},
{ADD_CONNECTION, 3, 0,
IN_QUEUE, {0,1,3,-1}},
{ADD_CONNECTION, 0, ALLOW_REPLACEMENT,
ALREADY_OWNER, {0,1,3,-1}},
{ADD_CONNECTION, 2, ALLOW_REPLACEMENT,
IN_QUEUE, {0,1,3,2}}
};
static dbus_bool_t
check_connection (DBusConnection *conn,
int iteration,
DBusConnection *uniq_conn[NUM_CONN])
{
DBusMessage *reply;
DBusMessage *method;
DBusError error;
char **list;
int len, i;
const char *name;
reply = NULL;
method = NULL;
list = NULL;
dbus_error_init (&error);
name = TEST_NAME;
method = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
DBUS_PATH_DBUS,
DBUS_INTERFACE_DBUS,
"ListQueuedOwners");
if (method == NULL)
goto out;
if (!dbus_message_append_args (method,
DBUS_TYPE_STRING, &name,
DBUS_TYPE_INVALID))
{
fprintf (stderr, "Error appending args\n") ;
goto out;
}
reply = dbus_connection_send_with_reply_and_block (conn,
method,
-1,
&error);
if (reply == NULL)
{
fprintf (stderr, "Error calling ListQueuedOwners: %s\n", error.message);
dbus_error_free (&error);
goto out;
}
if (!dbus_message_get_args (reply,
&error,
DBUS_TYPE_ARRAY, DBUS_TYPE_STRING,
&list, &len,
DBUS_TYPE_INVALID))
{
fprintf (stderr, "Error getting args: %s\n", error.message);
dbus_error_free (&error);
goto out;
}
printf ("Iteration %i: ", iteration);
if (len > NUM_CONN)
{
fprintf (stderr, "There are %i connections in the queue,"
" we are only expecting up to %i connections!\n",
len,
NUM_CONN);
goto out;
}
for (i = 0; i < len; i++)
{
int expected_conn_num;
const char *expected_uname;
if (i > 0)
printf (", ");
printf ("%s", list[i]);
expected_conn_num = test_data[iteration].expected_queue[i];
if (expected_conn_num == -1)
{
fprintf (stderr,
"\nDid not expect this last connection"
" to be in the queue!\n");
goto out;
}
expected_uname =
dbus_bus_connection_get_unique_name (uniq_conn[expected_conn_num]);
if (strcmp (list[i], expected_uname) != 0)
{
fprintf (stderr,
"\n%s expected but %s is in the queue!\n",
expected_uname,
list[i]);
goto out;
}
}
printf ("\n");
dbus_message_unref (method);
dbus_message_unref (reply);
dbus_free_string_array (list);
return TRUE;
out:
if (method != NULL)
dbus_message_unref (method);
if (reply != NULL)
dbus_message_unref (reply);
if (list != NULL)
dbus_free_string_array (list);
return FALSE;
}
static void
clear_message_queue (DBusConnection *conn)
{
int tries;
DBusMessage *msg;
for (tries = 0; tries < NUM_TRIES_TIL_FAIL; tries++)
{
_dbus_connection_lock (conn);
_dbus_connection_do_iteration_unlocked (conn,
DBUS_ITERATION_DO_READING |
DBUS_ITERATION_DO_WRITING |
DBUS_ITERATION_BLOCK,
0);
_dbus_connection_unlock (conn);
msg = dbus_connection_pop_message (conn);
}
}
static dbus_bool_t
match_acquired_or_lost_signal (DBusConnection *conn, const char *member, const char *name)
{
int tries;
DBusMessage *msg;
const char *interface = "org.freedesktop.DBus";
for (tries = 0; tries < NUM_TRIES_TIL_FAIL; tries++)
{
_dbus_connection_lock (conn);
_dbus_connection_do_iteration_unlocked (conn,
DBUS_ITERATION_DO_READING |
DBUS_ITERATION_DO_WRITING |
DBUS_ITERATION_BLOCK,
0);
_dbus_connection_unlock (conn);
msg = dbus_connection_pop_message (conn);
if (msg != NULL)
{
if (dbus_message_is_signal (msg,
interface,
member))
{
const char *n;
DBusError error;
dbus_error_init (&error);
dbus_message_get_args (msg, &error, DBUS_TYPE_STRING, &n, DBUS_TYPE_INVALID);
if (dbus_error_is_set (&error))
{
fprintf (stderr, "Error getting args: %s\n", error.message);
dbus_error_free (&error);
dbus_message_unref (msg);
return FALSE;
}
if (strcmp (n, name) == 0)
{
dbus_message_unref (msg);
break;
}
}
dbus_message_unref (msg);
}
}
if (tries == NUM_TRIES_TIL_FAIL)
{
fprintf (stderr, "Did not recive the expected %s.%s signal!!!\n", interface, member);
return FALSE;
}
return TRUE;
}
static dbus_bool_t
match_name_owner_changed_signal (DBusConnection *conn, const char *bus_name, const char *lost_name, const char *acquired_name)
{
int tries;
DBusMessage *msg;
for (tries = 0; tries < NUM_TRIES_TIL_FAIL; tries++)
{
_dbus_connection_lock (conn);
_dbus_connection_do_iteration_unlocked (conn,
DBUS_ITERATION_DO_READING |
DBUS_ITERATION_DO_WRITING |
DBUS_ITERATION_BLOCK,
0);
_dbus_connection_unlock (conn);
msg = dbus_connection_pop_message (conn);
if (msg != NULL)
{
if (dbus_message_is_signal (msg,
"org.freedesktop.DBus",
"NameOwnerChanged"))
{
const char *n;
const char *ln;
const char *an;
DBusError error;
dbus_error_init (&error);
dbus_message_get_args (msg, &error, DBUS_TYPE_STRING, &n, DBUS_TYPE_STRING, &ln, DBUS_TYPE_STRING, &an, DBUS_TYPE_INVALID);
if (dbus_error_is_set (&error))
{
fprintf (stderr, "Error getting args: %s\n", error.message);
dbus_error_free (&error);
dbus_message_unref (msg);
return FALSE;
}
if (strcmp (n, bus_name) == 0)
{
if ((lost_name == NULL && strcmp (ln, "") == 0)
|| strcmp (lost_name, ln) == 0)
{
if ((acquired_name == NULL && strcmp (an, "") == 0)
|| strcmp (acquired_name, an) == 0)
{
dbus_message_unref (msg);
break;
}
else
{
fprintf (stderr, "Error: name %s was expected to be acquired but we got %s instead\n", acquired_name, an);
dbus_message_unref (msg);
return FALSE;
}
}
else
{
fprintf (stderr, "Error: name %s was expected to be lost but we got %s instead\n", lost_name, ln);
dbus_message_unref (msg);
return FALSE;
}
}
}
dbus_message_unref (msg);
}
}
if (tries == NUM_TRIES_TIL_FAIL)
{
fprintf (stderr, "Did not recive the expected NameOwnerChanged signal!!!\n");
return FALSE;
}
return TRUE;
}
static dbus_bool_t
check_signals (DBusConnection *monitor,
int iteration,
DBusConnection *conn[NUM_CONN])
{
DBusConnection *lost_conn = NULL;
DBusConnection *acquired_conn = NULL;
const char *lost_name;
const char *acquired_name;
if (iteration == 0)
{
int i;
i = test_data[iteration].expected_queue[0];
if (i >= 0)
acquired_conn = conn[i];
}
else
{
int i;
i = test_data[iteration - 1].expected_queue[0];
if (i >= 0)
lost_conn = conn[i];
i = test_data[iteration].expected_queue[0];
if (i >= 0)
acquired_conn = conn[i];
if (acquired_conn == lost_conn)
acquired_conn = lost_conn = NULL;
}
lost_name = lost_conn == NULL? NULL :
dbus_bus_connection_get_unique_name (lost_conn);
acquired_name = acquired_conn == NULL? NULL :
dbus_bus_connection_get_unique_name (acquired_conn);
if (lost_name != NULL)
if (!match_acquired_or_lost_signal (lost_conn,
"NameLost",
TEST_NAME))
return FALSE;
if (acquired_name != NULL)
if (!match_acquired_or_lost_signal (acquired_conn,
"NameAcquired",
TEST_NAME))
return FALSE;
if (acquired_name != NULL || lost_name != NULL)
if (!match_name_owner_changed_signal (monitor,
TEST_NAME,
lost_name,
acquired_name))
return FALSE;
return TRUE;
}
int
main (int argc, char *argv[])
{
DBusConnection *conn[NUM_CONN];
DBusConnection *monitor;
DBusError error;
int i;
int test_data_len;
test_data_len = sizeof (test_data) / sizeof (CommandAndResult);
dbus_error_init (&error);
conn[0] = dbus_bus_get_private (DBUS_BUS_SESSION, &error);
if (dbus_error_is_set (&error))
{
fprintf (stderr, "*** Failed to open connection 0 to session bus: %s\n",
error.message);
dbus_error_free (&error);
return 1;
}
if (!match_acquired_or_lost_signal (conn[0],
"NameAcquired",
dbus_bus_connection_get_unique_name (conn[0])))
return 1;
conn[1] = dbus_bus_get_private (DBUS_BUS_SESSION, &error);
if (dbus_error_is_set (&error))
{
fprintf (stderr, "*** Failed to open connection 1 to session bus: %s\n",
error.message);
dbus_error_free (&error);
return 1;
}
if (!match_acquired_or_lost_signal (conn[1],
"NameAcquired",
dbus_bus_connection_get_unique_name (conn[1])))
return 1;
conn[2] = dbus_bus_get_private (DBUS_BUS_SESSION, &error);
if (dbus_error_is_set (&error))
{
fprintf (stderr, "*** Failed to open connection 2 to session bus: %s\n",
error.message);
dbus_error_free (&error);
return 1;
}
if (!match_acquired_or_lost_signal (conn[2],
"NameAcquired",
dbus_bus_connection_get_unique_name (conn[2])))
return 1;
conn[3] = dbus_bus_get_private (DBUS_BUS_SESSION, &error);
if (dbus_error_is_set (&error))
{
fprintf (stderr, "*** Failed to open connection 3 to session bus: %s\n",
error.message);
dbus_error_free (&error);
return 1;
}
if (!match_acquired_or_lost_signal (conn[3],
"NameAcquired",
dbus_bus_connection_get_unique_name (conn[3])))
return 1;
monitor = dbus_bus_get (DBUS_BUS_SESSION, &error);
if (dbus_error_is_set (&error))
{
fprintf (stderr, "*** Failed to open monitoring connection to session bus: %s\n",
error.message);
dbus_error_free (&error);
return 1;
}
if (!match_acquired_or_lost_signal (monitor,
"NameAcquired",
dbus_bus_connection_get_unique_name (monitor)))
return 1;
dbus_bus_add_match (monitor, "", &error);
if (dbus_error_is_set (&error))
{
fprintf (stderr, "*** Failed to set filter on monitoring connection: %s\n",
error.message);
dbus_error_free (&error);
return 1;
}
for (i = 0; i < NUM_CONN; i++)
dbus_connection_set_exit_on_disconnect (conn[i], FALSE);
for (i = 0; i < test_data_len; i++)
{
dbus_uint32_t result;
result = 0;
if (test_data[i].command == ADD_CONNECTION)
{
result = dbus_bus_request_name (conn[test_data[i].connection_number],
TEST_NAME,
test_data[i].flags,
&error);
if (dbus_error_is_set (&error))
{
fprintf (stderr, "Error on addition in iteration %i: %s\n", i, error.message);
dbus_error_free (&error);
return 1;
}
}
else if (test_data[i].command == REMOVE_CONNECTION)
{
result = dbus_bus_release_name (conn[test_data[i].connection_number],
TEST_NAME,
&error);
if (dbus_error_is_set (&error))
{
fprintf (stderr, "*** Failed to remove connection %i in iteration %i: %s\n",
test_data[i].connection_number,
i,
error.message);
dbus_error_free (&error);
return 1;
}
}
else
{
fprintf (stderr, "Command #%i not a valid command!\n", test_data[i].command);
return 1;
}
if (result != test_data[i].expected_result)
{
fprintf (stderr, "Results recived (%i) are not the expected results (%i) in iteration %i\n",
result,
test_data[i].expected_result,
i);
return 1;
}
if (!check_connection (monitor, i, conn))
{
fprintf (stderr, "Failed at iteration %i\n", i);
return 1;
}
if (!check_signals (monitor, i, conn))
{
fprintf (stderr, "Failed at iteration %i\n", i);
return 1;
}
}
return 0;
}