diff options
| author | John (J5) Palmieri <johnp@redhat.com> | 2005-11-22 20:37:00 +0000 | 
|---|---|---|
| committer | John (J5) Palmieri <johnp@redhat.com> | 2005-11-22 20:37:00 +0000 | 
| commit | 1a163e765c0d6a86d2aa2ffb18a1d7e29a052e7a (patch) | |
| tree | f03b91de2eea70ffcb02aebcb265e3552dd9e48d | |
| parent | c33af17b934fcc8528b393ed2dca603e4940e6b3 (diff) | |
	* 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
| -rw-r--r-- | ChangeLog | 103 | ||||
| -rw-r--r-- | bus/activation.c | 2 | ||||
| -rw-r--r-- | bus/bus.h | 1 | ||||
| -rw-r--r-- | bus/dispatch.c | 2 | ||||
| -rw-r--r-- | bus/driver.c | 123 | ||||
| -rw-r--r-- | bus/services.c | 538 | ||||
| -rw-r--r-- | bus/services.h | 45 | ||||
| -rw-r--r-- | bus/signals.c | 2 | ||||
| -rw-r--r-- | configure.in | 1 | ||||
| -rw-r--r-- | dbus/dbus-bus.c | 47 | ||||
| -rw-r--r-- | dbus/dbus-glib-lowlevel.h | 7 | ||||
| -rw-r--r-- | dbus/dbus-shared.h | 5 | ||||
| -rw-r--r-- | dbus/dbus-sysdeps.c | 55 | ||||
| -rw-r--r-- | doc/TODO | 5 | ||||
| -rw-r--r-- | doc/dbus-specification.xml | 162 | ||||
| -rw-r--r-- | glib/dbus-gobject.c | 28 | ||||
| -rw-r--r-- | glib/examples/example-service.c | 2 | ||||
| -rw-r--r-- | glib/examples/example-signal-emitter.c | 2 | ||||
| -rw-r--r-- | glib/examples/statemachine/statemachine-server.c | 2 | ||||
| -rw-r--r-- | test/Makefile.am | 4 | ||||
| -rw-r--r-- | test/name-test/Makefile.am | 26 | ||||
| -rwxr-xr-x | test/name-test/run-test.sh | 30 | ||||
| -rw-r--r-- | test/name-test/test-names.c | 578 | 
23 files changed, 1584 insertions, 186 deletions
| @@ -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 diff --git a/bus/activation.c b/bus/activation.c index 43a135fc..1cdedb9f 100644 --- a/bus/activation.c +++ b/bus/activation.c @@ -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. @@ -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; diff --git a/bus/dispatch.c b/bus/dispatch.c index aae7f707..526c0182 100644 --- a/bus/dispatch.c +++ b/bus/dispatch.c @@ -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, diff --git a/bus/driver.c b/bus/driver.c index bc63e7c2..10f37bd2 100644 --- a/bus/driver.c +++ b/bus/driver.c @@ -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? */ @@ -924,6 +922,113 @@ bus_driver_handle_get_service_owner (DBusConnection *connection,  }  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,                                              DBusMessage    *message, @@ -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, diff --git a/bus/services.c b/bus/services.c index 87feab2f..52f522b4 100644 --- a/bus/services.c +++ b/bus/services.c @@ -42,8 +42,17 @@ struct BusService    BusRegistry *registry;    char *name;    DBusList *owners; -   -  unsigned int prohibit_replacement : 1; +}; + +struct BusOwner +{ +  int refcount; + +  BusService *service; +  DBusConnection *conn; + +  unsigned int allow_replacement : 1; +  unsigned int do_not_queue : 1;  };  struct BusRegistry @@ -54,6 +63,7 @@ struct BusRegistry    DBusHashTable *service_hash;    DBusMemPool   *service_pool; +  DBusMemPool   *owner_pool;    DBusHashTable *service_sid_table;  }; @@ -77,9 +87,16 @@ bus_registry_new (BusContext *context)    registry->service_pool = _dbus_mem_pool_new (sizeof (BusService),                                                 TRUE); +    if (registry->service_pool == NULL)      goto failed; +  registry->owner_pool = _dbus_mem_pool_new (sizeof (BusOwner), +                                             TRUE); + +  if (registry->owner_pool == NULL) +    goto failed; +    registry->service_sid_table = NULL;    return registry; @@ -110,6 +127,8 @@ bus_registry_unref  (BusRegistry *registry)          _dbus_hash_table_unref (registry->service_hash);        if (registry->service_pool)          _dbus_mem_pool_free (registry->service_pool); +      if (registry->owner_pool) +        _dbus_mem_pool_free (registry->owner_pool);        if (registry->service_sid_table)          _dbus_hash_table_unref (registry->service_sid_table); @@ -129,10 +148,98 @@ bus_registry_lookup (BusRegistry      *registry,    return service;  } +static DBusList * +_bus_service_find_owner_link (BusService *service, +                              DBusConnection *connection) +{ +  DBusList *link; +   +  link = _dbus_list_get_first_link (&service->owners); + +  while (link != NULL) +    { +      BusOwner *bus_owner; + +      bus_owner = (BusOwner *) link->data; +      if (bus_owner->conn == connection)  +        break; + +      link = _dbus_list_get_next_link (&service->owners, link); +    } + +  return link; +} + +static void +bus_owner_set_flags (BusOwner *owner, +                     dbus_uint32_t flags) +{ +   owner->allow_replacement =  +        (flags & DBUS_NAME_FLAG_ALLOW_REPLACEMENT) != FALSE; + +   owner->do_not_queue = +        (flags & DBUS_NAME_FLAG_DO_NOT_QUEUE) != FALSE; +} + +static BusOwner * +bus_owner_new (BusService *service,  +               DBusConnection *conn,  +	       dbus_uint32_t flags) +{ +  BusOwner *result; + +  result = _dbus_mem_pool_alloc (service->registry->owner_pool); +  if (result != NULL) +    { +      result->refcount = 1; +      /* don't ref the connection because we don't want +         to block the connection from going away. +         transactions take care of reffing the connection +         but we need to use refcounting on the owner +         so that the owner does not get freed before +         we can deref the connection in the transaction +       */ +      result->conn = conn; +      result->service = service; + +      if (!bus_connection_add_owned_service (conn, service)) +        { +          _dbus_mem_pool_dealloc (service->registry->owner_pool, result); +          return NULL; +        } +         +      bus_owner_set_flags (result, flags); +    } +  return result; +} + +static BusOwner * +bus_owner_ref (BusOwner *owner) +{ +  _dbus_assert (owner->refcount > 0); +  owner->refcount += 1; + +  return owner; +} + +static void +bus_owner_unref  (BusOwner *owner) +{ +  _dbus_assert (owner->refcount > 0); +  owner->refcount -= 1; + +  if (owner->refcount == 0) +    { +      bus_connection_remove_owned_service (owner->conn, owner->service); +      _dbus_mem_pool_dealloc (owner->service->registry->owner_pool, owner); +    } +} +  BusService*  bus_registry_ensure (BusRegistry               *registry,                       const DBusString          *service_name, -                     DBusConnection            *owner_if_created, +                     DBusConnection            *owner_connection_if_created, +                     dbus_uint32_t              flags,                       BusTransaction            *transaction,                       DBusError                 *error)  { @@ -140,7 +247,7 @@ bus_registry_ensure (BusRegistry               *registry,    _DBUS_ASSERT_ERROR_IS_CLEAR (error); -  _dbus_assert (owner_if_created != NULL); +  _dbus_assert (owner_connection_if_created != NULL);    _dbus_assert (transaction != NULL);    service = _dbus_hash_table_lookup_string (registry->service_hash, @@ -172,7 +279,7 @@ bus_registry_ensure (BusRegistry               *registry,    if (!bus_driver_send_service_owner_changed (service->name,   					      NULL, -					      bus_connection_get_name (owner_if_created), +					      bus_connection_get_name (owner_connection_if_created),  					      transaction, error))      {        bus_service_unref (service); @@ -186,8 +293,8 @@ bus_registry_ensure (BusRegistry               *registry,        return NULL;      } -  if (!bus_service_add_owner (service, owner_if_created, -                              transaction, error)) +  if (!bus_service_add_owner (service, owner_connection_if_created, flags, +                                              transaction, error))      {        bus_service_unref (service);        return NULL; @@ -275,13 +382,14 @@ bus_registry_acquire_service (BusRegistry      *registry,                                DBusError        *error)  {    dbus_bool_t retval; -  DBusConnection *old_owner; -  DBusConnection *current_owner; +  DBusConnection *old_owner_conn; +  DBusConnection *current_owner_conn;    BusClientPolicy *policy;    BusService *service;    BusActivation  *activation;    BusSELinuxID *sid; -   +  BusOwner *primary_owner; +     retval = FALSE;    if (!_dbus_validate_bus_name (service_name, 0, @@ -366,37 +474,70 @@ bus_registry_acquire_service (BusRegistry      *registry,    service = bus_registry_lookup (registry, service_name);    if (service != NULL) -    old_owner = bus_service_get_primary_owner (service); +    { +      primary_owner = bus_service_get_primary_owner (service); +      if (primary_owner != NULL) +        old_owner_conn = primary_owner->conn; +      else +        old_owner_conn = NULL; +    }    else -    old_owner = NULL; +    old_owner_conn = NULL;    if (service == NULL)      {        service = bus_registry_ensure (registry, -                                     service_name, connection, transaction, error); +                                     service_name, connection, flags, +                                     transaction, error);        if (service == NULL)          goto out;      } -  current_owner = bus_service_get_primary_owner (service); - -  if (old_owner == NULL) +  primary_owner = bus_service_get_primary_owner (service); +  if (primary_owner == NULL) +    goto out; +     +  current_owner_conn = primary_owner->conn; +      +  if (old_owner_conn == NULL)      { -      _dbus_assert (current_owner == connection); +      _dbus_assert (current_owner_conn == connection); -      bus_service_set_prohibit_replacement (service, -					    (flags & DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT));       -			        *result = DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER;            } -  else if (old_owner == connection) -    *result = DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER; -  else if (!((flags & DBUS_NAME_FLAG_REPLACE_EXISTING))) -    *result = DBUS_REQUEST_NAME_REPLY_EXISTS; -  else if (bus_service_get_prohibit_replacement (service)) +  else if (old_owner_conn == connection) +    { +      bus_owner_set_flags (primary_owner, flags); +      *result = DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER; +    } +  else if (((flags & DBUS_NAME_FLAG_DO_NOT_QUEUE) && +           !(bus_service_get_allow_replacement (service))) || +	   ((flags & DBUS_NAME_FLAG_DO_NOT_QUEUE) && +           !(flags & DBUS_NAME_FLAG_REPLACE_EXISTING)))  +    { +      DBusList *link; +      BusOwner *temp_owner; +    /* Since we can't be queued if we are already in the queue +       remove us */ + +      link = _bus_service_find_owner_link (service, connection); +      if (link != NULL) +        { +          _dbus_list_unlink (&service->owners, link); +          temp_owner = (BusOwner *)link->data; +          bus_owner_unref (temp_owner);  +          _dbus_list_free_link (link); +        } +       +      *result = DBUS_REQUEST_NAME_REPLY_EXISTS; +    } +  else if (!(flags & DBUS_NAME_FLAG_DO_NOT_QUEUE) && +           (!(flags & DBUS_NAME_FLAG_REPLACE_EXISTING) || +	    !(bus_service_get_allow_replacement (service))))      {        /* Queue the connection */ -      if (!bus_service_add_owner (service, connection, +      if (!bus_service_add_owner (service, connection,  +                                  flags,                                    transaction, error))          goto out; @@ -412,14 +553,25 @@ bus_registry_acquire_service (BusRegistry      *registry,         */        if (!bus_service_add_owner (service, connection, +                                  flags,                                    transaction, error))          goto out; -      if (!bus_service_remove_owner (service, old_owner, -                                     transaction, error)) -        goto out; -       -      _dbus_assert (connection == bus_service_get_primary_owner (service)); +      if (primary_owner->do_not_queue) +        { +          if (!bus_service_remove_owner (service, old_owner_conn, +                                         transaction, error)) +            goto out; +        } +      else +        { +          if (!bus_service_swap_owner (service, old_owner_conn, +                                       transaction, error)) +            goto out; +        } +         +     +      _dbus_assert (connection == bus_service_get_primary_owner (service)->conn);        *result = DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER;      } @@ -528,10 +680,10 @@ bus_registry_set_service_context_table (BusRegistry   *registry,  static void  bus_service_unlink_owner (BusService      *service, -                          DBusConnection  *owner) +                          BusOwner        *owner)  {    _dbus_list_remove_last (&service->owners, owner); -  bus_connection_remove_owned_service (owner, service); +  bus_owner_unref (owner);  }  static void @@ -570,7 +722,7 @@ bus_service_relink (BusService           *service,   */  typedef struct  { -  DBusConnection *connection; /**< the connection */ +  BusOwner *owner;            /**< the owner */    BusService *service;        /**< service to cancel ownership of */  } OwnershipCancelData; @@ -583,7 +735,7 @@ cancel_ownership (void *data)     * changes, since we're reverting something that was     * cancelled (effectively never really happened)     */ -  bus_service_unlink_owner (d->service, d->connection); +  bus_service_unlink_owner (d->service, d->owner);    if (d->service->owners == NULL)      bus_service_unlink (d->service); @@ -594,7 +746,8 @@ free_ownership_cancel_data (void *data)  {    OwnershipCancelData *d = data; -  dbus_connection_unref (d->connection); +  dbus_connection_unref (d->owner->conn); +  bus_owner_unref (d->owner);    bus_service_unref (d->service);    dbus_free (d); @@ -603,7 +756,7 @@ free_ownership_cancel_data (void *data)  static dbus_bool_t  add_cancel_ownership_to_transaction (BusTransaction *transaction,                                       BusService     *service, -                                     DBusConnection *connection) +                                     BusOwner       *owner)  {    OwnershipCancelData *d; @@ -612,7 +765,7 @@ add_cancel_ownership_to_transaction (BusTransaction *transaction,      return FALSE;    d->service = service; -  d->connection = connection; +  d->owner = owner;    if (!bus_transaction_add_cancel_hook (transaction, cancel_ownership, d,                                          free_ownership_cancel_data)) @@ -622,18 +775,23 @@ add_cancel_ownership_to_transaction (BusTransaction *transaction,      }    bus_service_ref (d->service); -  dbus_connection_ref (d->connection); -   +  bus_owner_ref (owner); +  dbus_connection_ref (d->owner->conn); +     return TRUE;  }  /* this function is self-cancelling if you cancel the transaction */  dbus_bool_t  bus_service_add_owner (BusService     *service, -                       DBusConnection *owner, +                       DBusConnection *connection, +                       dbus_uint32_t  flags,                         BusTransaction *transaction,                         DBusError      *error)  { +  BusOwner *bus_owner; +  DBusList *bus_owner_link; +      _DBUS_ASSERT_ERROR_IS_CLEAR (error);   /* Send service acquired message first, OOM will result @@ -641,42 +799,83 @@ bus_service_add_owner (BusService     *service,    */    if (service->owners == NULL)      { -      if (!bus_driver_send_service_acquired (owner, service->name, transaction, error)) +      if (!bus_driver_send_service_acquired (connection, service->name, transaction, error))          return FALSE;      } -  if (!_dbus_list_append (&service->owners, -                          owner)) +  bus_owner_link = _bus_service_find_owner_link (service, connection); +   +  if (bus_owner_link == NULL)      { -      BUS_SET_OOM (error); -      return FALSE; -    } +      bus_owner = bus_owner_new (service, connection, flags); +      if (bus_owner == NULL) +        { +          BUS_SET_OOM (error); +          return FALSE; +        } -  if (!bus_connection_add_owned_service (owner, service)) +      bus_owner_set_flags (bus_owner, flags); +      if (!(flags & DBUS_NAME_FLAG_REPLACE_EXISTING) || service->owners == NULL) +        { +          if (!_dbus_list_append (&service->owners, +                                  bus_owner)) +            { +              bus_owner_unref (bus_owner); +              BUS_SET_OOM (error); +              return FALSE; +            } +        } +      else +        { +          if (!_dbus_list_insert_after (&service->owners, +                                         _dbus_list_get_first_link (&service->owners), +                                         bus_owner)) +            { +              bus_owner_unref (bus_owner); +              BUS_SET_OOM (error); +              return FALSE; +            } +        }       +    }  +  else       { -      _dbus_list_remove_last (&service->owners, owner); -      BUS_SET_OOM (error); -      return FALSE; +      /* Update the link since we are already in the queue +       * No need for operations that can produce OOM +       */ + +      bus_owner = (BusOwner *) bus_owner_link->data; +      if (flags & DBUS_NAME_FLAG_REPLACE_EXISTING) +        { +	  DBusList *link; +          _dbus_list_unlink (&service->owners, bus_owner_link); +	  link = _dbus_list_get_first_link (&service->owners); +	  _dbus_assert (link != NULL); +	   +          _dbus_list_insert_after_link (&service->owners, link, bus_owner_link); +        } +       +      bus_owner_set_flags (bus_owner, flags); +      return TRUE;      }    if (!add_cancel_ownership_to_transaction (transaction,                                              service, -                                            owner)) +                                            bus_owner))      { -      bus_service_unlink_owner (service, owner); +      bus_service_unlink_owner (service, bus_owner);        BUS_SET_OOM (error);        return FALSE;      } -   +    return TRUE;  }  typedef struct  { -  DBusConnection *connection; +  BusOwner       *owner;    BusService     *service; -  DBusConnection *before_connection; /* restore to position before this connection in owners list */ -  DBusList       *connection_link; +  BusOwner       *before_owner; /* restore to position before this connection in owners list */ +  DBusList       *owner_link;    DBusList       *service_link;    DBusPreallocatedHash *hash_entry;  } OwnershipRestoreData; @@ -688,7 +887,7 @@ restore_ownership (void *data)    DBusList *link;    _dbus_assert (d->service_link != NULL); -  _dbus_assert (d->connection_link != NULL); +  _dbus_assert (d->owner_link != NULL);    if (d->service->owners == NULL)      { @@ -707,13 +906,13 @@ restore_ownership (void *data)    link = _dbus_list_get_first_link (&d->service->owners);    while (link != NULL)      { -      if (link->data == d->before_connection) +      if (link->data == d->before_owner)          break;        link = _dbus_list_get_next_link (&d->service->owners, link);      } -  _dbus_list_insert_before_link (&d->service->owners, link, d->connection_link); +  _dbus_list_insert_before_link (&d->service->owners, link, d->owner_link);    /* Note that removing then restoring this changes the order in which     * ServiceDeleted messages are sent on destruction of the @@ -721,11 +920,11 @@ restore_ownership (void *data)     * that the base service is destroyed last, and we never even     * tentatively remove the base service.     */ -  bus_connection_add_owned_service_link (d->connection, d->service_link); +  bus_connection_add_owned_service_link (d->owner->conn, d->service_link);    d->hash_entry = NULL;    d->service_link = NULL; -  d->connection_link = NULL; +  d->owner_link = NULL;  }  static void @@ -735,13 +934,14 @@ free_ownership_restore_data (void *data)    if (d->service_link)      _dbus_list_free_link (d->service_link); -  if (d->connection_link) -    _dbus_list_free_link (d->connection_link); +  if (d->owner_link) +    _dbus_list_free_link (d->owner_link);    if (d->hash_entry)      _dbus_hash_table_free_preallocated_entry (d->service->registry->service_hash,                                                d->hash_entry); -  dbus_connection_unref (d->connection); +  dbus_connection_unref (d->owner->conn); +  bus_owner_unref (d->owner);    bus_service_unref (d->service);    dbus_free (d); @@ -750,7 +950,7 @@ free_ownership_restore_data (void *data)  static dbus_bool_t  add_restore_ownership_to_transaction (BusTransaction *transaction,                                        BusService     *service, -                                      DBusConnection *connection) +                                      BusOwner       *owner)  {    OwnershipRestoreData *d;    DBusList *link; @@ -760,24 +960,25 @@ add_restore_ownership_to_transaction (BusTransaction *transaction,      return FALSE;    d->service = service; -  d->connection = connection; +  d->owner = owner;    d->service_link = _dbus_list_alloc_link (service); -  d->connection_link = _dbus_list_alloc_link (connection); +  d->owner_link = _dbus_list_alloc_link (owner);    d->hash_entry = _dbus_hash_table_preallocate_entry (service->registry->service_hash);    bus_service_ref (d->service); -  dbus_connection_ref (d->connection); +  bus_owner_ref (d->owner); +  dbus_connection_ref (d->owner->conn); -  d->before_connection = NULL; +  d->before_owner = NULL;    link = _dbus_list_get_first_link (&service->owners);    while (link != NULL)      { -      if (link->data == connection) +      if (link->data == owner)          {            link = _dbus_list_get_next_link (&service->owners, link);            if (link) -            d->before_connection = link->data; +            d->before_owner = link->data;            break;          } @@ -786,7 +987,7 @@ add_restore_ownership_to_transaction (BusTransaction *transaction,      }    if (d->service_link == NULL || -      d->connection_link == NULL || +      d->owner_link == NULL ||        d->hash_entry == NULL ||        !bus_transaction_add_cancel_hook (transaction, restore_ownership, d,                                          free_ownership_restore_data)) @@ -798,13 +999,92 @@ add_restore_ownership_to_transaction (BusTransaction *transaction,    return TRUE;  } +dbus_bool_t +bus_service_swap_owner (BusService     *service, +                        DBusConnection *connection, +                        BusTransaction *transaction, +                        DBusError      *error) +{ +  DBusList *swap_link; +  BusOwner *primary_owner; + +  _DBUS_ASSERT_ERROR_IS_CLEAR (error); + +  /* We send out notifications before we do any work we +   * might have to undo if the notification-sending failed +   */ +   +  /* Send service lost message */ +  primary_owner = bus_service_get_primary_owner (service); +  if (primary_owner == NULL || primary_owner->conn != connection) +    _dbus_assert_not_reached ("Tried to swap a non primary owner"); + +     +  if (!bus_driver_send_service_lost (connection, service->name, +                                     transaction, error)) +    return FALSE; + +  if (service->owners == NULL) +    { +      _dbus_assert_not_reached ("Tried to swap owner of a service that has no owners"); +    } +  else if (_dbus_list_length_is_one (&service->owners)) +    { +      _dbus_assert_not_reached ("Tried to swap owner of a service that has no other owners in the queue"); +    } +  else +    { +      DBusList *link; +      BusOwner *new_owner; +      DBusConnection *new_owner_conn; +      link = _dbus_list_get_first_link (&service->owners); +      _dbus_assert (link != NULL); +      link = _dbus_list_get_next_link (&service->owners, link); +      _dbus_assert (link != NULL); + +      new_owner = (BusOwner *)link->data; +      new_owner_conn = new_owner->conn; + +      if (!bus_driver_send_service_owner_changed (service->name, + 						  bus_connection_get_name (connection), + 						  bus_connection_get_name (new_owner_conn), + 						  transaction, error)) +        return FALSE; + +      /* This will be our new owner */ +      if (!bus_driver_send_service_acquired (new_owner_conn, +                                             service->name, +                                             transaction, +                                             error)) +        return FALSE; +    } + +  if (!add_restore_ownership_to_transaction (transaction, service, primary_owner)) +    { +      BUS_SET_OOM (error); +      return FALSE; +    } + +  /* unlink the primary and make it the second link */ +  swap_link = _dbus_list_get_first_link (&service->owners); +  _dbus_list_unlink (&service->owners, swap_link); + +  _dbus_list_insert_after_link (&service->owners, +                                _dbus_list_get_first_link (&service->owners), +				swap_link); + +  return TRUE; +} +  /* this function is self-cancelling if you cancel the transaction */  dbus_bool_t  bus_service_remove_owner (BusService     *service, -                          DBusConnection *owner, +                          DBusConnection *connection,                            BusTransaction *transaction,                            DBusError      *error)  { +  BusOwner *primary_owner; +      _DBUS_ASSERT_ERROR_IS_CLEAR (error);    /* We send out notifications before we do any work we @@ -812,12 +1092,27 @@ bus_service_remove_owner (BusService     *service,     */    /* Send service lost message */ -  if (bus_service_get_primary_owner (service) == owner) +  primary_owner = bus_service_get_primary_owner (service); +  if (primary_owner != NULL && primary_owner->conn == connection)      { -      if (!bus_driver_send_service_lost (owner, service->name, +      if (!bus_driver_send_service_lost (connection, service->name,                                           transaction, error))          return FALSE;      } +  else +    { +      /* if we are not the primary owner then just remove us from the queue */ +      DBusList *link; +      BusOwner *temp_owner; + +      link = _bus_service_find_owner_link (service, connection); +      _dbus_list_unlink (&service->owners, link); +      temp_owner = (BusOwner *)link->data; +      bus_owner_unref (temp_owner);  +      _dbus_list_free_link (link); + +      return TRUE;  +    }    if (service->owners == NULL)      { @@ -826,7 +1121,7 @@ bus_service_remove_owner (BusService     *service,    else if (_dbus_list_length_is_one (&service->owners))      {        if (!bus_driver_send_service_owner_changed (service->name, - 						  bus_connection_get_name (owner), + 						  bus_connection_get_name (connection),   						  NULL,   						  transaction, error))          return FALSE; @@ -834,35 +1129,37 @@ bus_service_remove_owner (BusService     *service,    else      {        DBusList *link; -      DBusConnection *new_owner; +      BusOwner *new_owner; +      DBusConnection *new_owner_conn;        link = _dbus_list_get_first_link (&service->owners);        _dbus_assert (link != NULL);        link = _dbus_list_get_next_link (&service->owners, link);        _dbus_assert (link != NULL); -      new_owner = link->data; +      new_owner = (BusOwner *)link->data; +      new_owner_conn = new_owner->conn;        if (!bus_driver_send_service_owner_changed (service->name, - 						  bus_connection_get_name (owner), - 						  bus_connection_get_name (new_owner), + 						  bus_connection_get_name (connection), + 						  bus_connection_get_name (new_owner_conn),   						  transaction, error))          return FALSE;        /* This will be our new owner */ -      if (!bus_driver_send_service_acquired (new_owner, +      if (!bus_driver_send_service_acquired (new_owner_conn,                                               service->name,                                               transaction,                                               error))          return FALSE;      } -  if (!add_restore_ownership_to_transaction (transaction, service, owner)) +  if (!add_restore_ownership_to_transaction (transaction, service, primary_owner))      {        BUS_SET_OOM (error);        return FALSE;      } -   -  bus_service_unlink_owner (service, owner); +  +  bus_service_unlink_owner (service, primary_owner);    if (service->owners == NULL)      bus_service_unlink (service); @@ -896,7 +1193,20 @@ bus_service_unref (BusService *service)      }  } -DBusConnection* +DBusConnection * +bus_service_get_primary_owners_connection (BusService *service) +{ +  BusOwner *owner; + +  owner = bus_service_get_primary_owner (service); + +  if (owner != NULL) +    return owner->conn; +  else +    return NULL; +} + +BusOwner*  bus_service_get_primary_owner (BusService *service)  {    return _dbus_list_get_first (&service->owners); @@ -908,34 +1218,64 @@ bus_service_get_name (BusService *service)    return service->name;  } -void -bus_service_set_prohibit_replacement (BusService  *service, -				      dbus_bool_t  prohibit_replacement) +dbus_bool_t +bus_service_get_allow_replacement (BusService *service)  { -  service->prohibit_replacement = prohibit_replacement != FALSE; +  BusOwner *owner; +  DBusList *link; +  +  _dbus_assert (service->owners != NULL); + +  link = _dbus_list_get_first_link (&service->owners); +  owner = (BusOwner *) link->data; + +  return owner->allow_replacement;  }  dbus_bool_t -bus_service_get_prohibit_replacement (BusService *service) +bus_service_has_owner (BusService     *service, +		       DBusConnection *connection)  { -  return service->prohibit_replacement; +  DBusList *link; + +  link = _bus_service_find_owner_link (service, connection); +  +  if (link == NULL) +    return FALSE; +  else +    return TRUE;  } -dbus_bool_t -bus_service_has_owner (BusService     *service, -		       DBusConnection *owner) +dbus_bool_t  +bus_service_list_queued_owners (BusService *service, +                                DBusList  **return_list, +                                DBusError  *error)  {    DBusList *link; +  _dbus_assert (*return_list == NULL); +    link = _dbus_list_get_first_link (&service->owners); +  _dbus_assert (link != NULL);    while (link != NULL)      { -      if (link->data == owner) -	return TRUE; -       +      BusOwner *owner; +      const char *uname; + +      owner = (BusOwner *) link->data; +      uname = bus_connection_get_name (owner->conn); + +      if (!_dbus_list_append (return_list, uname)) +        goto oom; +        link = _dbus_list_get_next_link (&service->owners, link);      } - +   +  return TRUE; +   + oom: +  _dbus_list_clear (return_list); +  BUS_SET_OOM (error);    return FALSE;  } diff --git a/bus/services.h b/bus/services.h index d4b3d833..1527fb9a 100644 --- a/bus/services.h +++ b/bus/services.h @@ -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 */ diff --git a/bus/signals.c b/bus/signals.c index caeb31da..abc38770 100644 --- a/bus/signals.c +++ b/bus/signals.c @@ -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 diff --git a/configure.in b/configure.in index 1a826543..2e7617e3 100644 --- a/configure.in +++ b/configure.in @@ -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 diff --git a/dbus/dbus-bus.c b/dbus/dbus-bus.c index 9016f1b1..7578efb2 100644 --- a/dbus/dbus-bus.c +++ b/dbus/dbus-bus.c @@ -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 */ + +  /** @} */ diff --git a/dbus/dbus-glib-lowlevel.h b/dbus/dbus-glib-lowlevel.h index 9f6fc84e..cb015ccb 100644 --- a/dbus/dbus-glib-lowlevel.h +++ b/dbus/dbus-glib-lowlevel.h @@ -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 diff --git a/dbus/dbus-shared.h b/dbus/dbus-shared.h index a8519c13..2ef1dc9c 100644 --- a/dbus/dbus-shared.h +++ b/dbus/dbus-shared.h @@ -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 diff --git a/dbus/dbus-sysdeps.c b/dbus/dbus-sysdeps.c index 1b7cd906..030d0801 100644 --- a/dbus/dbus-sysdeps.c +++ b/dbus/dbus-sysdeps.c @@ -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", @@ -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  === diff --git a/doc/dbus-specification.xml b/doc/dbus-specification.xml index d1184650..da9a813f 100644 --- a/doc/dbus-specification.xml +++ b/doc/dbus-specification.xml @@ -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> diff --git a/glib/dbus-gobject.c b/glib/dbus-gobject.c index 1abe2581..0a019cc2 100644 --- a/glib/dbus-gobject.c +++ b/glib/dbus-gobject.c @@ -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); diff --git a/glib/examples/example-service.c b/glib/examples/example-service.c index 5e58175f..a66855c1 100644 --- a/glib/examples/example-service.c +++ b/glib/examples/example-service.c @@ -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)) diff --git a/glib/examples/example-signal-emitter.c b/glib/examples/example-signal-emitter.c index d1cc444c..c60865d2 100644 --- a/glib/examples/example-signal-emitter.c +++ b/glib/examples/example-signal-emitter.c @@ -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)) diff --git a/glib/examples/statemachine/statemachine-server.c b/glib/examples/statemachine/statemachine-server.c index 2cbf39fe..cc9ca4bd 100644 --- a/glib/examples/statemachine/statemachine-server.c +++ b/glib/examples/statemachine/statemachine-server.c @@ -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)) diff --git a/test/Makefile.am b/test/Makefile.am index a43d8f54..e419fb8c 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -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)  diff --git a/test/name-test/Makefile.am b/test/name-test/Makefile.am new file mode 100644 index 00000000..7e931c8a --- /dev/null +++ b/test/name-test/Makefile.am @@ -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 + diff --git a/test/name-test/run-test.sh b/test/name-test/run-test.sh new file mode 100755 index 00000000..5171b18c --- /dev/null +++ b/test/name-test/run-test.sh @@ -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" diff --git a/test/name-test/test-names.c b/test/name-test/test-names.c new file mode 100644 index 00000000..3db2a8cc --- /dev/null +++ b/test/name-test/test-names.c @@ -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; +} | 
