dbus/bus activation.c, 1.40, 1.41 bus.h, 1.26, 1.27 dispatch.c, 1.73, 1.74 driver.c, 1.75, 1.76 services.c, 1.32, 1.33 services.h, 1.14, 1.15 signals.c, 1.13, 1.14

John Palmieri johnp at freedesktop.org
Tue Nov 22 12:37:02 PST 2005


Update of /cvs/dbus/dbus/bus
In directory gabe:/tmp/cvs-serv18986/bus

Modified Files:
	activation.c bus.h dispatch.c driver.c services.c services.h 
	signals.c 
Log Message:
	* 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



Index: activation.c
===================================================================
RCS file: /cvs/dbus/dbus/bus/activation.c,v
retrieving revision 1.40
retrieving revision 1.41
diff -u -d -r1.40 -r1.41
--- activation.c	6 Sep 2005 22:38:54 -0000	1.40
+++ activation.c	22 Nov 2005 20:37:00 -0000	1.41
@@ -980,7 +980,7 @@
         {
           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.

Index: bus.h
===================================================================
RCS file: /cvs/dbus/dbus/bus/bus.h,v
retrieving revision 1.26
retrieving revision 1.27
diff -u -d -r1.26 -r1.27
--- bus.h	12 Sep 2004 10:23:42 -0000	1.26
+++ bus.h	22 Nov 2005 20:37:00 -0000	1.27
@@ -40,6 +40,7 @@
 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;

Index: dispatch.c
===================================================================
RCS file: /cvs/dbus/dbus/bus/dispatch.c,v
retrieving revision 1.73
retrieving revision 1.74
diff -u -d -r1.73 -r1.74
--- dispatch.c	3 Oct 2005 19:55:56 -0000	1.73
+++ dispatch.c	22 Nov 2005 20:37:00 -0000	1.74
@@ -287,7 +287,7 @@
         }
       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,

Index: driver.c
===================================================================
RCS file: /cvs/dbus/dbus/bus/driver.c,v
retrieving revision 1.75
retrieving revision 1.76
diff -u -d -r1.75 -r1.76
--- driver.c	15 Nov 2005 17:19:19 -0000	1.75
+++ driver.c	22 Nov 2005 20:37:00 -0000	1.76
@@ -308,12 +308,10 @@
 
   /* 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 @@
     }
   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 @@
 }
 
 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 @@
       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 @@
       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 @@
       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 @@
     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,

Index: services.c
===================================================================
RCS file: /cvs/dbus/dbus/bus/services.c,v
retrieving revision 1.32
retrieving revision 1.33
diff -u -d -r1.32 -r1.33
--- services.c	15 Nov 2005 17:19:19 -0000	1.32
+++ services.c	22 Nov 2005 20:37:00 -0000	1.33
@@ -42,8 +42,17 @@
   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 @@
   
   DBusHashTable *service_hash;
   DBusMemPool   *service_pool;
+  DBusMemPool   *owner_pool;
 
   DBusHashTable *service_sid_table;
 };
@@ -77,9 +87,16 @@
   
   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 @@
         _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 @@
   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 @@
 
   _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 @@
 
   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 @@
       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 @@
                               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 @@
   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 @@
        */
       
       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 @@
 
 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 @@
  */
 typedef struct
 {
-  DBusConnection *connection; /**< the connection */
+  BusOwner *owner;            /**< the owner */
   BusService *service;        /**< service to cancel ownership of */
 } OwnershipCancelData;
 
@@ -583,7 +735,7 @@
    * 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 @@
 {
   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 @@
 static dbus_bool_t
 add_cancel_ownership_to_transaction (BusTransaction *transaction,
                                      BusService     *service,
-                                     DBusConnection *connection)
+                                     BusOwner       *owner)
 {
   OwnershipCancelData *d;
 
@@ -612,7 +765,7 @@
     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 @@
     }
 
   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 @@
   */
   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 @@
   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 @@
   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 @@
    * 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 @@
 
   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 @@
 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 @@
     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 @@
     }
   
   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 @@
   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 @@
    */
   
   /* 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 @@
   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 @@
   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 @@
     }
 }
 
-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 @@
   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;
 }

Index: services.h
===================================================================
RCS file: /cvs/dbus/dbus/bus/services.h,v
retrieving revision 1.14
retrieving revision 1.15
diff -u -d -r1.14 -r1.15
--- services.h	15 Nov 2005 17:19:19 -0000	1.14
+++ services.h	22 Nov 2005 20:37:00 -0000	1.15
@@ -40,7 +40,8 @@
                                            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_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 */

Index: signals.c
===================================================================
RCS file: /cvs/dbus/dbus/bus/signals.c,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -d -r1.13 -r1.14
--- signals.c	29 Jul 2005 17:43:30 -0000	1.13
+++ signals.c	22 Nov 2005 20:37:00 -0000	1.14
@@ -1274,7 +1274,7 @@
   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



More information about the dbus-commit mailing list