2005-02-26 Havoc Pennington <hp@redhat.com>
authorHavoc Pennington <hp@redhat.com>
Sat, 26 Feb 2005 06:37:46 +0000 (06:37 +0000)
committerHavoc Pennington <hp@redhat.com>
Sat, 26 Feb 2005 06:37:46 +0000 (06:37 +0000)
* doc/TODO: remove the "guid" item

* test/glib/test-profile.c (no_bus_thread_func): use open_private
(with_bus_thread_func): use open_private

* dbus/dbus-connection.c (dbus_connection_open_private): new
function that works like the old dbus_connection_open()
(dbus_connection_open): now returns an existing connection if
possible

* dbus/dbus-server-unix.c (handle_new_client_fd_and_unlock): pass
through the GUID to the transport

* dbus/dbus-server.c (_dbus_server_init_base): keep around the
GUID in hex-encoded form.

* dbus/dbus-server-debug-pipe.c (_dbus_transport_debug_pipe_new):
pass GUID argument in to the transport

* dbus/dbus-transport-unix.c (_dbus_transport_new_for_fd): add
guid argument

* dbus/dbus-transport.c (_dbus_transport_init_base): add guid argument

* dbus/dbus-auth.c (_dbus_auth_server_new): add guid argument

19 files changed:
ChangeLog
dbus/dbus-auth-script.c
dbus/dbus-auth.c
dbus/dbus-auth.h
dbus/dbus-connection.c
dbus/dbus-connection.h
dbus/dbus-internals.h
dbus/dbus-server-debug-pipe.c
dbus/dbus-server-protected.h
dbus/dbus-server-unix.c
dbus/dbus-server.c
dbus/dbus-threads.c
dbus/dbus-transport-protected.h
dbus/dbus-transport-unix.c
dbus/dbus-transport-unix.h
dbus/dbus-transport.c
dbus/dbus-transport.h
doc/TODO
test/glib/test-profile.c

index 0f8daf2..e51ea0c 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,31 @@
+2005-02-26  Havoc Pennington  <hp@redhat.com>
+
+       * doc/TODO: remove the "guid" item
+
+       * test/glib/test-profile.c (no_bus_thread_func): use open_private
+       (with_bus_thread_func): use open_private
+
+       * dbus/dbus-connection.c (dbus_connection_open_private): new
+       function that works like the old dbus_connection_open()
+       (dbus_connection_open): now returns an existing connection if
+       possible
+
+       * dbus/dbus-server-unix.c (handle_new_client_fd_and_unlock): pass
+       through the GUID to the transport
+
+       * dbus/dbus-server.c (_dbus_server_init_base): keep around the
+       GUID in hex-encoded form.
+
+       * dbus/dbus-server-debug-pipe.c (_dbus_transport_debug_pipe_new):
+       pass GUID argument in to the transport
+
+       * dbus/dbus-transport-unix.c (_dbus_transport_new_for_fd): add
+       guid argument
+
+       * dbus/dbus-transport.c (_dbus_transport_init_base): add guid argument
+
+       * dbus/dbus-auth.c (_dbus_auth_server_new): add guid argument
+
 2005-02-25  Havoc Pennington  <hp@redhat.com>
 
        * doc/dbus-specification.xml: document the GUID thing
index f32f1c1..10bf703 100644 (file)
@@ -231,10 +231,12 @@ _dbus_auth_script_run (const DBusString *filename)
   DBusString from_auth;
   DBusAuthState state;
   DBusString context;
+  DBusString guid;
   
   retval = FALSE;
   auth = NULL;
 
+  _dbus_string_init_const (&guid, "5fa01f4202cd837709a3274ca0df9d00");
   _dbus_string_init_const (&context, "org_freedesktop_test");
   
   if (!_dbus_string_init (&file))
@@ -334,7 +336,7 @@ _dbus_auth_script_run (const DBusString *filename)
               goto out;
             }
 
-          auth = _dbus_auth_server_new ();
+          auth = _dbus_auth_server_new (&guid);
           if (auth == NULL)
             {
               _dbus_warn ("no memory to create DBusAuth\n");
index 6412185..2a1bbd4 100644 (file)
@@ -211,6 +211,8 @@ typedef struct
 
   int failures;     /**< Number of times client has been rejected */
   int max_failures; /**< Number of times we reject before disconnect */
+
+  DBusString guid;  /**< Our globally unique ID in hex encoding */
   
 } DBusAuthServer;
 
@@ -1923,20 +1925,35 @@ process_command (DBusAuth *auth)
  * @returns the new object or #NULL if no memory
  */
 DBusAuth*
-_dbus_auth_server_new (void)
+_dbus_auth_server_new (const DBusString *guid)
 {
   DBusAuth *auth;
   DBusAuthServer *server_auth;
+  DBusString guid_copy;
 
-  auth = _dbus_auth_new (sizeof (DBusAuthServer));
-  if (auth == NULL)
+  if (!_dbus_string_init (&guid_copy))
     return NULL;
 
+  if (!_dbus_string_copy (guid, 0, &guid_copy, 0))
+    {
+      _dbus_string_free (&guid_copy);
+      return NULL;
+    }
+
+  auth = _dbus_auth_new (sizeof (DBusAuthServer));
+  if (auth == NULL)
+    {
+      _dbus_string_free (&guid_copy);
+      return NULL;
+    }
+  
   auth->side = auth_side_server;
   auth->state = &server_state_waiting_for_auth;
 
   server_auth = DBUS_AUTH_SERVER (auth);
 
+  server_auth->guid = guid_copy;
+  
   /* perhaps this should be per-mechanism with a lower
    * max
    */
@@ -2012,6 +2029,12 @@ _dbus_auth_unref (DBusAuth *auth)
         {
           _dbus_list_clear (& DBUS_AUTH_CLIENT (auth)->mechs_to_try);
         }
+      else
+        {
+          _dbus_assert (DBUS_AUTH_IS_SERVER (auth));
+
+          _dbus_string_free (& DBUS_AUTH_SERVER (auth)->guid);
+        }
 
       if (auth->keyring)
         _dbus_keyring_unref (auth->keyring);
index 715f6d1..6ed5040 100644 (file)
@@ -41,7 +41,7 @@ typedef enum
   DBUS_AUTH_STATE_AUTHENTICATED
 } DBusAuthState;
 
-DBusAuth*     _dbus_auth_server_new          (void);
+DBusAuth*     _dbus_auth_server_new          (const DBusString       *guid);
 DBusAuth*     _dbus_auth_client_new          (void);
 DBusAuth*     _dbus_auth_ref                 (DBusAuth               *auth);
 void          _dbus_auth_unref               (DBusAuth               *auth);
index 9c57edc..92e0331 100644 (file)
@@ -233,6 +233,10 @@ struct DBusConnection
                          *   for the global linked list mempool lock
                          */
   DBusObjectTree *objects; /**< Object path handlers registered with this connection */
+
+  char *server_guid; /**< GUID of server if we are in shared_connections, #NULL if server GUID is unknown or connection is private */
+
+  unsigned int shareable : 1; /**< #TRUE if connection can go in shared_connections once we know the GUID */
   
   unsigned int dispatch_acquired : 1; /**< Someone has dispatch path (can drain incoming queue) */
   unsigned int io_path_acquired : 1;  /**< Someone has transport io path (can use the transport to read/write messages) */
@@ -1175,6 +1179,7 @@ _dbus_connection_new_for_transport (DBusTransport *transport)
   connection->last_dispatch_status = DBUS_DISPATCH_COMPLETE; /* so we're notified first time there's data */
   connection->objects = objects;
   connection->exit_on_disconnect = FALSE;
+  connection->shareable = FALSE;
 #ifndef DBUS_DISABLE_CHECKS
   connection->generation = _dbus_current_generation;
 #endif
@@ -1363,6 +1368,301 @@ _dbus_connection_handle_watch (DBusWatch                   *watch,
   return retval;
 }
 
+_DBUS_DEFINE_GLOBAL_LOCK (shared_connections);
+static DBusHashTable *shared_connections = NULL;
+
+static void
+shared_connections_shutdown (void *data)
+{
+  _DBUS_LOCK (shared_connections);
+
+  _dbus_assert (_dbus_hash_table_get_n_entries (shared_connections) == 0);
+  _dbus_hash_table_unref (shared_connections);
+  shared_connections = NULL;
+  
+  _DBUS_UNLOCK (shared_connections);
+}
+
+static dbus_bool_t
+connection_lookup_shared (DBusAddressEntry  *entry,
+                          DBusConnection   **result)
+{
+  _dbus_verbose ("checking for existing connection\n");
+  
+  *result = NULL;
+  
+  _DBUS_LOCK (shared_connections);
+
+  if (shared_connections == NULL)
+    {
+      _dbus_verbose ("creating shared_connections hash table\n");
+      
+      shared_connections = _dbus_hash_table_new (DBUS_HASH_STRING,
+                                                 dbus_free,
+                                                 NULL);
+      if (shared_connections == NULL)
+        {
+          _DBUS_UNLOCK (shared_connections);
+          return FALSE;
+        }
+
+      if (!_dbus_register_shutdown_func (shared_connections_shutdown, NULL))
+        {
+          _dbus_hash_table_unref (shared_connections);
+          shared_connections = NULL;
+          _DBUS_UNLOCK (shared_connections);
+          return FALSE;
+        }
+
+      _dbus_verbose ("  successfully created shared_connections\n");
+      
+      _DBUS_UNLOCK (shared_connections);
+      return TRUE; /* no point looking up in the hash we just made */
+    }
+  else
+    {
+      const char *guid;
+
+      guid = dbus_address_entry_get_value (entry, "guid");
+      
+      if (guid != NULL)
+        {
+          *result = _dbus_hash_table_lookup_string (shared_connections,
+                                                    guid);
+
+          if (*result)
+            {
+              /* The DBusConnection can't have been disconnected
+               * between the lookup and this code, because the
+               * disconnection will take the shared_connections lock to
+               * remove the connection. It can't have been finalized
+               * since you have to disconnect prior to finalize.
+               *
+               * Thus it's safe to ref the connection.
+               */
+              dbus_connection_ref (*result);
+
+              _dbus_verbose ("looked up existing connection to server guid %s\n",
+                             guid);
+            }
+        }
+      
+      _DBUS_UNLOCK (shared_connections);
+      return TRUE;
+    }
+}
+
+static dbus_bool_t
+connection_record_shared_unlocked (DBusConnection *connection,
+                                   const char     *guid)
+{
+  char *guid_key;
+  char *guid_in_connection;
+
+  /* A separate copy of the key is required in the hash table, because
+   * we don't have a lock on the connection when we are doing a hash
+   * lookup.
+   */
+  
+  _dbus_assert (connection->server_guid == NULL);
+  _dbus_assert (connection->shareable);
+  
+  guid_key = _dbus_strdup (guid);
+  if (guid_key == NULL)
+    return FALSE;
+
+  guid_in_connection = _dbus_strdup (guid);
+  if (guid_in_connection == NULL)
+    {
+      dbus_free (guid_key);
+      return FALSE;
+    }
+  
+  _DBUS_LOCK (shared_connections);
+  _dbus_assert (shared_connections != NULL);
+  
+  if (!_dbus_hash_table_insert_string (shared_connections,
+                                       guid_key, connection))
+    {
+      dbus_free (guid_key);
+      dbus_free (guid_in_connection);
+      _DBUS_UNLOCK (shared_connections);
+      return FALSE;
+    }
+
+  connection->server_guid = guid_in_connection;
+
+  _dbus_verbose ("stored connection to %s to be shared\n",
+                 connection->server_guid);
+  
+  _DBUS_UNLOCK (shared_connections);
+
+  _dbus_assert (connection->server_guid != NULL);
+  
+  return TRUE;
+}
+
+static void
+connection_forget_shared_unlocked (DBusConnection *connection)
+{
+  HAVE_LOCK_CHECK (connection);
+  
+  if (connection->server_guid == NULL)
+    return;
+
+  _dbus_verbose ("dropping connection to %s out of the shared table\n",
+                 connection->server_guid);
+  
+  _DBUS_LOCK (shared_connections);
+
+  if (!_dbus_hash_table_remove_string (shared_connections,
+                                       connection->server_guid))
+    _dbus_assert_not_reached ("connection was not in the shared table");
+  
+  dbus_free (connection->server_guid);
+  connection->server_guid = NULL;
+
+  _DBUS_UNLOCK (shared_connections);
+}
+
+static DBusConnection*
+connection_try_from_address_entry (DBusAddressEntry *entry,
+                                   DBusError        *error)
+{
+  DBusTransport *transport;
+  DBusConnection *connection;
+
+  transport = _dbus_transport_open (entry, error);
+
+  if (transport == NULL)
+    {
+      _DBUS_ASSERT_ERROR_IS_SET (error);
+      return NULL;
+    }
+
+  connection = _dbus_connection_new_for_transport (transport);
+
+  _dbus_transport_unref (transport);
+  
+  if (connection == NULL)
+    {
+      _DBUS_SET_OOM (error);
+      return NULL;
+    }
+
+#ifndef DBUS_DISABLE_CHECKS
+  _dbus_assert (!connection->have_connection_lock);
+#endif
+  return connection;
+}
+
+/*
+ * If the shared parameter is true, then any existing connection will
+ * be used (and if a new connection is created, it will be available
+ * for use by others). If the shared parameter is false, a new
+ * connection will always be created, and the new connection will
+ * never be returned to other callers.
+ *
+ * @param address the address
+ * @param shared whether the connection is shared or private
+ * @param error error return
+ * @returns the connection or #NULL on error
+ */
+static DBusConnection*
+_dbus_connection_open_internal (const char     *address,
+                                dbus_bool_t     shared,
+                                DBusError      *error)
+{
+  DBusConnection *connection;
+  DBusAddressEntry **entries;
+  DBusError tmp_error;
+  DBusError first_error;
+  int len, i;
+
+  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+
+  _dbus_verbose ("opening %s connection to: %s\n",
+                 shared ? "shared" : "private", address);
+  
+  if (!dbus_parse_address (address, &entries, &len, error))
+    return NULL;
+
+  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+  
+  connection = NULL;
+
+  dbus_error_init (&tmp_error);
+  dbus_error_init (&first_error);
+  for (i = 0; i < len; i++)
+    {
+      if (shared)
+        {
+          if (!connection_lookup_shared (entries[i], &connection))
+            _DBUS_SET_OOM (&tmp_error);
+        }
+
+      if (connection == NULL)
+        {
+          connection = connection_try_from_address_entry (entries[i],
+                                                          &tmp_error);
+          
+          if (connection != NULL && shared)
+            {
+              const char *guid;
+
+              connection->shareable = TRUE;
+              
+              guid = dbus_address_entry_get_value (entries[i], "guid");
+
+              /* we don't have a connection lock but we know nobody
+               * else has a handle to the connection
+               */
+              
+              if (guid &&
+                  !connection_record_shared_unlocked (connection, guid))
+                {
+                  _DBUS_SET_OOM (&tmp_error);
+                  dbus_connection_disconnect (connection);
+                  dbus_connection_unref (connection);
+                  connection = NULL;
+                }
+
+              /* but as of now the connection is possibly shared
+               * since another thread could have pulled it from the table
+               */
+            }
+        }
+      
+      if (connection)
+       break;
+
+      _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
+      
+      if (i == 0)
+        dbus_move_error (&tmp_error, &first_error);
+      else
+        dbus_error_free (&tmp_error);
+    }
+
+  /* NOTE we don't have a lock on a possibly-shared connection object */
+  
+  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+  _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
+  
+  if (connection == NULL)
+    {
+      _DBUS_ASSERT_ERROR_IS_SET (&first_error);
+      dbus_move_error (&first_error, error);
+    }
+  else
+    {
+      dbus_error_free (&first_error);
+    }
+  
+  dbus_address_entries_free (entries);
+  return connection;
+}
+
 /** @} */
 
 /**
@@ -1372,16 +1672,19 @@ _dbus_connection_handle_watch (DBusWatch                   *watch,
  */
 
 /**
- * Opens a new connection to a remote address.
+ * Gets a connection to a remote address. If a connection to the given
+ * address already exists, returns the existing connection with its
+ * reference count incremented.  Otherwise, returns a new connection
+ * and saves the new connection for possible re-use if a future call
+ * to dbus_connection_open() asks to connect to the same server.
  *
- * @todo specify what the address parameter is. Right now
- * it's just the name of a UNIX domain socket. It should be
- * something more complex that encodes which transport to use.
+ * Use dbus_connection_open_private() to get a dedicated connection
+ * not shared with other callers of dbus_connection_open().
  *
- * If the open fails, the function returns #NULL, and provides
- * a reason for the failure in the result parameter. Pass
- * #NULL for the result parameter if you aren't interested
- * in the reason for failure.
+ * If the open fails, the function returns #NULL, and provides a
+ * reason for the failure in the error parameter. Pass #NULL for the
+ * error parameter if you aren't interested in the reason for
+ * failure.
  * 
  * @param address the address.
  * @param error address where an error can be returned.
@@ -1392,31 +1695,44 @@ dbus_connection_open (const char     *address,
                       DBusError      *error)
 {
   DBusConnection *connection;
-  DBusTransport *transport;
 
   _dbus_return_val_if_fail (address != NULL, NULL);
   _dbus_return_val_if_error_is_set (error, NULL);
-  
-  transport = _dbus_transport_open (address, error);
-  if (transport == NULL)
-    {
-      _DBUS_ASSERT_ERROR_IS_SET (error);
-      return NULL;
-    }
-  
-  connection = _dbus_connection_new_for_transport (transport);
 
-  _dbus_transport_unref (transport);
-  
-  if (connection == NULL)
-    {
-      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
-      return NULL;
-    }
+  connection = _dbus_connection_open_internal (address,
+                                               TRUE,
+                                               error);
+
+  return connection;
+}
+
+/**
+ * Opens a new, dedicated connection to a remote address. Unlike
+ * dbus_connection_open(), always creates a new connection.
+ * This connection will not be saved or recycled by libdbus.
+ *
+ * If the open fails, the function returns #NULL, and provides a
+ * reason for the failure in the error parameter. Pass #NULL for the
+ * error parameter if you aren't interested in the reason for
+ * failure.
+ * 
+ * @param address the address.
+ * @param error address where an error can be returned.
+ * @returns new connection, or #NULL on failure.
+ */
+DBusConnection*
+dbus_connection_open_private (const char     *address,
+                              DBusError      *error)
+{
+  DBusConnection *connection;
+
+  _dbus_return_val_if_fail (address != NULL, NULL);
+  _dbus_return_val_if_error_is_set (error, NULL);
+
+  connection = _dbus_connection_open_internal (address,
+                                               FALSE,
+                                               error);
 
-#ifndef DBUS_DISABLE_CHECKS
-  _dbus_assert (!connection->have_connection_lock);
-#endif
   return connection;
 }
 
@@ -1479,7 +1795,8 @@ _dbus_connection_last_unref (DBusConnection *connection)
    * you won't get the disconnected message.
    */
   _dbus_assert (!_dbus_transport_get_is_connected (connection->transport));
-
+  _dbus_assert (connection->server_guid == NULL);
+  
   /* ---- We're going to call various application callbacks here, hope it doesn't break anything... */
   _dbus_object_tree_free_all_unlocked (connection->objects);
   
@@ -1529,7 +1846,7 @@ _dbus_connection_last_unref (DBusConnection *connection)
   _dbus_list_clear (&connection->incoming_messages);
 
   _dbus_counter_unref (connection->outgoing_counter);
-  
+
   _dbus_transport_unref (connection->transport);
 
   if (connection->disconnect_message_link)
@@ -1620,6 +1937,7 @@ dbus_connection_disconnect (DBusConnection *connection)
   _dbus_verbose ("Disconnecting %p\n", connection);
   
   CONNECTION_LOCK (connection);
+  
   _dbus_transport_disconnect (connection->transport);
 
   _dbus_verbose ("%s middle\n", _DBUS_FUNCTION_NAME);
@@ -2838,7 +3156,9 @@ _dbus_connection_get_dispatch_status_unlocked (DBusConnection *connection)
             {
               _dbus_verbose ("Sending disconnect message from %s\n",
                              _DBUS_FUNCTION_NAME);
-                             
+
+              connection_forget_shared_unlocked (connection);
+              
               /* We haven't sent the disconnect message already,
                * and all real messages have been queued up.
                */
index a74ba41..0dc1b61 100644 (file)
@@ -89,6 +89,8 @@ typedef DBusHandlerResult (* DBusHandleMessageFunction) (DBusConnection     *con
 
 DBusConnection*    dbus_connection_open                         (const char                 *address,
                                                                  DBusError                  *error);
+DBusConnection*    dbus_connection_open_private                 (const char                 *address,
+                                                                 DBusError                  *error);
 DBusConnection*    dbus_connection_ref                          (DBusConnection             *connection);
 void               dbus_connection_unref                        (DBusConnection             *connection);
 void               dbus_connection_disconnect                   (DBusConnection             *connection);
index b141c23..8853094 100644 (file)
@@ -280,7 +280,8 @@ _DBUS_DECLARE_GLOBAL_LOCK (bus);
 _DBUS_DECLARE_GLOBAL_LOCK (shutdown_funcs);
 _DBUS_DECLARE_GLOBAL_LOCK (system_users);
 _DBUS_DECLARE_GLOBAL_LOCK (message_cache);
-#define _DBUS_N_GLOBAL_LOCKS (10)
+_DBUS_DECLARE_GLOBAL_LOCK (shared_connections);
+#define _DBUS_N_GLOBAL_LOCKS (11)
 
 dbus_bool_t _dbus_threads_init_debug (void);
 
index 090274a..9c147c6 100644 (file)
@@ -270,9 +270,9 @@ _dbus_transport_debug_pipe_new (const char     *server_name,
   _dbus_string_free (&address);
   
   client_fd = -1;
-  
+
   server_transport = _dbus_transport_new_for_fd (server_fd,
-                                                 TRUE, NULL);
+                                                 &server->guid_hex, NULL);
   if (server_transport == NULL)
     {
       _dbus_transport_unref (client_transport);
index dbbc3c6..7d09f64 100644 (file)
@@ -31,6 +31,7 @@
 #include <dbus/dbus-watch.h>
 #include <dbus/dbus-resources.h>
 #include <dbus/dbus-dataslot.h>
+#include <dbus/dbus-string.h>
 
 DBUS_BEGIN_DECLS
 
@@ -67,7 +68,9 @@ struct DBusServer
   const DBusServerVTable *vtable;             /**< Virtual methods for this instance. */
   DBusMutex *mutex;                           /**< Lock on the server object */
 
-  DBusGUID guid;                              /**< Globally unique ID of server */ 
+  DBusGUID guid;                              /**< Globally unique ID of server */
+
+  DBusString guid_hex;                        /**< Hex-encoded version of GUID */
   
   DBusWatchList *watches;                     /**< Our watches */
   DBusTimeoutList *timeouts;                  /**< Our timeouts */  
index 0aef536..a72bccf 100644 (file)
@@ -99,7 +99,7 @@ handle_new_client_fd_and_unlock (DBusServer *server,
       return TRUE;
     }
   
-  transport = _dbus_transport_new_for_fd (client_fd, TRUE, NULL);
+  transport = _dbus_transport_new_for_fd (client_fd, &server->guid_hex, NULL);
   if (transport == NULL)
     {
       close (client_fd);
index 20fb5f3..0a3b522 100644 (file)
@@ -75,33 +75,30 @@ init_guid (DBusGUID *guid)
  */
 static char*
 copy_address_with_guid_appended (const DBusString *address,
-                                 const DBusGUID   *guid)
+                                 const DBusString *guid_hex)
 {
   DBusString with_guid;
-  DBusString guid_str;
   char *retval;
   
   if (!_dbus_string_init (&with_guid))
     return NULL;
 
-  _dbus_string_init_const_len (&guid_str, guid->as_bytes,
-                               sizeof (guid->as_bytes));
-
-  if (!_dbus_string_copy (address, 0, &with_guid, 0) ||
+  if (!_dbus_string_copy (address, 0, &with_guid,
+                          _dbus_string_get_length (&with_guid)) ||
       !_dbus_string_append (&with_guid, ",guid=") ||
-      !_dbus_string_hex_encode (&guid_str, 0,
-                                &with_guid, _dbus_string_get_length (&with_guid)))
+      !_dbus_string_copy (guid_hex, 0,
+                          &with_guid, _dbus_string_get_length (&with_guid)))
     {
       _dbus_string_free (&with_guid);
       return NULL;
     }
 
   retval = NULL;
-  _dbus_string_copy_data (&with_guid, &retval);
+  _dbus_string_steal_data (&with_guid, &retval);
 
   _dbus_string_free (&with_guid);
       
-  return retval; /* may be NULL if copy failed */
+  return retval; /* may be NULL if steal_data failed */
 }
 
 /**
@@ -117,7 +114,9 @@ dbus_bool_t
 _dbus_server_init_base (DBusServer             *server,
                         const DBusServerVTable *vtable,
                         const DBusString       *address)
-{  
+{
+  DBusString guid_raw;
+  
   server->vtable = vtable;
   server->refcount.value = 1;
 
@@ -125,10 +124,20 @@ _dbus_server_init_base (DBusServer             *server,
   server->watches = NULL;
   server->timeouts = NULL;
 
+  if (!_dbus_string_init (&server->guid_hex))
+    return FALSE;
+
   init_guid (&server->guid);
 
+  _dbus_string_init_const_len (&guid_raw, server->guid.as_bytes,
+                               sizeof (server->guid.as_bytes));
+  if (!_dbus_string_hex_encode (&guid_raw, 0,
+                                &server->guid_hex,
+                                _dbus_string_get_length (&server->guid_hex)))
+    goto failed;
+  
   server->address = copy_address_with_guid_appended (address,
-                                                     &server->guid);
+                                                     &server->guid_hex);
   if (server->address == NULL)
     goto failed;
   
@@ -171,6 +180,7 @@ _dbus_server_init_base (DBusServer             *server,
       dbus_free (server->address);
       server->address = NULL;
     }
+  _dbus_string_free (&server->guid_hex);
   
   return FALSE;
 }
@@ -205,6 +215,8 @@ _dbus_server_finalize_base (DBusServer *server)
   dbus_free (server->address);
 
   dbus_free_string_array (server->auth_mechanisms);
+
+  _dbus_string_free (&server->guid_hex);
 }
 
 
index 0d004d6..fc83682 100644 (file)
@@ -231,7 +231,8 @@ init_global_locks (void)
     LOCK_ADDR (bus),
     LOCK_ADDR (shutdown_funcs),
     LOCK_ADDR (system_users),
-    LOCK_ADDR (message_cache)
+    LOCK_ADDR (message_cache),
+    LOCK_ADDR (shared_connections)
 #undef LOCK_ADDR
   };
 
index 5419593..879c3db 100644 (file)
@@ -113,7 +113,7 @@ struct DBusTransport
 
 dbus_bool_t _dbus_transport_init_base     (DBusTransport             *transport,
                                            const DBusTransportVTable *vtable,
-                                           dbus_bool_t                server,
+                                           const DBusString          *server_guid,
                                            const DBusString          *address);
 void        _dbus_transport_finalize_base (DBusTransport             *transport);
 
index 2959886..4c07d5f 100644 (file)
@@ -1114,13 +1114,13 @@ static DBusTransportVTable unix_vtable = {
  * boil down to a full duplex file descriptor.
  *
  * @param fd the file descriptor.
- * @param server #TRUE if this transport is on the server side of a connection
+ * @param server_guid non-#NULL if this transport is on the server side of a connection
  * @param address the transport's address
  * @returns the new transport, or #NULL if no memory.
  */
 DBusTransport*
 _dbus_transport_new_for_fd (int               fd,
-                            dbus_bool_t       server,
+                            const DBusString *server_guid,
                             const DBusString *address)
 {
   DBusTransportUnix *unix_transport;
@@ -1151,7 +1151,7 @@ _dbus_transport_new_for_fd (int               fd,
   
   if (!_dbus_transport_init_base (&unix_transport->base,
                                   &unix_vtable,
-                                  server, address))
+                                  server_guid, address))
     goto failed_4;
   
   unix_transport->fd = fd;
index 254144d..73986ba 100644 (file)
@@ -28,7 +28,7 @@
 DBUS_BEGIN_DECLS
 
 DBusTransport* _dbus_transport_new_for_fd            (int               fd,
-                                                      dbus_bool_t       server,
+                                                      const DBusString *server_guid,
                                                       const DBusString *address);
 DBusTransport* _dbus_transport_new_for_domain_socket (const char       *path,
                                                       dbus_bool_t       abstract,
index c08573d..b271d94 100644 (file)
@@ -75,19 +75,22 @@ live_messages_size_notify (DBusCounter *counter,
 }
 
 /**
- * Initializes the base class members of DBusTransport.
- * Chained up to by subclasses in their constructor.
+ * Initializes the base class members of DBusTransport.  Chained up to
+ * by subclasses in their constructor.  The server GUID is the
+ * globally unique ID for the server creating this connection
+ * and will be #NULL for the client side of a connection. The GUID
+ * is in hex format.
  *
  * @param transport the transport being created.
  * @param vtable the subclass vtable.
- * @param server #TRUE if this transport is on the server side of a connection
+ * @param server_guid non-#NULL if this transport is on the server side of a connection
  * @param address the address of the transport
  * @returns #TRUE on success.
  */
 dbus_bool_t
 _dbus_transport_init_base (DBusTransport             *transport,
                            const DBusTransportVTable *vtable,
-                           dbus_bool_t                server,
+                           const DBusString          *server_guid,
                            const DBusString          *address)
 {
   DBusMessageLoader *loader;
@@ -99,8 +102,8 @@ _dbus_transport_init_base (DBusTransport             *transport,
   if (loader == NULL)
     return FALSE;
   
-  if (server)
-    auth = _dbus_auth_server_new ();
+  if (server_guid)
+    auth = _dbus_auth_server_new (server_guid);
   else
     auth = _dbus_auth_client_new ();
   if (auth == NULL)
@@ -117,7 +120,7 @@ _dbus_transport_init_base (DBusTransport             *transport,
       return FALSE;
     }  
   
-  if (server)
+  if (server_guid)
     {
       _dbus_assert (address == NULL);
       address_copy = NULL;
@@ -142,9 +145,9 @@ _dbus_transport_init_base (DBusTransport             *transport,
   transport->live_messages_size = counter;
   transport->authenticated = FALSE;
   transport->disconnected = FALSE;
-  transport->send_credentials_pending = !server;
-  transport->receive_credentials_pending = server;
-  transport->is_server = server;
+  transport->is_server = (server_guid != NULL);
+  transport->send_credentials_pending = !transport->is_server;
+  transport->receive_credentials_pending = transport->is_server;
   transport->address = address_copy;
   
   transport->unix_user_function = NULL;
@@ -195,33 +198,22 @@ _dbus_transport_finalize_base (DBusTransport *transport)
 }
 
 /**
- * Opens a new transport for the given address.  (This opens a
- * client-side-of-the-connection transport.)
- *
- * @todo error messages on bad address could really be better.
- * DBusResultCode is a bit limiting here.
+ * Try to open a new transport for the given address entry.  (This
+ * opens a client-side-of-the-connection transport.)
  * 
- * @param address the address.
+ * @param entry the address entry
  * @param error location to store reason for failure.
  * @returns new transport of #NULL on failure.
  */
 DBusTransport*
-_dbus_transport_open (const char     *address,
-                      DBusError      *error)
+_dbus_transport_open (DBusAddressEntry *entry,
+                      DBusError        *error)
 {
   DBusTransport *transport;
-  DBusAddressEntry **entries;
-  DBusError tmp_error;
-  DBusError first_error;
-  int len, i;
   const char *address_problem_type;
   const char *address_problem_field;
   const char *address_problem_other;
-
-  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
-  
-  if (!dbus_parse_address (address, &entries, &len, error))
-    return NULL;
+  const char *method;     
 
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
   
@@ -229,125 +221,96 @@ _dbus_transport_open (const char     *address,
   address_problem_type = NULL;
   address_problem_field = NULL;
   address_problem_other = NULL;
-
-  dbus_error_init (&tmp_error);
-  dbus_error_init (&first_error);
-  for (i = 0; i < len; i++)
-    {
-      const char *method;
-
-      method = dbus_address_entry_get_method (entries[i]);
+  
+  method = dbus_address_entry_get_method (entry);
+  _dbus_assert (method != NULL);
       
-      if (strcmp (method, "unix") == 0)
-       {
-         const char *path = dbus_address_entry_get_value (entries[i], "path");
-          const char *tmpdir = dbus_address_entry_get_value (entries[i], "tmpdir");
-          const char *abstract = dbus_address_entry_get_value (entries[i], "abstract");
+  if (strcmp (method, "unix") == 0)
+    {
+      const char *path = dbus_address_entry_get_value (entry, "path");
+      const char *tmpdir = dbus_address_entry_get_value (entry, "tmpdir");
+      const char *abstract = dbus_address_entry_get_value (entry, "abstract");
           
-         if (tmpdir != NULL)
-            {
-              address_problem_other = "cannot use the \"tmpdir\" option for an address to connect to, only in an address to listen on";
-              goto bad_address;
-            }
+      if (tmpdir != NULL)
+        {
+          address_problem_other = "cannot use the \"tmpdir\" option for an address to connect to, only in an address to listen on";
+          goto bad_address;
+        }
           
-         if (path == NULL && abstract == NULL)
-            {
-              address_problem_type = "unix";
-              address_problem_field = "path or abstract";  
-              goto bad_address;
-            }
+      if (path == NULL && abstract == NULL)
+        {
+          address_problem_type = "unix";
+          address_problem_field = "path or abstract";  
+          goto bad_address;
+        }
 
-         if (path != NULL && abstract != NULL)
-            {
-              address_problem_other = "can't specify both \"path\" and \"abstract\" options in an address";
-              goto bad_address;
-            }
+      if (path != NULL && abstract != NULL)
+        {
+          address_problem_other = "can't specify both \"path\" and \"abstract\" options in an address";
+          goto bad_address;
+        }
 
-          if (path)
-            transport = _dbus_transport_new_for_domain_socket (path, FALSE,
-                                                               &tmp_error);
-          else
-            transport = _dbus_transport_new_for_domain_socket (abstract, TRUE,
-                                                               &tmp_error);
-       }
-      else if (strcmp (method, "tcp") == 0)
-       {
-         const char *host = dbus_address_entry_get_value (entries[i], "host");
-          const char *port = dbus_address_entry_get_value (entries[i], "port");
-          DBusString  str;
-          long lport;
-          dbus_bool_t sresult;
+      if (path)
+        transport = _dbus_transport_new_for_domain_socket (path, FALSE,
+                                                           error);
+      else
+        transport = _dbus_transport_new_for_domain_socket (abstract, TRUE,
+                                                           error);
+    }
+  else if (strcmp (method, "tcp") == 0)
+    {
+      const char *host = dbus_address_entry_get_value (entry, "host");
+      const char *port = dbus_address_entry_get_value (entry, "port");
+      DBusString  str;
+      long lport;
+      dbus_bool_t sresult;
           
-          if (port == NULL)
-            {
-              address_problem_type = "tcp";
-              address_problem_field = "port";
-              goto bad_address;
-            }
+      if (port == NULL)
+        {
+          address_problem_type = "tcp";
+          address_problem_field = "port";
+          goto bad_address;
+        }
 
-          _dbus_string_init_const (&str, port);
-          sresult = _dbus_string_parse_int (&str, 0, &lport, NULL);
-          _dbus_string_free (&str);
+      _dbus_string_init_const (&str, port);
+      sresult = _dbus_string_parse_int (&str, 0, &lport, NULL);
+      _dbus_string_free (&str);
           
-          if (sresult == FALSE || lport <= 0 || lport > 65535)
-            {
-              address_problem_other = "Port is not an integer between 0 and 65535";
-              goto bad_address;
-            }
+      if (sresult == FALSE || lport <= 0 || lport > 65535)
+        {
+          address_problem_other = "Port is not an integer between 0 and 65535";
+          goto bad_address;
+        }
           
-         transport = _dbus_transport_new_for_tcp_socket (host, lport, &tmp_error);
-       }
+      transport = _dbus_transport_new_for_tcp_socket (host, lport, error);
+    }
 #ifdef DBUS_BUILD_TESTS
-      else if (strcmp (method, "debug-pipe") == 0)
-       {
-         const char *name = dbus_address_entry_get_value (entries[i], "name");
+  else if (strcmp (method, "debug-pipe") == 0)
+    {
+      const char *name = dbus_address_entry_get_value (entry, "name");
 
-          if (name == NULL)
-            {
-              address_problem_type = "debug-pipe";
-              address_problem_field = "name";
-              goto bad_address;
-            }
-          
-         transport = _dbus_transport_debug_pipe_new (name, &tmp_error);
-       }
-#endif
-      else
+      if (name == NULL)
         {
-          address_problem_other = "Unknown address type (examples of valid types are \"unix\" and \"tcp\")";
+          address_problem_type = "debug-pipe";
+          address_problem_field = "name";
           goto bad_address;
         }
-
-      if (transport)
-       break;
-
-      _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
-      
-      if (i == 0)
-        dbus_move_error (&tmp_error, &first_error);
-      else
-        dbus_error_free (&tmp_error);
-    }
-
-  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
-  _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
-  
-  if (transport == NULL)
-    {
-      _DBUS_ASSERT_ERROR_IS_SET (&first_error);
-      dbus_move_error (&first_error, error);
+          
+      transport = _dbus_transport_debug_pipe_new (name, error);
     }
+#endif
   else
     {
-      dbus_error_free (&first_error);
+      address_problem_other = "Unknown address type (examples of valid types are \"unix\" and \"tcp\")";
+      goto bad_address;
     }
+
+  if (transport == NULL)
+    _DBUS_ASSERT_ERROR_IS_SET (error);
   
-  dbus_address_entries_free (entries);
   return transport;
-
+  
  bad_address:
-  dbus_address_entries_free (entries);
-
   if (address_problem_type != NULL)
     dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
                     "Address of type %s was missing argument %s",
index 8359474..502cfb0 100644 (file)
 #include <dbus/dbus-internals.h>
 #include <dbus/dbus-connection.h>
 #include <dbus/dbus-protocol.h>
+#include <dbus/dbus-address.h>
 
 DBUS_BEGIN_DECLS
 
 typedef struct DBusTransport DBusTransport;
 
-DBusTransport*     _dbus_transport_open                   (const char                 *address,
+DBusTransport*     _dbus_transport_open                   (DBusAddressEntry           *entry,
                                                            DBusError                  *error);
 DBusTransport*     _dbus_transport_ref                    (DBusTransport              *transport);
 void               _dbus_transport_unref                  (DBusTransport              *transport);
index 77d595a..dbe2d25 100644 (file)
--- a/doc/TODO
+++ b/doc/TODO
@@ -33,21 +33,9 @@ Important for 1.0
 
  - dbus-pending-call.c has some API and thread safety issues to review
 
- - make dbus_connection_open() return a shared connection from a pool.
-   Add dbus_connection_open_private() that works like the current one.
-   To do this, each DBusServer could have a 128-bit GUID. This GUID
-   would be in the address from dbus_server_get_address(). On
-   connection to a server, the GUID would be provided as the first
-   thing in the auth protocol, and verified vs. the expected GUID if a
-   GUID was in the address used to connect. A hash from GUID to
-   connection would be kept, so attempts to connect to a GUID already
-   in the hash would return a shared existing connection.
-
-   The purpose of all this is to allow a dbus_g_proxy_to_string() that
-   would convert the proxy to an "IOR" and dbus_g_proxy_from_string()
-   that would decode; using these, dbus-glib users could avoid
-   DBusConnection entirely. Of course the same applies to other kinds
-   of binding.
+ - transmit GUID from server to client in the auth protocol, so 
+   connections can be shared even if the address used to connect
+   to them didn't have a GUID in it.
 
 Important for 1.0 GLib Bindings
 ===
@@ -74,6 +62,13 @@ Might as Well for 1.0
 Can Be Post 1.0
 ===
 
+ - Allow a dbus_g_proxy_to_string()/g_object_to_string() that
+   would convert the proxy to an "IOR" and dbus_g_proxy_from_string()
+   that would decode; using these, dbus-glib users could avoid
+   DBusConnection entirely. Of course the same applies to other kinds
+   of binding. This would use dbus_connection_open()'s connection-sharing
+   feature to avoid massive proliferation of connections.
+
  - DBusWatchList/TimeoutList duplicate a lot of code, as do
    protected_change_watch/protected_change_timeout in dbus-connection.c
    and dbus-server.c. This could all be mopped up, cut-and-paste 
index ca4f33c..f23c7e2 100644 (file)
@@ -190,7 +190,7 @@ no_bus_thread_func (void *data)
   g_printerr ("Starting client thread %p\n", g_thread_self());  
   
   dbus_error_init (&error);
-  connection = dbus_connection_open (messages_address, &error);
+  connection = dbus_connection_open_private (messages_address, &error);
   if (connection == NULL)
     {
       g_printerr ("could not open connection: %s\n", error.message);
@@ -361,7 +361,7 @@ with_bus_thread_func (void *data)
     }
   
   dbus_error_init (&error);
-  connection = dbus_connection_open (address, &error);
+  connection = dbus_connection_open_private (address, &error);
   if (connection == NULL)
     {
       g_printerr ("could not open connection to bus: %s\n", error.message);