2003-03-12 Havoc Pennington <hp@redhat.com>
authorHavoc Pennington <hp@redhat.com>
Thu, 13 Mar 2003 00:56:43 +0000 (00:56 +0000)
committerHavoc Pennington <hp@redhat.com>
Thu, 13 Mar 2003 00:56:43 +0000 (00:56 +0000)
        Mega-patch that gets the message bus daemon initially handling
out-of-memory. Work still needed. Also lots of random
moving stuff to DBusError instead of ResultCode.

* dbus/dbus-list.c (_dbus_list_length_is_one): new function

* dbus/dbus-connection.c
(dbus_connection_send_with_reply_and_block): use DBusError

* dbus/dbus-bus.c: adapt to API changes, make it use DBusError not
DBusResultCode

* dbus/dbus-connection.c (dbus_connection_send): drop the result
code here, as the only failure possible is OOM.

* bus/connection.c (bus_connection_disconnect):
rename bus_connection_disconnected as it's a notification only

* bus/driver.c (bus_driver_handle_acquire_service): don't free
"name" on get_args failure, should be done by get_args;
don't disconnect client for bad args, just return an error.
(bus_driver_handle_service_exists): ditto

* bus/services.c (bus_services_list): NULL-terminate returned array

* bus/driver.c (bus_driver_send_service_lost)
(bus_driver_send_service_acquired): send messages from driver to a
specific client to the client's unique name, not to the broadcast
service.

* dbus/dbus-message.c (decode_header_data): reject messages that
contain no name field
(_dbus_message_get_client_serial): rename to
dbus_message_get_serial and make public
(_dbus_message_set_serial): rename from set_client_serial
(_dbus_message_set_reply_serial): make public
(_dbus_message_get_reply_serial): make public

* bus/connection.c (bus_connection_foreach): allow stopping
iteration by returning FALSE from foreach function.

* dbus/dbus-connection.c (dbus_connection_send_preallocated)
(dbus_connection_free_preallocated_send)
(dbus_connection_preallocate_send): new API for sending a message
without possibility of malloc failure.
(dbus_connection_send_message): rename to just
dbus_connection_send (and same for whole function family)

* dbus/dbus-errors.c (dbus_error_free): make this reinit the error

* dbus/dbus-sysdeps.c (_dbus_exit): new function

* bus/activation.c: handle/return errors

* dbus/dbus-errors.h: add more DBUS_ERROR #define

* dbus/dbus-sysdeps.c (_dbus_directory_open) (_dbus_file_get_contents)
(_dbus_directory_get_next_file): use DBusError instead of DBusResultCode
(_dbus_result_from_errno): move to this file

48 files changed:
ChangeLog
bus/activation.c
bus/activation.h
bus/connection.c
bus/connection.h
bus/desktop-file.c
bus/dispatch.c
bus/dispatch.h
bus/driver.c
bus/driver.h
bus/main.c
bus/services.c
bus/services.h
bus/utils.c
bus/utils.h
dbus/dbus-address.c
dbus/dbus-auth-script.c
dbus/dbus-auth.c
dbus/dbus-bus.c
dbus/dbus-bus.h
dbus/dbus-connection.c
dbus/dbus-connection.h
dbus/dbus-errors.c
dbus/dbus-errors.h
dbus/dbus-internals.c
dbus/dbus-internals.h
dbus/dbus-keyring.c
dbus/dbus-list.c
dbus/dbus-list.h
dbus/dbus-message-builder.c
dbus/dbus-message-internal.h
dbus/dbus-message.c
dbus/dbus-message.h
dbus/dbus-sha.c
dbus/dbus-sysdeps.c
dbus/dbus-sysdeps.h
glib/test-dbus-glib.c
glib/test-thread-client.c
test/bus-test.c
test/data/valid-messages/dict-simple.message
test/data/valid-messages/dict.message
test/data/valid-messages/lots-of-arguments.message
test/data/valid-messages/no-padding.message
test/data/valid-messages/simplest-manual.message
test/data/valid-messages/simplest.message
test/echo-client.c
test/unbase64.c
test/watch.c

index 36f27b9..c7bc436 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,65 @@
+2003-03-12  Havoc Pennington  <hp@redhat.com>
+
+        Mega-patch that gets the message bus daemon initially handling 
+       out-of-memory. Work still needed. Also lots of random 
+       moving stuff to DBusError instead of ResultCode.
+       
+       * dbus/dbus-list.c (_dbus_list_length_is_one): new function
+
+       * dbus/dbus-connection.c
+       (dbus_connection_send_with_reply_and_block): use DBusError
+
+       * dbus/dbus-bus.c: adapt to API changes, make it use DBusError not
+       DBusResultCode
+
+       * dbus/dbus-connection.c (dbus_connection_send): drop the result
+       code here, as the only failure possible is OOM.
+
+       * bus/connection.c (bus_connection_disconnect):
+       rename bus_connection_disconnected as it's a notification only
+
+       * bus/driver.c (bus_driver_handle_acquire_service): don't free
+       "name" on get_args failure, should be done by get_args; 
+       don't disconnect client for bad args, just return an error.
+       (bus_driver_handle_service_exists): ditto
+
+       * bus/services.c (bus_services_list): NULL-terminate returned array
+
+       * bus/driver.c (bus_driver_send_service_lost)
+       (bus_driver_send_service_acquired): send messages from driver to a
+       specific client to the client's unique name, not to the broadcast
+       service.
+
+       * dbus/dbus-message.c (decode_header_data): reject messages that
+       contain no name field
+       (_dbus_message_get_client_serial): rename to
+       dbus_message_get_serial and make public
+       (_dbus_message_set_serial): rename from set_client_serial
+       (_dbus_message_set_reply_serial): make public
+       (_dbus_message_get_reply_serial): make public
+
+       * bus/connection.c (bus_connection_foreach): allow stopping
+       iteration by returning FALSE from foreach function.
+
+       * dbus/dbus-connection.c (dbus_connection_send_preallocated) 
+       (dbus_connection_free_preallocated_send) 
+       (dbus_connection_preallocate_send): new API for sending a message
+       without possibility of malloc failure.
+       (dbus_connection_send_message): rename to just
+       dbus_connection_send (and same for whole function family)
+
+       * dbus/dbus-errors.c (dbus_error_free): make this reinit the error
+
+       * dbus/dbus-sysdeps.c (_dbus_exit): new function
+
+       * bus/activation.c: handle/return errors
+
+       * dbus/dbus-errors.h: add more DBUS_ERROR #define
+
+       * dbus/dbus-sysdeps.c (_dbus_directory_open) (_dbus_file_get_contents)
+       (_dbus_directory_get_next_file): use DBusError instead of DBusResultCode
+       (_dbus_result_from_errno): move to this file
+
 2003-03-10  Anders Carlsson  <andersca@codefactory.se>
 
        * dbus/dbus-marshal.c: 
index b5cec44..4e428bd 100644 (file)
@@ -59,18 +59,24 @@ bus_activation_entry_free (BusActivationEntry *entry)
 }
 
 static dbus_bool_t
-add_desktop_file_entry (BusDesktopFile *desktop_file)
+add_desktop_file_entry (BusDesktopFile *desktop_file,
+                        DBusError      *error)
 {
   char *name, *exec;
   BusActivationEntry *entry;
+
+  name = NULL;
+  exec = NULL;
+  entry = NULL;
   
   if (!bus_desktop_file_get_string (desktop_file,
                                    DBUS_SERVICE_SECTION,
                                    DBUS_SERVICE_NAME,
                                    &name))
     {
-      _dbus_verbose ("No \""DBUS_SERVICE_NAME"\" key in .service file\n");
-      return FALSE;
+      dbus_set_error (error, DBUS_ERROR_FAILED,
+                      "No \""DBUS_SERVICE_NAME"\" key in .service file\n");
+      goto failed;
     }
 
   if (!bus_desktop_file_get_string (desktop_file,
@@ -78,57 +84,104 @@ add_desktop_file_entry (BusDesktopFile *desktop_file)
                                    DBUS_SERVICE_EXEC,
                                    &exec))
     {
-      _dbus_verbose ("No \""DBUS_SERVICE_EXEC"\" key in .service file\n");
-      
-      dbus_free (name);
-      return FALSE;
+      dbus_set_error (error, DBUS_ERROR_FAILED,
+                      "No \""DBUS_SERVICE_EXEC"\" key in .service file\n");
+      goto failed;
     }
 
+  /* FIXME we need a better-defined algorithm for which service file to
+   * pick than "whichever one is first in the directory listing"
+   */
   if (_dbus_hash_table_lookup_string (activation_entries, name))
     {
-      _dbus_verbose ("Service %s already exists in activation entry list\n", name);
-      dbus_free (name);
-      dbus_free (exec);
-
-      return FALSE;
+      dbus_set_error (error, DBUS_ERROR_FAILED,
+                      "Service %s already exists in activation entry list\n", name);
+      goto failed;
+    }
+  
+  entry = dbus_new0 (BusActivationEntry, 1);
+  if (entry == NULL)
+    {
+      BUS_SET_OOM (error);
+      goto failed;
     }
   
-  BUS_HANDLE_OOM (entry = dbus_malloc0 (sizeof (BusActivationEntry)));
   entry->name = name;
   entry->exec = exec;
 
-  BUS_HANDLE_OOM (_dbus_hash_table_insert_string (activation_entries, entry->name, entry));
+  if (!_dbus_hash_table_insert_string (activation_entries, entry->name, entry))
+    {
+      BUS_SET_OOM (error);
+      goto failed;
+    }
 
   _dbus_verbose ("Added \"%s\" to list of services\n", entry->name);
   
   return TRUE;
+
+ failed:
+  dbus_free (name);
+  dbus_free (exec);
+  dbus_free (entry);
+  
+  return FALSE;
 }
 
-static void
-load_directory (const char *directory)
+/* warning: this doesn't fully "undo" itself on failure, i.e. doesn't strip
+ * hash entries it already added.
+ */
+static dbus_bool_t
+load_directory (const char *directory,
+                DBusError  *error)
 {
   DBusDirIter *iter;
   DBusString dir, filename;
-  DBusResultCode result;
-
+  DBusString full_path;
+  BusDesktopFile *desktop_file;
+  DBusError tmp_error;
+  
   _dbus_string_init_const (&dir, directory);
+
+  iter = NULL;
+  desktop_file = NULL;
   
-  iter = _dbus_directory_open (&dir, &result);
-  if (iter == NULL)
+  if (!_dbus_string_init (&filename, _DBUS_INT_MAX))
     {
-      _dbus_verbose ("Failed to open directory %s: &s\n", directory,
-                    result);
-    return;
+      BUS_SET_OOM (error);
+      return FALSE;
     }
 
-  BUS_HANDLE_OOM (_dbus_string_init (&filename, _DBUS_INT_MAX));
+  if (!_dbus_string_init (&full_path, _DBUS_INT_MAX))
+    {
+      BUS_SET_OOM (error);
+      _dbus_string_free (&filename);
+      return FALSE;
+    }
+
+  /* from this point it's safe to "goto failed" */
+  
+  iter = _dbus_directory_open (&dir, error);
+  if (iter == NULL)
+    {
+      _dbus_verbose ("Failed to open directory %s: %s\n",
+                     directory, error ? error->message : "unknown");
+      goto failed;
+    }
   
   /* Now read the files */
-  while (_dbus_directory_get_next_file (iter, &filename, &result))
+  dbus_error_init (&tmp_error);
+  while (_dbus_directory_get_next_file (iter, &filename, &tmp_error))
     {
-      DBusString full_path;
-      BusDesktopFile *desktop_file;
-      DBusError error;
+      _dbus_assert (!dbus_error_is_set (&tmp_error));
+      
+      _dbus_string_set_length (&full_path, 0);
+      
+      if (!_dbus_string_append (&full_path, directory) ||
+          !_dbus_concat_dir_and_file (&full_path, &filename))
+        {
+          BUS_SET_OOM (error);
+          goto failed;
+        }
       
       if (!_dbus_string_ends_with_c_str (&filename, ".service"))
        {
@@ -136,71 +189,133 @@ load_directory (const char *directory)
           _dbus_string_get_const_data (&filename, &filename_c);
           _dbus_verbose ("Skipping non-.service file %s\n",
                          filename_c);
-         continue;
+          continue;
        }
       
-      BUS_HANDLE_OOM (_dbus_string_init (&full_path, _DBUS_INT_MAX));
-      BUS_HANDLE_OOM (_dbus_string_append (&full_path, directory));
-
-      BUS_HANDLE_OOM (_dbus_concat_dir_and_file (&full_path, &filename));
+      desktop_file = bus_desktop_file_load (&full_path, &tmp_error);
 
-      desktop_file = bus_desktop_file_load (&full_path, &error);
-
-      if (!desktop_file)
+      if (desktop_file == NULL)
        {
          const char *full_path_c;
 
           _dbus_string_get_const_data (&full_path, &full_path_c);
          
          _dbus_verbose ("Could not load %s: %s\n", full_path_c,
-                        error.message);
-         dbus_error_free (&error);
-         _dbus_string_free (&full_path);
+                        tmp_error.message);
+
+          if (dbus_error_has_name (&tmp_error, DBUS_ERROR_NO_MEMORY))
+            {
+              dbus_move_error (&tmp_error, error);
+              goto failed;
+            }
+          
+         dbus_error_free (&tmp_error);
          continue;
        }
 
-      if (!add_desktop_file_entry (desktop_file))
+      if (!add_desktop_file_entry (desktop_file, &tmp_error))
        {
          const char *full_path_c;
 
+          bus_desktop_file_free (desktop_file);
+          desktop_file = NULL;
+          
           _dbus_string_get_const_data (&full_path, &full_path_c);
          
-         _dbus_verbose ("Could not add %s to activation entry list.\n", full_path_c);
+         _dbus_verbose ("Could not add %s to activation entry list: %s\n",
+                         full_path_c, tmp_error.message);
+
+          if (dbus_error_has_name (&tmp_error, DBUS_ERROR_NO_MEMORY))
+            {
+              dbus_move_error (&tmp_error, error);
+              goto failed;
+            }
+
+          dbus_error_free (&tmp_error);
+         continue;
        }
+      else
+        {
+          bus_desktop_file_free (desktop_file);
+          desktop_file = NULL;
+          continue;
+        }
+    }
 
-      bus_desktop_file_free (desktop_file);
-      _dbus_string_free (&full_path);
+  if (dbus_error_is_set (&tmp_error))
+    {
+      dbus_move_error (&tmp_error, error);
+      goto failed;
     }
+  
+  return TRUE;
+  
+ failed:
+  _DBUS_ASSERT_ERROR_IS_SET (error);
+  
+  if (iter != NULL)
+    _dbus_directory_close (iter);
+  if (desktop_file)
+    bus_desktop_file_free (desktop_file);
+  _dbus_string_free (&filename);
+  _dbus_string_free (&full_path);
+  
+  return FALSE;
 }
 
-
-void
-bus_activation_init (const char *address,
-                    const char **directories)
+dbus_bool_t
+bus_activation_init (const char  *address,
+                    const char **directories,
+                     DBusError   *error)
 {
   int i;
 
+  _dbus_assert (server_address == NULL);
+  _dbus_assert (activation_entries == NULL);
+  
   /* FIXME: We should split up the server addresses. */
-  BUS_HANDLE_OOM (server_address = _dbus_strdup (address));
+  server_address = _dbus_strdup (address);
+  if (server_address == NULL)
+    {
+      BUS_SET_OOM (error);
+      goto failed;
+    }
   
-  BUS_HANDLE_OOM (activation_entries = _dbus_hash_table_new (DBUS_HASH_STRING, NULL,
-                                                            (DBusFreeFunction)bus_activation_entry_free));
-
-  i = 0;
+  activation_entries = _dbus_hash_table_new (DBUS_HASH_STRING, NULL,
+                                             (DBusFreeFunction)bus_activation_entry_free);
+  if (activation_entries == NULL)
+    {      
+      BUS_SET_OOM (error);
+      goto failed;
+    }
 
   /* Load service files */
+  i = 0;
   while (directories[i] != NULL)
     {
-      load_directory (directories[i]);
-      i++;
+      if (!load_directory (directories[i], error))
+        goto failed;
+      ++i;
     }
+
+  return TRUE;
+  
+ failed:
+  dbus_free (server_address);
+  if (activation_entries)
+    _dbus_hash_table_unref (activation_entries);
+  
+  return FALSE;
 }
 
 static void
 child_setup (void *data)
 {
-  /* FIXME: Check return value in case of OOM */
-  _dbus_setenv ("DBUS_ADDRESS", server_address);
+  /* If no memory, we simply have the child exit, so it won't try
+   * to connect to the wrong thing.
+   */
+  if (!_dbus_setenv ("DBUS_ADDRESS", server_address))
+    _dbus_exit (1);
 }
 
 dbus_bool_t
@@ -220,6 +335,10 @@ bus_activation_activate_service (const char  *service_name,
       return FALSE;
     }
 
+  /* FIXME we need to support a full command line, not just a single
+   * argv[0]
+   */
+  
   /* Now try to spawn the process */
   argv[0] = entry->exec;
   argv[1] = NULL;
index 5f29871..e7a9cdf 100644 (file)
@@ -26,8 +26,9 @@
 
 #include <dbus/dbus.h>
 
-void        bus_activation_init             (const char  *address,
-                                            const char **paths);
+dbus_bool_t bus_activation_init             (const char  *address,
+                                            const char **paths,
+                                             DBusError   *error);
 dbus_bool_t bus_activation_activate_service (const char  *service_name,
                                             DBusError   *error);
 
index 40bbc32..ff671c5 100644 (file)
 #include "dispatch.h"
 #include "loop.h"
 #include "services.h"
+#include "utils.h"
 #include <dbus/dbus-list.h>
 
+static void bus_connection_remove_transactions (DBusConnection *connection);
+
 static int connection_data_slot;
 static DBusList *connections = NULL;
 
 typedef struct
 {
+  DBusConnection *connection;
   DBusList *services_owned;
-
   char *name;
+  DBusList *transaction_messages; /**< Stuff we need to send as part of a transaction */
+  DBusMessage *oom_message;
+  DBusPreallocatedSend *oom_preallocated;
 } BusConnectionData;
 
 #define BUS_CONNECTION_DATA(connection) (dbus_connection_get_data ((connection), connection_data_slot))
 
 void
-bus_connection_disconnect (DBusConnection *connection)
+bus_connection_disconnected (DBusConnection *connection)
 {
   BusConnectionData *d;
   BusService *service;
-
+  
   _dbus_warn ("Disconnected\n");
 
   d = BUS_CONNECTION_DATA (connection);
   _dbus_assert (d != NULL);  
 
-  /* Drop any service ownership */
-  while ((service = _dbus_list_get_last (&d->services_owned)))
-    bus_service_remove_owner (service, connection);
+  /* Drop any service ownership. FIXME Unfortunately, this requires
+   * memory allocation and there doesn't seem to be a good way to
+   * handle it other than sleeping; we can't "fail" the operation of
+   * disconnecting a client, and preallocating a broadcast "service is
+   * now gone" message for every client-service pair seems kind of
+   * involved. Probably we need to do that though, and also
+   * extend BusTransaction to be able to revert generic
+   * stuff, not just sending a message (so we can e.g. revert
+   * removal of service owners).
+   */
+  {
+    BusTransaction *transaction;
+    DBusError error;
+
+    dbus_error_init (&error);
+
+    transaction = NULL;
+    while (transaction == NULL)
+      {
+        transaction = bus_transaction_new ();
+        bus_wait_for_memory ();
+      }
+    
+    while ((service = _dbus_list_get_last (&d->services_owned)))
+      {
+      retry:
+        if (!bus_service_remove_owner (service, connection,
+                                       transaction, &error))
+          {
+            if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
+              {
+                dbus_error_free (&error);
+                bus_wait_for_memory ();
+                goto retry;
+              }
+            else
+              _dbus_assert_not_reached ("Removing service owner failed for non-memory-related reason");
+          }
+      }
+
+    bus_transaction_execute_and_free (transaction);
+  }
 
   bus_dispatch_remove_connection (connection);
   
@@ -60,12 +105,14 @@ bus_connection_disconnect (DBusConnection *connection)
                                        NULL, NULL,
                                        connection,
                                        NULL);
+
+  bus_connection_remove_transactions (connection);
   
   dbus_connection_set_data (connection,
                             connection_data_slot,
                             NULL, NULL);
   
-  _dbus_list_remove (&connections, connection);    
+  _dbus_list_remove (&connections, connection);
   dbus_connection_unref (connection);
 }
 
@@ -106,7 +153,14 @@ free_connection_data (void *data)
 
   /* services_owned should be NULL since we should be disconnected */
   _dbus_assert (d->services_owned == NULL);
+  /* similarly */
+  _dbus_assert (d->transaction_messages == NULL);
 
+  if (d->oom_preallocated)
+    dbus_connection_free_preallocated_send (d->connection, d->oom_preallocated);
+  if (d->oom_message)
+    dbus_message_unref (d->oom_message);
+  
   dbus_free (d->name);
   
   dbus_free (d);
@@ -132,6 +186,8 @@ bus_connection_setup (DBusConnection *connection)
   
   if (d == NULL)
     return FALSE;
+
+  d->connection = connection;
   
   if (!dbus_connection_set_data (connection,
                                  connection_data_slot,
@@ -163,6 +219,88 @@ bus_connection_setup (DBusConnection *connection)
   return TRUE;
 }
 
+/**
+ * Checks whether the connection is registered with the message bus.
+ *
+ * @param connection the connection
+ * @returns #TRUE if we're an active message bus participant
+ */
+dbus_bool_t
+bus_connection_is_active (DBusConnection *connection)
+{
+  BusConnectionData *d;
+
+  d = BUS_CONNECTION_DATA (connection);
+  
+  return d != NULL && d->name != NULL;
+}
+
+dbus_bool_t
+bus_connection_preallocate_oom_error (DBusConnection *connection)
+{
+  DBusMessage *message;
+  DBusPreallocatedSend *preallocated;
+  BusConnectionData *d;
+
+  d = BUS_CONNECTION_DATA (connection);  
+
+  _dbus_assert (d != NULL);
+
+  if (d->oom_preallocated != NULL)
+    return TRUE;
+  
+  preallocated = dbus_connection_preallocate_send (connection);
+  if (preallocated == NULL)
+    return FALSE;
+
+  message = dbus_message_new (DBUS_SERVICE_DBUS,
+                              DBUS_ERROR_NO_MEMORY);
+  if (message == NULL)
+    {
+      dbus_connection_free_preallocated_send (connection, preallocated);
+      return FALSE;
+    }
+
+  /* set reply serial to placeholder value just so space is already allocated
+   * for it.
+   */
+  if (!dbus_message_set_reply_serial (message, 14))
+    {
+      dbus_connection_free_preallocated_send (connection, preallocated);
+      dbus_message_unref (message);
+      return FALSE;
+    }
+
+  d->oom_message = message;
+  d->oom_preallocated = preallocated;
+  
+  return TRUE;
+}
+
+void
+bus_connection_send_oom_error (DBusConnection *connection,
+                               DBusMessage    *in_reply_to)
+{
+  BusConnectionData *d;
+
+  d = BUS_CONNECTION_DATA (connection);  
+
+  _dbus_assert (d != NULL);  
+  _dbus_assert (d->oom_message != NULL);
+
+  /* should always succeed since we set it to a placeholder earlier */
+  if (!dbus_message_set_reply_serial (d->oom_message,
+                                      dbus_message_get_serial (in_reply_to)))
+    _dbus_assert_not_reached ("Failed to set reply serial for preallocated oom message");
+
+  dbus_connection_send_preallocated (connection, d->oom_preallocated,
+                                     d->oom_message, NULL);
+
+  dbus_message_unref (d->oom_message);
+  d->oom_message = NULL;
+  d->oom_preallocated = NULL;
+}
+
 dbus_bool_t
 bus_connection_add_owned_service (DBusConnection *connection,
                                   BusService     *service)
@@ -223,9 +361,277 @@ bus_connection_get_name (DBusConnection *connection)
   return d->name;
 }
 
+/**
+ * Calls function on each connection; if the function returns
+ * #FALSE, stops iterating.
+ *
+ * @param function the function
+ * @param data data to pass to it as a second arg
+ */
 void
 bus_connection_foreach (BusConnectionForeachFunction  function,
                        void                         *data)
 {
-  _dbus_list_foreach (&connections, (DBusForeachFunction)function, data);
+  DBusList *link;
+  
+  link = _dbus_list_get_first_link (&connections);
+  while (link != NULL)
+    {
+      DBusConnection *connection = link->data;
+      DBusList *next = _dbus_list_get_next_link (&connections, link);
+
+      if (!(* function) (connection, data))
+        break;
+      
+      link = next;
+    }
+}
+
+typedef struct
+{
+  BusTransaction *transaction;
+  DBusMessage    *message;
+  DBusPreallocatedSend *preallocated;
+} MessageToSend;
+
+struct BusTransaction
+{
+  DBusList *connections;
+
+};
+
+static void
+message_to_send_free (DBusConnection *connection,
+                      MessageToSend  *to_send)
+{
+  if (to_send->message)
+    dbus_message_unref (to_send->message);
+
+  if (to_send->preallocated)
+    dbus_connection_free_preallocated_send (connection, to_send->preallocated);
+
+  dbus_free (to_send);
+}
+
+BusTransaction*
+bus_transaction_new (void)
+{
+  BusTransaction *transaction;
+
+  transaction = dbus_new0 (BusTransaction, 1);
+  if (transaction == NULL)
+    return NULL;
+
+  return transaction;
+}
+
+dbus_bool_t
+bus_transaction_send_message (BusTransaction *transaction,
+                              DBusConnection *connection,
+                              DBusMessage    *message)
+{
+  MessageToSend *to_send;
+  BusConnectionData *d;
+  DBusList *link;
+
+  if (!dbus_connection_get_is_connected (connection))
+    return TRUE; /* silently ignore disconnected connections */
+  
+  d = BUS_CONNECTION_DATA (connection);
+  _dbus_assert (d != NULL);
+  
+  to_send = dbus_new (MessageToSend, 1);
+  if (to_send == NULL)
+    {
+      return FALSE;
+    }
+
+  to_send->preallocated = dbus_connection_preallocate_send (connection);
+  if (to_send->preallocated == NULL)
+    {
+      dbus_free (to_send);
+      return FALSE;
+    }  
+  
+  dbus_message_ref (message);
+  to_send->message = message;
+  to_send->transaction = transaction;
+
+  if (!_dbus_list_prepend (&d->transaction_messages, to_send))
+    {
+      message_to_send_free (connection, to_send);
+      return FALSE;
+    }
+  
+  /* See if we already had this connection in the list
+   * for this transaction. If we have a pending message,
+   * then we should already be in transaction->connections
+   */
+  link = _dbus_list_get_first_link (&d->transaction_messages);
+  _dbus_assert (link->data == to_send);
+  link = _dbus_list_get_next_link (&d->transaction_messages, link);
+  while (link != NULL)
+    {
+      MessageToSend *m = link->data;
+      DBusList *next = _dbus_list_get_next_link (&d->transaction_messages, link);
+      
+      if (m->transaction == transaction)
+        break;
+        
+      link = next;
+    }
+
+  if (link == NULL)
+    {
+      if (!_dbus_list_prepend (&transaction->connections, connection))
+        {
+          _dbus_list_remove (&d->transaction_messages, to_send);
+          message_to_send_free (connection, to_send);
+          return FALSE;
+        }
+    }
+
+  return TRUE;
+}
+
+static void
+connection_cancel_transaction (DBusConnection *connection,
+                               BusTransaction *transaction)
+{
+  DBusList *link;
+  BusConnectionData *d;
+  
+  d = BUS_CONNECTION_DATA (connection);
+  _dbus_assert (d != NULL);
+  
+  link = _dbus_list_get_first_link (&d->transaction_messages);
+  while (link != NULL)
+    {
+      MessageToSend *m = link->data;
+      DBusList *next = _dbus_list_get_next_link (&d->transaction_messages, link);
+      
+      if (m->transaction == transaction)
+        {
+          _dbus_list_remove_link (&d->transaction_messages,
+                                  link);
+          
+          message_to_send_free (connection, m);
+        }
+        
+      link = next;
+    }
+}
+
+void
+bus_transaction_cancel_and_free (BusTransaction *transaction)
+{
+  DBusConnection *connection;
+  
+  while ((connection = _dbus_list_pop_first (&transaction->connections)))
+    connection_cancel_transaction (connection, transaction);
+
+  _dbus_assert (transaction->connections == NULL);
+
+  dbus_free (transaction);
+}
+
+static void
+connection_execute_transaction (DBusConnection *connection,
+                                BusTransaction *transaction)
+{
+  DBusList *link;
+  BusConnectionData *d;
+  
+  d = BUS_CONNECTION_DATA (connection);
+  _dbus_assert (d != NULL);
+
+  /* Send the queue in order (FIFO) */
+  link = _dbus_list_get_last_link (&d->transaction_messages);
+  while (link != NULL)
+    {
+      MessageToSend *m = link->data;
+      DBusList *prev = _dbus_list_get_prev_link (&d->transaction_messages, link);
+      
+      if (m->transaction == transaction)
+        {
+          _dbus_list_remove_link (&d->transaction_messages,
+                                  link);
+
+          dbus_connection_send_preallocated (connection,
+                                             m->preallocated,
+                                             m->message,
+                                             NULL);
+
+          m->preallocated = NULL; /* so we don't double-free it */
+          
+          message_to_send_free (connection, m);
+        }
+        
+      link = prev;
+    }
+}
+
+void
+bus_transaction_execute_and_free (BusTransaction *transaction)
+{
+  /* For each connection in transaction->connections
+   * send the messages
+   */
+  DBusConnection *connection;
+  
+  while ((connection = _dbus_list_pop_first (&transaction->connections)))
+    connection_execute_transaction (connection, transaction);
+
+  _dbus_assert (transaction->connections == NULL);
+
+  dbus_free (transaction);
+}
+
+static void
+bus_connection_remove_transactions (DBusConnection *connection)
+{
+  MessageToSend *to_send;
+  BusConnectionData *d;
+  
+  d = BUS_CONNECTION_DATA (connection);
+  _dbus_assert (d != NULL);
+  
+  while ((to_send = _dbus_list_get_first (&d->transaction_messages)))
+    {
+      /* only has an effect for the first MessageToSend listing this transaction */
+      _dbus_list_remove (&to_send->transaction->connections,
+                         connection);
+
+      _dbus_list_remove (&d->transaction_messages, to_send);
+      message_to_send_free (connection, to_send);
+    }
+}
+
+/**
+ * Converts the DBusError to a message reply
+ */
+dbus_bool_t
+bus_transaction_send_error_reply (BusTransaction  *transaction,
+                                  DBusConnection  *connection,
+                                  const DBusError *error,
+                                  DBusMessage     *in_reply_to)
+{
+  DBusMessage *reply;
+
+  _dbus_assert (error != NULL);
+  _DBUS_ASSERT_ERROR_IS_SET (error);
+  
+  reply = dbus_message_new_error_reply (in_reply_to,
+                                        error->name,
+                                        error->message);
+  if (reply == NULL)
+    return FALSE;
+
+  if (!bus_transaction_send_message (transaction, connection, reply))
+    {
+      dbus_message_unref (reply);
+      return FALSE;
+    }
+
+  return TRUE;
 }
index 04ab1f0..a7a448a 100644 (file)
 #include <dbus/dbus.h>
 #include "services.h"
 
-typedef void (* BusConnectionForeachFunction) (DBusConnection *connection, 
-                                              void           *data);
+typedef dbus_bool_t (* BusConnectionForeachFunction) (DBusConnection *connection, 
+                                                      void           *data);
 
 dbus_bool_t bus_connection_init (void);
 
 dbus_bool_t bus_connection_setup (DBusConnection *connection);
 
+dbus_bool_t bus_connection_is_active (DBusConnection *connection);
+
+dbus_bool_t bus_connection_preallocate_oom_error (DBusConnection *connection);
+void        bus_connection_send_oom_error        (DBusConnection *connection,
+                                                  DBusMessage    *in_reply_to);
+
 /* called by services.c */
 dbus_bool_t bus_connection_add_owned_service    (DBusConnection *connection,
                                                  BusService     *service);
@@ -47,8 +53,20 @@ const char *bus_connection_get_name (DBusConnection               *connection);
 void        bus_connection_foreach  (BusConnectionForeachFunction  function,
                                     void                         *data);
 
-/* called by dispatch.c */
-void        bus_connection_disconnect (DBusConnection *connection);
+/* called by dispatch.c when the connection is dropped */
+void        bus_connection_disconnected (DBusConnection *connection);
+
+/* transaction API so we can send or not send a block of messages as a whole */
+BusTransaction* bus_transaction_new              (void);
+dbus_bool_t     bus_transaction_send_message     (BusTransaction  *transaction,
+                                                  DBusConnection  *connection,
+                                                  DBusMessage     *message);
+dbus_bool_t     bus_transaction_send_error_reply (BusTransaction  *transaction,
+                                                  DBusConnection  *connection,
+                                                  const DBusError *error,
+                                                  DBusMessage     *in_reply_to);
+void            bus_transaction_cancel_and_free  (BusTransaction  *transaction);
+void            bus_transaction_execute_and_free (BusTransaction  *transaction);
 
 
 #endif /* BUS_CONNECTION_H */
index 0ab6afc..65a0d76 100644 (file)
@@ -125,7 +125,7 @@ bus_desktop_file_free (BusDesktopFile *desktop_file)
   dbus_free (desktop_file);
 }
 
-static void
+static dbus_bool_t
 grow_lines_in_section (BusDesktopFileSection *section)
 {
   BusDesktopFileLine *lines;
@@ -137,14 +137,19 @@ grow_lines_in_section (BusDesktopFileSection *section)
   else
     new_n_lines = section->n_allocated_lines*2;
 
-  BUS_HANDLE_OOM (lines = dbus_realloc (section->lines,
-                                       sizeof (BusDesktopFileLine) * new_n_lines));
-  section->lines = lines;
+  lines = dbus_realloc (section->lines,
+                        sizeof (BusDesktopFileLine) * new_n_lines);
+
+  if (lines == NULL)
+    return FALSE;
   
+  section->lines = lines;
   section->n_allocated_lines = new_n_lines;
+
+  return TRUE;
 }
 
-static void
+static dbus_bool_t
 grow_sections (BusDesktopFile *desktop_file)
 {
   int new_n_sections;
@@ -155,21 +160,36 @@ grow_sections (BusDesktopFile *desktop_file)
   else
     new_n_sections = desktop_file->n_allocated_sections*2;
 
-  BUS_HANDLE_OOM (sections = dbus_realloc (desktop_file->sections,
-                                          sizeof (BusDesktopFileSection) * new_n_sections));
+  sections = dbus_realloc (desktop_file->sections,
+                           sizeof (BusDesktopFileSection) * new_n_sections);
+  if (sections == NULL)
+    return FALSE;
+  
   desktop_file->sections = sections;
   
   desktop_file->n_allocated_sections = new_n_sections;
+
+  return TRUE;
 }
 
 static char *
-unescape_string (const DBusString *str, int pos, int end_pos)
+unescape_string (BusDesktopFileParser *parser,
+                 const DBusString     *str,
+                 int                   pos,
+                 int                   end_pos,
+                 DBusError            *error)
 {
   char *retval, *q;
   
   /* len + 1 is enough, because unescaping never makes the
-   * string longer */
-  BUS_HANDLE_OOM (retval = dbus_malloc (end_pos - pos + 1));
+   * string longer
+   */
+  retval = dbus_malloc (end_pos - pos + 1);
+  if (retval == NULL)
+    {
+      BUS_SET_OOM (error);
+      return NULL;
+    }
 
   q = retval;
   
@@ -179,6 +199,8 @@ unescape_string (const DBusString *str, int pos, int end_pos)
        {
          /* Found an embedded null */
          dbus_free (retval);
+          report_error (parser, "Text to be unescaped contains embedded nul",
+                        BUS_DESKTOP_PARSE_ERROR_INVALID_ESCAPES, error);
          return NULL;
        }
 
@@ -190,6 +212,8 @@ unescape_string (const DBusString *str, int pos, int end_pos)
            {
              /* Escape at end of string */
              dbus_free (retval);
+              report_error (parser, "Text to be unescaped ended in \\",
+                            BUS_DESKTOP_PARSE_ERROR_INVALID_ESCAPES, error);
              return NULL;
            }
 
@@ -213,7 +237,9 @@ unescape_string (const DBusString *str, int pos, int end_pos)
            default:
             /* Invalid escape code */
             dbus_free (retval);
-            return NULL;
+             report_error (parser, "Text to be unescaped had invalid escape sequence",
+                           BUS_DESKTOP_PARSE_ERROR_INVALID_ESCAPES, error);
+             return NULL;
            }
          pos++;
        }
@@ -235,20 +261,34 @@ new_section (BusDesktopFile *desktop_file,
              const char     *name)
 {
   int n;
+  char *name_copy;
   
   if (desktop_file->n_allocated_sections == desktop_file->n_sections)
-    grow_sections (desktop_file);
-
-  n = desktop_file->n_sections++;
+    {
+      if (!grow_sections (desktop_file))
+        return NULL;
+    }
 
-  BUS_HANDLE_OOM (desktop_file->sections[n].section_name = _dbus_strdup (name));
+  name_copy = _dbus_strdup (name);
+  if (name_copy == NULL)
+    return NULL;
+  
+  n = desktop_file->n_sections + 1;
+  desktop_file->sections[n].section_name = name_copy;
 
   desktop_file->sections[n].n_lines = 0;
   desktop_file->sections[n].lines = NULL;
   desktop_file->sections[n].n_allocated_lines = 0;
 
-  grow_lines_in_section (&desktop_file->sections[n]);
+  if (!grow_lines_in_section (&desktop_file->sections[n]))
+    {
+      dbus_free (desktop_file->sections[n].section_name);
+      desktop_file->sections[n].section_name = NULL;
+      return NULL;
+    }
 
+  desktop_file->n_sections = n;
+  
   return &desktop_file->sections[n];  
 }
 
@@ -277,7 +317,10 @@ new_line (BusDesktopFileParser *parser)
   section = &parser->desktop_file->sections[parser->current_section];
 
   if (section->n_allocated_lines == section->n_lines)
-    grow_lines_in_section (section);
+    {
+      if (!grow_lines_in_section (section))
+        return NULL;
+    }
 
   line = &section->lines[section->n_lines++];
 
@@ -358,11 +401,12 @@ parse_section_start (BusDesktopFileParser *parser, DBusError *error)
       return FALSE;
     }
 
-  section_name = unescape_string (&parser->data, parser->pos + 1, line_end - 1);
+  section_name = unescape_string (parser,
+                                  &parser->data, parser->pos + 1, line_end - 1,
+                                  error);
 
   if (section_name == NULL)
     {
-      report_error (parser, "Invalid escaping in section name", BUS_DESKTOP_PARSE_ERROR_INVALID_ESCAPES, error);
       parser_free (parser);
       return FALSE;
     }
@@ -450,20 +494,39 @@ parse_key_value (BusDesktopFileParser *parser, DBusError *error)
 
   value_start = p;
   
-  value = unescape_string (&parser->data, value_start, line_end);
+  value = unescape_string (parser, &parser->data, value_start, line_end, error);
   if (value == NULL)
     {
-      report_error (parser, "Invalid escaping in value", BUS_DESKTOP_PARSE_ERROR_INVALID_ESCAPES, error);
       parser_free (parser);
       return FALSE;
     }
 
   line = new_line (parser);
-
-  BUS_HANDLE_OOM (_dbus_string_init (&key, key_end - key_start));
-  BUS_HANDLE_OOM (_dbus_string_copy_len (&parser->data, key_start, key_end - key_start,
-                                        &key, 0));
-  BUS_HANDLE_OOM (_dbus_string_steal_data (&key, &tmp));
+  if (line == NULL)
+    {
+      parser_free (parser);
+      return FALSE;
+    }
+  
+  if (!_dbus_string_init (&key, key_end - key_start))
+    {
+      parser_free (parser);
+      return FALSE;
+    }
+  
+  if (!_dbus_string_copy_len (&parser->data, key_start, key_end - key_start,
+                              &key, 0))
+    {
+      parser_free (parser);
+      return FALSE;
+    }
+  
+  if (!_dbus_string_steal_data (&key, &tmp))
+    {
+      parser_free (parser);
+      return FALSE;
+    }
+  
   _dbus_string_free (&key);
   
   line->key = tmp;
@@ -491,11 +554,11 @@ report_error (BusDesktopFileParser *parser,
     section_name = parser->desktop_file->sections[parser->current_section].section_name;
 
   if (section_name)
-    BUS_HANDLE_OOM (dbus_set_error (error, error_name,
-                                   "Error in section %s at line %d: %s\n", section_name, parser->line_num, message));
+    dbus_set_error (error, error_name,
+                    "Error in section %s at line %d: %s\n", section_name, parser->line_num, message);
   else
-    BUS_HANDLE_OOM (dbus_set_error (error, error_name,
-                                   "Error at line %d: %s\n", parser->line_num, message));
+    dbus_set_error (error, error_name,
+                    "Error at line %d: %s\n", parser->line_num, message);
 }
 
 #if 0
@@ -519,39 +582,52 @@ dump_desktop_file (BusDesktopFile *file)
 }
 #endif
 
-BusDesktopFile *
+BusDesktopFile*
 bus_desktop_file_load (DBusString *filename,
                       DBusError  *error)
 {
   DBusString str;
-  DBusResultCode result_code;
   BusDesktopFileParser parser;
+  DBusStat sb;
   
-  /* FIXME: Check file size so we don't try to load a ridicously large file. */
+  /* Clearly there's a race here, but it's just to make it unlikely
+   * that we do something silly, we still handle doing it below.
+   */
+  if (!_dbus_stat (filename, &sb, error))
+    return NULL;
 
-  BUS_HANDLE_OOM (_dbus_string_init (&str, _DBUS_INT_MAX));
+  if (sb.size > _DBUS_ONE_KILOBYTE * 128)
+    {
+      dbus_set_error (error, DBUS_ERROR_FAILED,
+                      "Desktop file size (%ld bytes) is too large", (long) sb.size);
+      return NULL;
+    }
   
-  BUS_HANDLE_OOM ((result_code = _dbus_file_get_contents (&str, filename)) !=
-                 DBUS_RESULT_NO_MEMORY);
+  if (!_dbus_string_init (&str, _DBUS_INT_MAX))
+    return NULL;
   
-  if (result_code != DBUS_RESULT_SUCCESS)
+  if (!_dbus_file_get_contents (&str, filename, error))
     {
       _dbus_string_free (&str);
-
-      /* FIXME: Set error */
       return NULL;
     }
 
   if (!_dbus_string_validate_utf8 (&str, 0, _dbus_string_get_length (&str)))
     {
       _dbus_string_free (&str);
-      
-      /* FIXME: Set error */
+      dbus_set_error (error, DBUS_ERROR_FAILED,
+                      "invalid UTF-8");   
+      return NULL;
+    }
+  
+  parser.desktop_file = dbus_new0 (BusDesktopFile, 1);
+  if (parser.desktop_file == NULL)
+    {
+      _dbus_string_free (&str);
+      BUS_SET_OOM (error);
       return NULL;
     }
   
-  BUS_HANDLE_OOM (parser.desktop_file = dbus_malloc0 (sizeof (BusDesktopFile)));
-
   parser.data = str;
   parser.line_num = 1;
   parser.pos = 0;
@@ -563,7 +639,10 @@ bus_desktop_file_load (DBusString *filename,
       if (_dbus_string_get_byte (&parser.data, parser.pos) == '[')
        {
          if (!parse_section_start (&parser, error))
-           return NULL;
+            {
+              _dbus_string_free (&parser.data);
+              return NULL;
+            }
        }
       else if (is_blank_line (&parser) ||
               _dbus_string_get_byte (&parser.data, parser.pos) == '#')
@@ -571,7 +650,10 @@ bus_desktop_file_load (DBusString *filename,
       else
        {
          if (!parse_key_value (&parser, error))
-           return NULL;
+            {
+              _dbus_string_free (&parser.data);
+              return NULL;
+            }
        }
     }
 
@@ -661,7 +743,13 @@ bus_desktop_file_get_string (BusDesktopFile  *desktop_file,
   if (!bus_desktop_file_get_raw (desktop_file, section, keyname, &raw))
     return FALSE;
 
-  BUS_HANDLE_OOM (*val = _dbus_strdup (raw));
+  *val = _dbus_strdup (raw);
+
+  /* FIXME we don't distinguish "key not found" from "out of memory" here,
+   * which is broken.
+   */
+  if (*val == NULL)
+    return FALSE;
   
   return TRUE;
 }
index 76e10a9..d9fe81a 100644 (file)
 
 static int message_handler_slot;
 
-static void
+typedef struct
+{
+  DBusMessage    *message;
+  BusTransaction *transaction;
+  DBusError      *error;
+} SendMessageData;
+
+static dbus_bool_t
 send_one_message (DBusConnection *connection, void *data)
 {
-  /* Only send messages to registered connections */
-  if (bus_connection_get_name (connection) == NULL)
-    return;
+  SendMessageData *d = data;
   
-  BUS_HANDLE_OOM (dbus_connection_send_message (connection, data, NULL, NULL));
+  if (!bus_connection_is_active (connection))
+    return TRUE;
+
+  if (!bus_transaction_send_message (d->transaction,
+                                     connection,
+                                     d->message))
+    {
+      BUS_SET_OOM (d->error);
+      return FALSE;
+    }
+
+  return TRUE;
 }
 
-void
-bus_dispatch_broadcast_message (DBusMessage *message)
+dbus_bool_t
+bus_dispatch_broadcast_message (BusTransaction *transaction,
+                                DBusMessage    *message,
+                                DBusError      *error)
 {
-  _dbus_assert (dbus_message_get_sender (message) != NULL);
-  
-  bus_connection_foreach (send_one_message, message);
+  DBusError tmp_error;
+  SendMessageData d;
   
+  _dbus_assert (dbus_message_get_sender (message) != NULL);
+
+  dbus_error_init (&tmp_error);
+  d.message = message;
+  d.transaction = transaction;
+  d.error = &tmp_error;
+  bus_connection_foreach (send_one_message, &d);
+
+  if (dbus_error_is_set (&tmp_error))
+    {
+      dbus_move_error (&tmp_error, error);
+      return FALSE;
+    }
+  else
+    return TRUE;
+}
+
+static dbus_bool_t
+send_service_nonexistent_error (BusTransaction *transaction,
+                                DBusConnection *connection,
+                                const char     *service_name,
+                                DBusMessage    *in_reply_to,
+                                DBusError      *error)
+{
+  DBusMessage *error_reply;
+  DBusString error_message;
+  const char *error_str;
+         
+  /* Trying to send a message to a non-existant service,
+   * bounce back an error message.
+   */
+         
+  if (!_dbus_string_init (&error_message, _DBUS_INT_MAX))
+    {
+      BUS_SET_OOM (error);
+      return FALSE;
+    }
+
+  if (!_dbus_string_append (&error_message, "Service \"") ||
+      !_dbus_string_append (&error_message, service_name) ||
+      !_dbus_string_append (&error_message, "does not exist"))
+    {
+      _dbus_string_free (&error_message);
+      BUS_SET_OOM (error);
+      return FALSE;
+    }
+              
+  _dbus_string_get_const_data (&error_message, &error_str);
+  error_reply = dbus_message_new_error_reply (in_reply_to,
+                                              DBUS_ERROR_SERVICE_DOES_NOT_EXIST,
+                                              error_str);
+
+  _dbus_string_free (&error_message);
+              
+  if (error_reply == NULL)
+    {
+      BUS_SET_OOM (error);
+      return FALSE;
+    }
+              
+  if (!bus_transaction_send_message (transaction, connection, error_reply))
+    {
+      dbus_message_unref (error_reply);
+      BUS_SET_OOM (error);
+      return FALSE;
+    }
+              
+  dbus_message_unref (error_reply);
+
+  return TRUE;
 }
 
 static DBusHandlerResult
@@ -56,76 +143,164 @@ bus_dispatch_message_handler (DBusMessageHandler *handler,
                              void               *user_data)
 {
   const char *sender, *service_name, *message_name;
+  DBusError error;
+  BusTransaction *transaction;
+
+  transaction = NULL;
+  dbus_error_init (&error);
   
-  /* Assign a sender to the message */
-  sender = bus_connection_get_name (connection);
-  BUS_HANDLE_OOM (dbus_message_set_sender (message, sender));
+  /* If we can't even allocate an OOM error, we just go to sleep
+   * until we can.
+   */
+  while (!bus_connection_preallocate_oom_error (connection))
+    bus_wait_for_memory ();
+  
+  /* Ref connection in case we disconnect it at some point in here */
+  dbus_connection_ref (connection);
 
   service_name = dbus_message_get_service (message);
   message_name = dbus_message_get_name (message);
+
+  _dbus_assert (message_name != NULL); /* DBusMessageLoader is supposed to check this */
+
+  /* If service_name is NULL, this is a message to the bus daemon, not intended
+   * to actually go "on the bus"; e.g. a peer-to-peer ping. Handle these
+   * immediately, especially disconnection messages.
+   */
+  if (service_name == NULL)
+    {
+      if (strcmp (message_name, DBUS_MESSAGE_LOCAL_DISCONNECT) == 0)
+        bus_connection_disconnected (connection);
+
+      /* DBusConnection also handles some of these automatically, we leave
+       * it to do so.
+       */
+      goto out;
+    }
+
+  _dbus_assert (service_name != NULL); /* this message is intended for bus routing */
   
-  /* TODO: Crashes if service_name == NULL */
+  /* Create our transaction */
+  transaction = bus_transaction_new ();
+  if (transaction == NULL)
+    {
+      BUS_SET_OOM (&error);
+      goto out;
+    }
   
-  /* See if the message is to the driver */
-  if (message_name && strcmp (message_name, DBUS_MESSAGE_LOCAL_DISCONNECT) == 0)
+  /* Assign a sender to the message */
+  if (bus_connection_is_active (connection))
     {
-      bus_connection_disconnect (connection);
+      sender = bus_connection_get_name (connection);
+      _dbus_assert (sender != NULL);
+      
+      if (!dbus_message_set_sender (message, sender))
+        {
+          BUS_SET_OOM (&error);
+          goto out;
+        }
     }
-  else if (strcmp (service_name, DBUS_SERVICE_DBUS) == 0)
+
+  if (strcmp (service_name, DBUS_SERVICE_DBUS) == 0) /* to bus driver */
     {
-      bus_driver_handle_message (connection, message);
+      if (!bus_driver_handle_message (connection, transaction, message, &error))
+        goto out;
     }
-  else if (sender == NULL)
+  else if (!bus_connection_is_active (connection)) /* clients must talk to bus driver first */
     {
       _dbus_verbose ("Received message from non-registered client. Disconnecting.\n");
       dbus_connection_disconnect (connection);
     }
-  else if (strcmp (service_name, DBUS_SERVICE_BROADCAST) == 0)
+  /* FIXME what if we un-special-case this service and just have a flag
+   * on services that all service owners will get messages to it, not just
+   * the primary owner.
+   */
+  else if (strcmp (service_name, DBUS_SERVICE_BROADCAST) == 0) /* spam! */
     {
-      bus_dispatch_broadcast_message (message);
+      if (!bus_dispatch_broadcast_message (transaction, message, &error))
+        goto out;
     }
-  else  
+  else  /* route to named service */
     {
       DBusString service_string;
       BusService *service;
 
       _dbus_string_init_const (&service_string, service_name);
-      service = bus_service_lookup (&service_string, FALSE);
-
-      if (!service)
-       {
-         DBusMessage *error_reply;
-         DBusString error_message;
-         const char *error_str;
-         
-         /* Trying to send a message to a non-existant service,
-            bounce back an error message. */
-         
-         BUS_HANDLE_OOM (_dbus_string_init (&error_message, _DBUS_INT_MAX));
-
-         BUS_HANDLE_OOM (_dbus_string_append (&error_message, "Service \""));
-         BUS_HANDLE_OOM (_dbus_string_append (&error_message, service_name));
-         BUS_HANDLE_OOM (_dbus_string_append (&error_message, "does not exist"));        
+      service = bus_service_lookup (&service_string);
 
-         _dbus_string_get_const_data (&error_message, &error_str);
-         BUS_HANDLE_OOM (error_reply = dbus_message_new_error_reply (message, DBUS_ERROR_SERVICE_DOES_NOT_EXIST,
-                                                                     error_str));
-         _dbus_string_free (&error_message);
+      if (service == NULL)
+        {
+          if (!send_service_nonexistent_error (transaction, connection,
+                                               service_name,
+                                               message, &error))
+            goto out;
+        }
+      else
+        {
+          _dbus_assert (bus_service_get_primary_owner (service) != NULL);
+      
+          /* Dispatch the message */
+          if (!bus_transaction_send_message (transaction,
+                                             bus_service_get_primary_owner (service),
+                                             message))
+            {
+              BUS_SET_OOM (&error);
+              goto out;
+            }
+        }
+    }
+  
+ out:
+  if (dbus_error_is_set (&error))
+    {
+      if (!dbus_connection_get_is_connected (connection))
+        {
+          /* If we disconnected it, we won't bother to send it any error
+           * messages.
+           */
+        }
+      else if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
+        {
+          bus_connection_send_oom_error (connection, message);
 
-         /* Dispatch the message */
-         BUS_HANDLE_OOM (dbus_connection_send_message (connection, error_reply, NULL, NULL));
-         dbus_message_unref (error_reply);
-       }
+          /* cancel transaction due to OOM */
+          if (transaction != NULL)
+            {
+              bus_transaction_cancel_and_free (transaction);
+              transaction = NULL;
+            }
+        }
       else
-       {
-         _dbus_assert (bus_service_get_primary_owner (service) != NULL);
+        {
+          /* Try to send the real error, if no mem to do that, send
+           * the OOM error
+           */
+          _dbus_assert (transaction != NULL);
+          
+          if (!bus_transaction_send_error_reply (transaction, connection,
+                                                 &error, message))
+            {
+              bus_connection_send_oom_error (connection, message);
+
+              /* cancel transaction due to OOM */
+              if (transaction != NULL)
+                {
+                  bus_transaction_cancel_and_free (transaction);
+                  transaction = NULL;
+                }
+            }
+        }
       
-         /* Dispatch the message */
-         BUS_HANDLE_OOM (dbus_connection_send_message (bus_service_get_primary_owner (service),
-                                                       message, NULL, NULL));
-       }
+      dbus_error_free (&error);
     }
 
+  if (transaction != NULL)
+    {
+      bus_transaction_execute_and_free (transaction);
+    }
+
+  dbus_connection_unref (connection);
+  
   return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
 }
 
index 2fe3479..c24170d 100644 (file)
 #define BUS_DISPATCH_H
 
 #include <dbus/dbus.h>
+#include "connection.h"
 
 dbus_bool_t bus_dispatch_add_connection    (DBusConnection *connection);
 void        bus_dispatch_remove_connection (DBusConnection *connection);
-void        bus_dispatch_broadcast_message (DBusMessage    *message);
-
+dbus_bool_t bus_dispatch_broadcast_message (BusTransaction *transaction,
+                                            DBusMessage    *message,
+                                            DBusError      *error);
 
 #endif /* BUS_DISPATCH_H */
index 80478e4..4698559 100644 (file)
 #include <dbus/dbus-internals.h>
 #include <string.h>
 
-static void bus_driver_send_welcome_message (DBusConnection *connection,
-                                            DBusMessage    *hello_message);
-
-void
-bus_driver_send_service_deleted (const char *service_name)
+static dbus_bool_t bus_driver_send_welcome_message (DBusConnection *connection,
+                                                    DBusMessage    *hello_message,
+                                                    BusTransaction *transaction,
+                                                    DBusError      *error);
+
+dbus_bool_t
+bus_driver_send_service_deleted (const char     *service_name,
+                                 BusTransaction *transaction,
+                                 DBusError      *error)
 {
   DBusMessage *message;
-
+  dbus_bool_t retval;
+  
   _dbus_verbose ("sending service deleted: %s\n", service_name);
   
-  BUS_HANDLE_OOM (message = dbus_message_new (DBUS_SERVICE_BROADCAST,
-                                             DBUS_MESSAGE_SERVICE_DELETED));
+  message = dbus_message_new (DBUS_SERVICE_BROADCAST,
+                              DBUS_MESSAGE_SERVICE_DELETED);
+  if (message == NULL)
+    {
+      BUS_SET_OOM (error);
+      return FALSE;
+    }
   
-  BUS_HANDLE_OOM (dbus_message_set_sender (message, DBUS_SERVICE_DBUS));
+  if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS) ||
+      !dbus_message_append_args (message,
+                                 DBUS_TYPE_STRING, service_name,
+                                 0))
+    {
+      dbus_message_unref (message);
+      BUS_SET_OOM (error);
+      return FALSE;
+    }
 
-  BUS_HANDLE_OOM (dbus_message_append_args (message,
-                                           DBUS_TYPE_STRING, service_name,
-                                           0));
-  bus_dispatch_broadcast_message (message);
-  dbus_message_unref (message);  
+  retval = bus_dispatch_broadcast_message (transaction, message, error);
+  dbus_message_unref (message);
+
+  return retval;
 }
 
-void
-bus_driver_send_service_created (const char *service_name)
+dbus_bool_t
+bus_driver_send_service_created (const char     *service_name,
+                                 BusTransaction *transaction,
+                                 DBusError      *error)
 {
   DBusMessage *message;
-
-  BUS_HANDLE_OOM (message = dbus_message_new (DBUS_SERVICE_BROADCAST,
-                                             DBUS_MESSAGE_SERVICE_CREATED));
+  dbus_bool_t retval;
+  
+  message = dbus_message_new (DBUS_SERVICE_BROADCAST,
+                              DBUS_MESSAGE_SERVICE_CREATED);
+  if (message == NULL)
+    {
+      BUS_SET_OOM (error);
+      return FALSE;
+    }
   
-  BUS_HANDLE_OOM (dbus_message_set_sender (message, DBUS_SERVICE_DBUS));
+  if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS))
+    {
+      dbus_message_unref (message);
+      BUS_SET_OOM (error);
+      return FALSE;
+    }
   
-  BUS_HANDLE_OOM (dbus_message_append_args (message,
-                                           DBUS_TYPE_STRING, service_name,
-                                           0));
-  bus_dispatch_broadcast_message (message);
+  if (!dbus_message_append_args (message,
+                                 DBUS_TYPE_STRING, service_name,
+                                 0))
+    {
+      dbus_message_unref (message);
+      BUS_SET_OOM (error);
+      return FALSE;
+    }
+  
+  retval = bus_dispatch_broadcast_message (transaction, message, error);
   dbus_message_unref (message);
+
+  return retval;
 }
 
-void
+dbus_bool_t
 bus_driver_send_service_lost (DBusConnection *connection,
-                             const char *service_name)
+                             const char     *service_name,
+                              BusTransaction *transaction,
+                              DBusError      *error)
 {
   DBusMessage *message;
 
-  BUS_HANDLE_OOM (message = dbus_message_new (DBUS_SERVICE_BROADCAST,
-                                             DBUS_MESSAGE_SERVICE_LOST));
+  message = dbus_message_new (bus_connection_get_name (connection),
+                              DBUS_MESSAGE_SERVICE_LOST);
+  if (message == NULL)
+    {
+      BUS_SET_OOM (error);
+      return FALSE;
+    }
   
-  BUS_HANDLE_OOM (dbus_message_set_sender (message, DBUS_SERVICE_DBUS));
-  BUS_HANDLE_OOM (dbus_message_append_args (message,
-                                           DBUS_TYPE_STRING, service_name,
-                                           0));
-  BUS_HANDLE_OOM (dbus_connection_send_message (connection, message, NULL, NULL));
+  if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS))
+    {
+      dbus_message_unref (message);
+      BUS_SET_OOM (error);
+      return FALSE;
+    }
   
-  dbus_message_unref (message);
+  if (!dbus_message_append_args (message,
+                                 DBUS_TYPE_STRING, service_name,
+                                 0))
+    {
+      dbus_message_unref (message);
+      BUS_SET_OOM (error);
+      return FALSE;
+    }
+
+  if (!bus_transaction_send_message (transaction, connection, message))
+    {
+      dbus_message_unref (message);
+      BUS_SET_OOM (error);
+      return FALSE;
+    }
+  else
+    {
+      dbus_message_unref (message);
+      return TRUE;
+    }
 }
 
-void
+dbus_bool_t
 bus_driver_send_service_acquired (DBusConnection *connection,
-                                 const char *service_name)
+                                  const char     *service_name,
+                                  BusTransaction *transaction,
+                                  DBusError      *error)
 {
   DBusMessage *message;
 
-  BUS_HANDLE_OOM (message = dbus_message_new (DBUS_SERVICE_BROADCAST,
-                                             DBUS_MESSAGE_SERVICE_ACQUIRED));
+  message = dbus_message_new (bus_connection_get_name (connection),
+                              DBUS_MESSAGE_SERVICE_ACQUIRED);
+  if (message == NULL)
+    {
+      BUS_SET_OOM (error);
+      return FALSE;
+    }
   
-  BUS_HANDLE_OOM (dbus_message_set_sender (message, DBUS_SERVICE_DBUS));
-  BUS_HANDLE_OOM (dbus_message_append_args (message,
-                                           DBUS_TYPE_STRING, service_name,
-                                           0));
-  BUS_HANDLE_OOM (dbus_connection_send_message (connection, message, NULL, NULL));
+  if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS))
+    {
+      dbus_message_unref (message);
+      BUS_SET_OOM (error);
+      return FALSE;
+    }
   
-  dbus_message_unref (message);
+  if (!dbus_message_append_args (message,
+                                 DBUS_TYPE_STRING, service_name,
+                                 0))
+    {
+      dbus_message_unref (message);
+      BUS_SET_OOM (error);
+      return FALSE;
+    }
+
+  if (!bus_transaction_send_message (transaction, connection, message))
+    {
+      dbus_message_unref (message);
+      BUS_SET_OOM (error);
+      return FALSE;
+    }
+  else
+    {
+      dbus_message_unref (message);
+      return TRUE;
+    }
 }
 
 static dbus_bool_t
@@ -154,7 +246,7 @@ create_unique_client_name (DBusString *str)
       next_minor_number += 1;
       
       /* Check if a client with the name exists */
-      if (bus_service_lookup (str, FALSE) == NULL)
+      if (bus_service_lookup (str) == NULL)
        break;
 
       /* drop the number again, try the next one. */
@@ -164,35 +256,65 @@ create_unique_client_name (DBusString *str)
   return TRUE;
 }
 
-static void
+static dbus_bool_t
 bus_driver_handle_hello (DBusConnection *connection,
-                        DBusMessage    *message)
+                         BusTransaction *transaction,
+                         DBusMessage    *message,
+                         DBusError      *error)
 {
   DBusString unique_name;
   BusService *service;
+  dbus_bool_t retval;
+  
+  if (!_dbus_string_init (&unique_name, _DBUS_INT_MAX))
+    {
+      BUS_SET_OOM (error);
+      return FALSE;
+    }
 
-  BUS_HANDLE_OOM (_dbus_string_init (&unique_name, _DBUS_INT_MAX));
-  BUS_HANDLE_OOM (create_unique_client_name (&unique_name));
+  retval = FALSE;
+  
+  if (!create_unique_client_name (&unique_name))
+    {
+      BUS_SET_OOM (error);
+      goto out_0;
+    }
 
-  BUS_HANDLE_OOM (bus_connection_set_name (connection, &unique_name));
-  BUS_HANDLE_OOM (dbus_message_set_sender (message,
-                                          bus_connection_get_name (connection)));
+  if (!bus_connection_set_name (connection, &unique_name))
+    {
+      BUS_SET_OOM (error);
+      goto out_0;
+    }
+  
+  if (!dbus_message_set_sender (message,
+                                bus_connection_get_name (connection)))
+    {
+      BUS_SET_OOM (error);
+      goto out_0;
+    }
   
-  BUS_HANDLE_OOM (bus_driver_send_welcome_message (connection, message));
+  if (!bus_driver_send_welcome_message (connection, message, transaction, error))
+    goto out_0;
 
   /* Create the service */
-  BUS_HANDLE_OOM (service = bus_service_lookup (&unique_name, TRUE));
-  bus_service_set_prohibit_replacement (service, TRUE);
+  service = bus_service_ensure (&unique_name, connection, transaction, error);
+  if (service == NULL)
+    goto out_0;
   
-  /* Add the connection as the owner */
-  BUS_HANDLE_OOM (bus_service_add_owner (service, connection));
+  bus_service_set_prohibit_replacement (service, TRUE);
 
+  retval = TRUE;
+  
+ out_0:
   _dbus_string_free (&unique_name);
+  return retval;
 }
 
-static void
+static dbus_bool_t
 bus_driver_send_welcome_message (DBusConnection *connection,
-                                DBusMessage    *hello_message)
+                                 DBusMessage    *hello_message,
+                                 BusTransaction *transaction,
+                                 DBusError      *error)
 {
   DBusMessage *welcome;
   const char *name;
@@ -200,209 +322,330 @@ bus_driver_send_welcome_message (DBusConnection *connection,
   name = bus_connection_get_name (connection);
   _dbus_assert (name != NULL);
   
-  BUS_HANDLE_OOM (welcome = dbus_message_new_reply (hello_message));
-  
-  BUS_HANDLE_OOM (dbus_message_set_sender (welcome, DBUS_SERVICE_DBUS));
-  
-  BUS_HANDLE_OOM (dbus_message_append_args (welcome,
-                                           DBUS_TYPE_STRING, name,
-                                           NULL));
+  welcome = dbus_message_new_reply (hello_message);
+  if (welcome == NULL)
+    {
+      BUS_SET_OOM (error);
+      return FALSE;
+    }
   
-  BUS_HANDLE_OOM (dbus_connection_send_message (connection, welcome, NULL, NULL));
+  if (!dbus_message_set_sender (welcome, DBUS_SERVICE_DBUS))
+    {
+      dbus_message_unref (welcome);
+      BUS_SET_OOM (error);
+      return FALSE;
+    }
   
-  dbus_message_unref (welcome);
+  if (!dbus_message_append_args (welcome,
+                                 DBUS_TYPE_STRING, name,
+                                 NULL))
+    {
+      dbus_message_unref (welcome);
+      BUS_SET_OOM (error);
+      return FALSE;
+    }
+
+  if (!bus_transaction_send_message (transaction, connection, welcome))
+    {
+      dbus_message_unref (welcome);
+      BUS_SET_OOM (error);
+      return FALSE;
+    }
+  else
+    {
+      dbus_message_unref (welcome);
+      return TRUE;
+    }
 }
 
-static void
+static dbus_bool_t
 bus_driver_handle_list_services (DBusConnection *connection,
-                                DBusMessage    *message)
+                                 BusTransaction *transaction,
+                                 DBusMessage    *message,
+                                 DBusError      *error)
 {
   DBusMessage *reply;
-  int len, i;
+  int len;
   char **services;
 
-  BUS_HANDLE_OOM (reply = dbus_message_new_reply (message));
-
-  BUS_HANDLE_OOM (services = bus_services_list (&len));
-
-  BUS_HANDLE_OOM (dbus_message_append_args (reply,
-                                           DBUS_TYPE_STRING_ARRAY, services, len,
-                                           0));
-
-  BUS_HANDLE_OOM (dbus_connection_send_message (connection, reply, NULL, NULL));
+  reply = dbus_message_new_reply (message);
+  if (reply == NULL)
+    {
+      BUS_SET_OOM (error);
+      return FALSE;
+    }
 
-  dbus_message_unref (reply);
+  services = bus_services_list (&len);
+  if (services == NULL)
+    {
+      dbus_message_unref (reply);
+      BUS_SET_OOM (error);
+      return FALSE;
+    }
+  
+  if (!dbus_message_append_args (reply,
+                                 DBUS_TYPE_STRING_ARRAY, services, len,
+                                 0))
+    {
+      dbus_free_string_array (services);
+      dbus_message_unref (reply);
+      BUS_SET_OOM (error);
+      return FALSE;
+    }
 
-  if (services != NULL)
+  dbus_free_string_array (services);
+  
+  if (!bus_transaction_send_message (transaction, connection, reply))
     {
-      for (i = 0; i < len; i++)
-        dbus_free (services[i]);
-      dbus_free (services);
+      dbus_message_unref (reply);
+      BUS_SET_OOM (error);
+      return FALSE;
+    }
+  else
+    {
+      dbus_message_unref (reply);
+      return TRUE;
     }
 }
 
-static void
+static dbus_bool_t
 bus_driver_handle_acquire_service (DBusConnection *connection,
-                                  DBusMessage    *message)
+                                   BusTransaction *transaction,
+                                   DBusMessage    *message,
+                                   DBusError      *error)
 {
   DBusMessage *reply;
-  DBusResultCode result;
   DBusString service_name;
   BusService *service;  
   char *name;
   int service_reply;
   int flags;
+  dbus_bool_t retval;
+  DBusConnection *old_owner;
+  DBusConnection *current_owner;
   
-  BUS_HANDLE_OOM ((result = dbus_message_get_args (message,
-                                                  DBUS_TYPE_STRING, &name,
-                                                  DBUS_TYPE_UINT32, &flags,
-                                                  0)) != DBUS_RESULT_NO_MEMORY);
+  if (!dbus_message_get_args (message,
+                              error,
+                              DBUS_TYPE_STRING, &name,
+                              DBUS_TYPE_UINT32, &flags,
+                              0))
+    return FALSE;
   
-  if (result != DBUS_RESULT_SUCCESS)
-    {
-      dbus_free (name);
-      dbus_connection_disconnect (connection);
-      return;
-    }
+  _dbus_verbose ("Trying to own service %s with flags 0x%x\n", name, flags);
 
-  _dbus_verbose ("Trying to own service %s with flags %d\n", name, flags);
+  retval = FALSE;
+  reply = NULL;
 
   _dbus_string_init_const (&service_name, name);
-  service = bus_service_lookup (&service_name, TRUE);
+  
+  service = bus_service_lookup (&service_name);
 
-  BUS_HANDLE_OOM ((reply = dbus_message_new_reply (message)));
+  if (service != NULL)
+    old_owner = bus_service_get_primary_owner (service);
+  else
+    old_owner = NULL;  
   
-  /*
-   * Check if the service already has an owner
-   */
-  if (bus_service_get_primary_owner (service) != NULL)
-    {
-      if (bus_service_has_owner (service, connection))
-       service_reply = DBUS_SERVICE_REPLY_ALREADY_OWNER;
-      else if (!(flags & DBUS_SERVICE_FLAG_REPLACE_EXISTING))
-       service_reply = DBUS_SERVICE_REPLY_SERVICE_EXISTS;
-      else
-       {
-         if (bus_service_get_prohibit_replacement (service))
-           {
-             
-             /* Queue the connection */
-             BUS_HANDLE_OOM (bus_service_add_owner (service, connection));
-             
-             service_reply = DBUS_SERVICE_REPLY_IN_QUEUE;
-           }
-         else
-           {
-             DBusConnection *owner;
-             
-             /* We can replace the primary owner */
-             owner = bus_service_get_primary_owner (service);
-
-             /* We enqueue the new owner and remove the first one because
-              * that will cause ServiceAcquired and ServiceLost messages to
-              * be sent.
-              */
-             BUS_HANDLE_OOM (bus_service_add_owner (service, connection));
-             bus_service_remove_owner (service, owner);
-             _dbus_assert (connection == bus_service_get_primary_owner (service));
-             service_reply = DBUS_SERVICE_REPLY_PRIMARY_OWNER;
-           }
-       }
+  reply = dbus_message_new_reply (message);
+  if (reply == NULL)
+    {
+      BUS_SET_OOM (error);
+      goto out;
     }
-  else
+
+  if (service == NULL)
     {
+      service = bus_service_ensure (&service_name, connection, transaction, error);
+      if (service == NULL)
+        goto out;
+    }
+
+  current_owner = bus_service_get_primary_owner (service);
+
+  if (old_owner == NULL)
+    {
+      _dbus_assert (current_owner == connection);
+
       bus_service_set_prohibit_replacement (service,
-                                           (flags & DBUS_SERVICE_FLAG_PROHIBIT_REPLACEMENT));
+                                           (flags & DBUS_SERVICE_FLAG_PROHIBIT_REPLACEMENT));      
+                       
+      service_reply = DBUS_SERVICE_REPLY_PRIMARY_OWNER;      
+    }
+  else if (old_owner == connection)
+    service_reply = DBUS_SERVICE_REPLY_ALREADY_OWNER;
+  else if (!((flags & DBUS_SERVICE_FLAG_REPLACE_EXISTING)))
+    service_reply = DBUS_SERVICE_REPLY_SERVICE_EXISTS;
+  else if (bus_service_get_prohibit_replacement (service))
+    {
+      /* Queue the connection */
+      if (!bus_service_add_owner (service, connection,
+                                  transaction, error))
+        goto out;
       
-      /* Broadcast service created message */
-      bus_driver_send_service_created (bus_service_get_name (service));
+      service_reply = DBUS_SERVICE_REPLY_IN_QUEUE;
+    }
+  else
+    {
+      /* Replace the current owner */
+
+      /* We enqueue the new owner and remove the first one because
+       * that will cause ServiceAcquired and ServiceLost messages to
+       * be sent.
+       */
       
-      BUS_HANDLE_OOM (bus_service_add_owner (service, connection));
-                       
+      /* FIXME this is broken, if the remove_owner fails
+       * we don't undo the add_owner
+       * (easiest fix is probably to move all this to
+       * services.c and have a single routine for it)
+       */
+      
+      if (!bus_service_add_owner (service, connection,
+                                  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));
       service_reply = DBUS_SERVICE_REPLY_PRIMARY_OWNER;
     }
 
-  BUS_HANDLE_OOM (dbus_message_append_args (reply, DBUS_TYPE_UINT32, service_reply, 0));
+  if (!dbus_message_append_args (reply, DBUS_TYPE_UINT32, service_reply, 0))
+    {
+      BUS_SET_OOM (error);
+      goto out;
+    }
 
-  /* Send service reply */
-  BUS_HANDLE_OOM (dbus_connection_send_message (connection, reply, NULL, NULL));
+  if (!bus_transaction_send_message (transaction, connection, reply))
+    {
+      BUS_SET_OOM (error);
+      goto out;
+    }
+
+  retval = TRUE;
+  
+ out:
   dbus_free (name);
-  dbus_message_unref (reply);
-}
+  if (reply)
+    dbus_message_unref (reply);
+  return retval;
+} 
 
-static void
+static dbus_bool_t
 bus_driver_handle_service_exists (DBusConnection *connection,
-                                 DBusMessage    *message)
+                                  BusTransaction *transaction,
+                                  DBusMessage    *message,
+                                  DBusError      *error)
 {
   DBusMessage *reply;
-  DBusResultCode result;
   DBusString service_name;
   BusService *service;
   char *name;
+  dbus_bool_t retval;
   
-  BUS_HANDLE_OOM ((result = dbus_message_get_args (message,
-                                                  DBUS_TYPE_STRING, &name,
-                                                  0)) != DBUS_RESULT_NO_MEMORY);
-  if (result != DBUS_RESULT_SUCCESS)
-    {
-      dbus_free (name);
-      dbus_connection_disconnect (connection);
-      return;
-    }
+  if (!dbus_message_get_args (message, error,
+                              DBUS_TYPE_STRING, &name,
+                              0))
+    return FALSE;
 
+  retval = FALSE;
+  
   _dbus_string_init_const (&service_name, name);
-  service = bus_service_lookup (&service_name, FALSE);
+  service = bus_service_lookup (&service_name);
  
-  BUS_HANDLE_OOM ((reply = dbus_message_new_reply (message)));
-  BUS_HANDLE_OOM (dbus_message_set_sender (reply, DBUS_SERVICE_DBUS));
-
-  BUS_HANDLE_OOM (dbus_message_append_args (reply,
-                                           DBUS_TYPE_UINT32, service != NULL,
-                                           0));
-  BUS_HANDLE_OOM (dbus_connection_send_message (connection, reply, NULL, NULL));
-  dbus_message_unref (reply);
+  reply = dbus_message_new_reply (message);
+  if (reply == NULL)
+    {
+      BUS_SET_OOM (error);
+      goto out;
+    }
+  
+  if (!dbus_message_set_sender (reply, DBUS_SERVICE_DBUS))
+    {
+      BUS_SET_OOM (error);
+      goto out;
+    }
+
+  if (!dbus_message_append_args (reply,
+                                 DBUS_TYPE_UINT32, service != NULL,
+                                 0))
+    {
+      BUS_SET_OOM (error);
+      goto out;
+    }
+
+  if (!bus_transaction_send_message (transaction, connection, reply))
+    {
+      BUS_SET_OOM (error);
+      goto out;
+    }
+
+  retval = TRUE;
+  
+ out:
+  if (reply)
+    dbus_message_unref (reply);
   dbus_free (name);
+
+  return retval;
 }
 
-static void
+static dbus_bool_t
 bus_driver_handle_activate_service (DBusConnection *connection,
-                                   DBusMessage    *message)
+                                    BusTransaction *transaction,
+                                    DBusMessage    *message,
+                                    DBusError      *error)
 {
-  DBusResultCode result;
   dbus_uint32_t flags;
   char *name;
-  DBusError error;
+  dbus_bool_t retval;
   
-  BUS_HANDLE_OOM ((result = dbus_message_get_args (message,
-                                                  DBUS_TYPE_STRING, &name,
-                                                  DBUS_TYPE_UINT32, &flags,
-                                                  0)) != DBUS_RESULT_NO_MEMORY);
-  if (result != DBUS_RESULT_SUCCESS)
-    {
-      dbus_free (name);
-      dbus_connection_disconnect (connection);
-      return;
-    }
+  if (!dbus_message_get_args (message, error,
+                              DBUS_TYPE_STRING, &name,
+                              DBUS_TYPE_UINT32, &flags,
+                              0))
+    return FALSE;
 
-  if (!bus_activation_activate_service (name, &error))
-    {
-      DBusMessage *error_reply;
-      
-      BUS_HANDLE_OOM (error_reply = dbus_message_new_error_reply (message,
-                                                                 error.name, error.message));
-      dbus_error_free (&error);
+  retval = FALSE;
 
-      BUS_HANDLE_OOM (dbus_connection_send_message (connection, error_reply, NULL, NULL));
-      dbus_message_unref (error_reply);
-    }
+  if (!bus_activation_activate_service (name, error))
+    goto out;
+
+  retval = TRUE;
+  
+ out:
+  dbus_free (name);
+  return retval;
 }
 
-void
+/* For speed it might be useful to sort this in order of
+ * frequency of use (but doesn't matter with only a few items
+ * anyhow)
+ */
+struct
+{
+  const char *name;
+  dbus_bool_t (* handler) (DBusConnection *connection,
+                           BusTransaction *transaction,
+                           DBusMessage    *message,
+                           DBusError      *error);
+} message_handlers[] = {
+  { DBUS_MESSAGE_ACQUIRE_SERVICE, bus_driver_handle_acquire_service },
+  { DBUS_MESSAGE_ACTIVATE_SERVICE, bus_driver_handle_activate_service },
+  { DBUS_MESSAGE_HELLO, bus_driver_handle_hello },
+  { DBUS_MESSAGE_SERVICE_EXISTS, bus_driver_handle_service_exists },
+  { DBUS_MESSAGE_LIST_SERVICES, bus_driver_handle_list_services }
+};
+
+dbus_bool_t
 bus_driver_handle_message (DBusConnection *connection,
-                          DBusMessage    *message)
+                           BusTransaction *transaction,
+                          DBusMessage    *message,
+                           DBusError      *error)
 {
   const char *name, *sender;
-
+  int i;
+  
   _dbus_verbose ("Driver got a message: %s\n",
                 dbus_message_get_name (message));
   
@@ -411,26 +654,39 @@ bus_driver_handle_message (DBusConnection *connection,
 
   if (sender == NULL && (strcmp (name, DBUS_MESSAGE_HELLO) != 0))
     {
-      _dbus_verbose ("Trying to send a message without being registered. Disconnecting.\n");
+      dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
+                      "Client tried to send a message other than %s without being registered",
+                      DBUS_MESSAGE_HELLO);
+
       dbus_connection_disconnect (connection);
-      return;
-    }
-
-  /* Now check names. */
-  if (strcmp (name, DBUS_MESSAGE_HELLO) == 0)
-    bus_driver_handle_hello (connection, message);
-  else if (strcmp (name, DBUS_MESSAGE_LIST_SERVICES) == 0)
-    bus_driver_handle_list_services (connection, message);
-  else if (strcmp (name, DBUS_MESSAGE_ACQUIRE_SERVICE) == 0)
-    bus_driver_handle_acquire_service (connection, message);
-  else if (strcmp (name, DBUS_MESSAGE_SERVICE_EXISTS) == 0)
-    bus_driver_handle_service_exists (connection, message);
-  else if (strcmp (name, DBUS_MESSAGE_ACTIVATE_SERVICE) == 0)
-    bus_driver_handle_activate_service (connection, message);
+      return FALSE;
+    }
+
+  i = 0;
+  while (i < _DBUS_N_ELEMENTS (message_handlers))
+    {
+      if (strcmp (message_handlers[i].name, name) == 0)
+        {
+          if ((* message_handlers[i].handler) (connection, transaction, message, error))
+            return TRUE;
+          else
+            return FALSE;
+        }
+      
+      ++i;
+    }
+
+  dbus_set_error (error, DBUS_ERROR_UNKNOWN_MESSAGE,
+                  "%s does not understand message %s",
+                  DBUS_SERVICE_DBUS, name);
+  
+  return FALSE;
 }
 
 void
 bus_driver_remove_connection (DBusConnection *connection)
 {
-  /* Does nothing for now */
+  /* FIXME Does nothing for now, should unregister the connection
+   * with the bus driver.
+   */
 }
index 3019fe4..ac80c15 100644 (file)
 #define BUS_DRIVER_H
 
 #include <dbus/dbus.h>
+#include "connection.h"
 
-void bus_driver_remove_connection     (DBusConnection *connection);
-void bus_driver_handle_message        (DBusConnection *connection,
-                                      DBusMessage    *message);
-void bus_driver_send_service_deleted  (const char     *service_name);
-void bus_driver_send_service_lost     (DBusConnection *connection,
-                                      const char     *service_name);
-void bus_driver_send_service_acquired (DBusConnection *connection,
-                                      const char     *service_name);
-void bus_driver_send_service_created  (const char     *service_name);
-
-
+void        bus_driver_remove_connection     (DBusConnection *connection);
+dbus_bool_t bus_driver_handle_message        (DBusConnection *connection,
+                                              BusTransaction *transaction,
+                                              DBusMessage    *message,
+                                              DBusError      *error);
+dbus_bool_t bus_driver_send_service_deleted  (const char     *service_name,
+                                              BusTransaction *transaction,
+                                              DBusError      *error);
+dbus_bool_t bus_driver_send_service_lost     (DBusConnection *connection,
+                                              const char     *service_name,
+                                              BusTransaction *transaction,
+                                              DBusError      *error);
+dbus_bool_t bus_driver_send_service_acquired (DBusConnection *connection,
+                                              const char     *service_name,
+                                              BusTransaction *transaction,
+                                              DBusError      *error);
+dbus_bool_t bus_driver_send_service_created  (const char     *service_name,
+                                              BusTransaction *transaction,
+                                              DBusError      *error);
 
 #endif /* BUS_DRIVER_H */
index fdb6462..56345c7 100644 (file)
@@ -97,9 +97,18 @@ main (int argc, char **argv)
     }
   else
     {
-      char *paths[] = { argv[2], NULL };
+      const char *paths[] = { argv[2], NULL };
+      DBusError error;
 
-      bus_activation_init (argv[1], paths);
+      dbus_error_init (&error);
+      if (!bus_activation_init (argv[1], paths,
+                                &error))
+        {
+          _dbus_warn ("Could not initialize service activation: %s\n",
+                      error.message);
+          dbus_error_free (&error);
+          return 1;
+        }
     }
   
   setup_server (server);
index 497978d..22302af 100644 (file)
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
  */
-#include "driver.h"
-#include "services.h"
-#include "connection.h"
 #include <dbus/dbus-hash.h>
 #include <dbus/dbus-list.h>
 #include <dbus/dbus-mempool.h>
 
+#include "driver.h"
+#include "services.h"
+#include "connection.h"
+#include "utils.h"
+
 struct BusService
 {
   char *name;
   DBusList *owners;
-
-  unsigned int prohibit_replacement:1;
+  
+  unsigned int prohibit_replacement : 1;
 };
 
 static DBusHashTable *service_hash = NULL;
 static DBusMemPool   *service_pool = NULL;
 
-BusService*
-bus_service_lookup (const DBusString *service_name,
-                    dbus_bool_t       create_if_not_found)
+static dbus_bool_t
+init_hash (void)
 {
-  const char *c_name;
-  BusService *service;
-  
   if (service_hash == NULL)
     {
       service_hash = _dbus_hash_table_new (DBUS_HASH_STRING,
@@ -65,93 +63,182 @@ bus_service_lookup (const DBusString *service_name,
               _dbus_mem_pool_free (service_pool);
               service_pool = NULL;
             }
-          return NULL;
+          return FALSE;
         }
     }
+  return TRUE;
+}
+
+BusService*
+bus_service_lookup (const DBusString *service_name)
+{
+  const char *c_name;
+  BusService *service;
+  
+  if (!init_hash ())
+    return NULL;
   
   _dbus_string_get_const_data (service_name, &c_name);
 
   service = _dbus_hash_table_lookup_string (service_hash,
                                             c_name);
-  if (service != NULL)
-    return service;
 
-  if (!create_if_not_found)
+  return service;
+}
+
+BusService*
+bus_service_ensure (const DBusString          *service_name,
+                    DBusConnection            *owner_if_created,
+                    BusTransaction            *transaction,
+                    DBusError                 *error)
+{
+  const char *c_name;
+  BusService *service;
+
+  _dbus_assert (owner_if_created != NULL);
+  _dbus_assert (transaction != NULL);
+  
+  if (!init_hash ())
     return NULL;
   
+  _dbus_string_get_const_data (service_name, &c_name);
+
+  service = _dbus_hash_table_lookup_string (service_hash,
+                                            c_name);
+  if (service != NULL)
+    return service;
+  
   service = _dbus_mem_pool_alloc (service_pool);
   if (service == NULL)
-    return NULL;
+    {
+      BUS_SET_OOM (error);
+      return NULL;
+    }
 
   service->name = _dbus_strdup (c_name);
   if (service->name == NULL)
     {
       _dbus_mem_pool_dealloc (service_pool, service);
+      BUS_SET_OOM (error);
       return NULL;
     }
 
+  if (!bus_driver_send_service_created (service->name, transaction, error))
+    {
+      dbus_free (service->name);
+      _dbus_mem_pool_dealloc (service_pool, service);
+      return NULL;
+    }
+
+  if (!bus_service_add_owner (service, owner_if_created,
+                              transaction, error))
+    {
+      dbus_free (service->name);
+      _dbus_mem_pool_dealloc (service_pool, service);
+      return NULL;
+    }
+  
   if (!_dbus_hash_table_insert_string (service_hash,
                                        service->name,
                                        service))
     {
+      _dbus_list_clear (&service->owners);
       dbus_free (service->name);
       _dbus_mem_pool_dealloc (service_pool, service);
+      BUS_SET_OOM (error);
       return NULL;
     }
-
-  bus_driver_send_service_created (service->name);
   
   return service;
 }
 
 dbus_bool_t
 bus_service_add_owner (BusService     *service,
-                       DBusConnection *owner)
+                       DBusConnection *owner,
+                       BusTransaction *transaction,
+                       DBusError      *error)
 {
+ /* Send service acquired message first, OOM will result
+  * in cancelling the transaction
+  */
+  if (service->owners == NULL)
+    {
+      if (!bus_driver_send_service_acquired (owner, service->name, transaction, error))
+        return FALSE;
+    }
+  
   if (!_dbus_list_append (&service->owners,
                           owner))
-    return FALSE;
+    {
+      BUS_SET_OOM (error);
+      return FALSE;
+    }
 
   if (!bus_connection_add_owned_service (owner, service))
     {
       _dbus_list_remove_last (&service->owners, owner);
+      BUS_SET_OOM (error);
       return FALSE;
     }
-
- /* Send service acquired message */
-  if (bus_service_get_primary_owner (service) == owner)
-    bus_driver_send_service_acquired (owner, service->name);
   
   return TRUE;
 }
 
-void
+dbus_bool_t
 bus_service_remove_owner (BusService     *service,
-                          DBusConnection *owner)
+                          DBusConnection *owner,
+                          BusTransaction *transaction,
+                          DBusError      *error)
 {
+  /* We send out notifications before we do any work we
+   * might have to undo if the notification-sending failed
+   */
+  
   /* Send service lost message */
   if (bus_service_get_primary_owner (service) == owner)
-    bus_driver_send_service_lost (owner, service->name);
+    {
+      if (!bus_driver_send_service_lost (owner, service->name,
+                                         transaction, error))
+        return FALSE;
+    }
+
+  if (_dbus_list_length_is_one (&service->owners))
+    {
+      /* We are the only owner - send service deleted */
+      if (!bus_driver_send_service_deleted (service->name,
+                                            transaction, error))
+        return FALSE;
+    }
+  else
+    {
+      DBusList *link;
+      link = _dbus_list_get_first (&service->owners);
+      link = _dbus_list_get_next_link (&service->owners, link);
+
+      if (link != NULL)
+        {
+          /* This will be our new owner */
+          if (!bus_driver_send_service_acquired (link->data,
+                                                 service->name,
+                                                 transaction,
+                                                 error))
+            return FALSE;
+        }
+    }
   
   _dbus_list_remove_last (&service->owners, owner);
   bus_connection_remove_owned_service (owner, service);
 
   if (service->owners == NULL)
     {
-      /* Delete service */
-      bus_driver_send_service_deleted (service->name);
-      
+      /* Delete service (already sent message that it was deleted above) */
       _dbus_hash_table_remove_string (service_hash, service->name);
       
       dbus_free (service->name);
       _dbus_mem_pool_dealloc (service_pool, service);
     }
-  else 
-    {
-      /* Send service acquired to the new owner */
-      bus_driver_send_service_acquired (bus_service_get_primary_owner (service),
-                                       service->name);
-    }
+
+  return TRUE;
 }
 
 DBusConnection*
@@ -192,7 +279,7 @@ bus_services_list (int *array_len)
   DBusHashIter iter;
    
   len = _dbus_hash_table_get_n_entries (service_hash);
-  retval = dbus_new (char *, len);
+  retval = dbus_new (char *, len + 1);
 
   if (retval == NULL)
     return NULL;
@@ -210,6 +297,8 @@ bus_services_list (int *array_len)
       i++;
     }
 
+  retval[i] = NULL;
+  
   if (array_len)
     *array_len = len;
   
@@ -227,8 +316,6 @@ void
 bus_service_set_prohibit_replacement (BusService  *service,
                                      dbus_bool_t  prohibit_replacement)
 {
-  _dbus_assert (service->owners == NULL);
-  
   service->prohibit_replacement = prohibit_replacement != FALSE;
 }
 
index 3f6b31a..9758358 100644 (file)
 
 #include <dbus/dbus.h>
 #include <dbus/dbus-string.h>
+#include "connection.h"
+
+/* forward decl that probably shouldn't be in this file */
+typedef struct BusTransaction BusTransaction;
 
 /* Each service can have multiple owners; one owner is the "real
  * owner" and the others are queued up. For example, if I have
@@ -38,12 +42,19 @@ typedef struct BusService BusService;
 typedef void (* BusServiceForeachFunction) (BusService       *service,
                                             void             *data);
 
-BusService*     bus_service_lookup                   (const DBusString          *service_name,
-                                                     dbus_bool_t                create_if_not_found);
+BusService*     bus_service_lookup                   (const DBusString          *service_name);
+BusService*     bus_service_ensure                   (const DBusString          *service_name,
+                                                      DBusConnection            *owner_if_created,
+                                                      BusTransaction            *transaction,
+                                                      DBusError                 *error);
 dbus_bool_t     bus_service_add_owner                (BusService                *service,
-                                                     DBusConnection            *owner);
-void            bus_service_remove_owner             (BusService                *service,
-                                                     DBusConnection            *owner);
+                                                     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);
index 8663b1e..8b964cc 100644 (file)
@@ -25,6 +25,8 @@
 #include "utils.h"
 #include <dbus/dbus-sysdeps.h>
 
+const char bus_no_memory_message[] = "Memory allocation failure in message bus";
+
 void
 bus_wait_for_memory (void)
 {
index 5cbe284..41eb555 100644 (file)
@@ -25,8 +25,9 @@
 #ifndef BUS_UTILS_H
 #define BUS_UTILS_H
 
-#define BUS_HANDLE_OOM(stat) (stat)
-
 void bus_wait_for_memory (void);
 
+extern const char bus_no_memory_message[];
+#define BUS_SET_OOM(error) dbus_set_error ((error), DBUS_ERROR_NO_MEMORY, bus_no_memory_message)
+
 #endif /* BUS_ACTIVATION_H */
index fb8952b..25179ce 100644 (file)
@@ -27,9 +27,9 @@
 #include "dbus-list.h"
 
 /**
- * @defgroup DBusAddress address parsing
+ * @defgroup DBusAddress Address parsing
  * @ingroup  DBus
- * @brief Parsing addresses to DBus servers.
+ * @brief Parsing addresses of D-BUS servers.
  *
  * @{
  */
index 732b451..336d63e 100644 (file)
@@ -184,7 +184,7 @@ dbus_bool_t
 _dbus_auth_script_run (const DBusString *filename)
 {
   DBusString file;
-  DBusResultCode result;
+  DBusError error;
   DBusString line;
   dbus_bool_t retval;
   int line_no;
@@ -213,14 +213,14 @@ _dbus_auth_script_run (const DBusString *filename)
       _dbus_string_free (&line);
       return FALSE;
     }
-  
-  if ((result = _dbus_file_get_contents (&file, filename)) != DBUS_RESULT_SUCCESS)
-    {
+
+  dbus_error_init (&error);
+  if (!_dbus_file_get_contents (&file, filename, &error))    {
       const char *s;
       _dbus_string_get_const_data (filename, &s);
       _dbus_warn ("Getting contents of %s failed: %s\n",
-                  s, dbus_result_to_string (result));
-                     
+                  s, error.message);
+      dbus_error_free (&error);
       goto out;
     }
 
index 516a51a..8dfdc76 100644 (file)
@@ -514,7 +514,7 @@ sha1_handle_first_client_response (DBusAuth         *auth,
             }
           else
             {
-              _dbus_assert (dbus_error_is_set (&error));
+              _DBUS_ASSERT_ERROR_IS_SET (&error);
               _dbus_verbose ("Error loading keyring: %s\n",
                              error.message);
               if (send_rejected (auth))
@@ -535,7 +535,7 @@ sha1_handle_first_client_response (DBusAuth         *auth,
   auth->cookie_id = _dbus_keyring_get_best_key (auth->keyring, &error);
   if (auth->cookie_id < 0)
     {
-      _dbus_assert (dbus_error_is_set (&error));
+      _DBUS_ASSERT_ERROR_IS_SET (&error);
       _dbus_verbose ("Could not get a cookie ID to send to client: %s\n",
                      error.message);
       if (send_rejected (auth))
@@ -844,7 +844,8 @@ handle_client_data_cookie_sha1_mech (DBusAuth         *auth,
             }
           else
             {
-              _dbus_assert (dbus_error_is_set (&error));
+              _DBUS_ASSERT_ERROR_IS_SET (&error);
+
               _dbus_verbose ("Error loading keyring: %s\n",
                              error.message);
               
@@ -2238,7 +2239,7 @@ process_test_subdir (const DBusString          *test_base_dir,
   DBusString filename;
   DBusDirIter *dir;
   dbus_bool_t retval;
-  DBusResultCode result;
+  DBusError error;
 
   retval = FALSE;
   dir = NULL;
@@ -2258,22 +2259,23 @@ process_test_subdir (const DBusString          *test_base_dir,
   _dbus_string_free (&filename);
   if (!_dbus_string_init (&filename, _DBUS_INT_MAX))
     _dbus_assert_not_reached ("didn't allocate filename string\n");
-  
-  dir = _dbus_directory_open (&test_directory, &result);
+
+  dbus_error_init (&error);
+  dir = _dbus_directory_open (&test_directory, &error);
   if (dir == NULL)
     {
       const char *s;
       _dbus_string_get_const_data (&test_directory, &s);
       _dbus_warn ("Could not open %s: %s\n", s,
-                  dbus_result_to_string (result));
+                  error.message);
+      dbus_error_free (&error);
       goto failed;
     }
 
   printf ("Testing:\n");
   
-  result = DBUS_RESULT_SUCCESS;
  next:
-  while (_dbus_directory_get_next_file (dir, &filename, &result))
+  while (_dbus_directory_get_next_file (dir, &filename, &error))
     {
       DBusString full_path;
       
@@ -2311,12 +2313,13 @@ process_test_subdir (const DBusString          *test_base_dir,
         _dbus_string_free (&full_path);
     }
 
-  if (result != DBUS_RESULT_SUCCESS)
+  if (dbus_error_is_set (&error))
     {
       const char *s;
       _dbus_string_get_const_data (&test_directory, &s);
       _dbus_warn ("Could not get next file in %s: %s\n",
-                  s, dbus_result_to_string (result));
+                  s, error.message);
+      dbus_error_free (&error);
       goto failed;
     }
     
index 99ef5ad..cc612a7 100644 (file)
@@ -2,6 +2,7 @@
 /* dbus-bus.c  Convenience functions for communicating with the bus.
  *
  * Copyright (C) 2003  CodeFactory AB
+ * Copyright (C) 2003  Red Hat, Inc.
  *
  * Licensed under the Academic Free License version 1.2
  * 
 
 #include "dbus-bus.h"
 #include "dbus-protocol.h"
+#include "dbus-internals.h"
 
 /**
- * @defgroup DBusBus Convenience functinos for communicating with the bus.
+ * @defgroup DBusBus Message bus APIs
  * @ingroup DBus
- * @brief Convenience functinos for communicating with the bus.
+ * @brief Functions for communicating with the message bus
  *
  * @{
  */
 
 /**
- * Registers a connection with the bus. This is needed to send messages
- * to other clients.
+ * Registers a connection with the bus. This must be the first
+ * thing an application does when connecting to the message bus.
  *
- * @param connection The connection
- * @param result address where a result code can be returned. 
- * @returns the service name of which the client is known as.
+ * @todo if we get an error reply, it has to be converted into
+ * DBusError and returned
+ * 
+ * @param connection the connection
+ * @param error place to store errors
+ * @returns the client's unique service name, #NULL on error
  */
-char *
+char*
 dbus_bus_register_client (DBusConnection *connection,
-                         DBusResultCode *result)
+                          DBusError      *error)
 {
   DBusMessage *message, *reply;
-  DBusResultCode code;
   char *name;
   
   message = dbus_message_new (DBUS_SERVICE_DBUS,
@@ -53,56 +57,61 @@ dbus_bus_register_client (DBusConnection *connection,
 
   if (!message)
     {
-      dbus_set_result (result, DBUS_RESULT_NO_MEMORY);
+      _DBUS_SET_OOM (error);
       return NULL;
     }
   
-  reply = dbus_connection_send_message_with_reply_and_block (connection, message, -1, result);
+  reply = dbus_connection_send_with_reply_and_block (connection, message, -1, error);
 
   dbus_message_unref (message);
   
-  if (!reply)
-    return NULL;
-
-  code = dbus_message_get_args (reply,
-                               DBUS_TYPE_STRING, &name,
-                               0);
-  if (code != DBUS_RESULT_SUCCESS)
+  if (reply == NULL)
     {
-      dbus_set_result (result, code);
+      _DBUS_ASSERT_ERROR_IS_SET (error);
       return NULL;
     }
 
-  dbus_set_result (result, DBUS_RESULT_SUCCESS);
-                  
+  if (!dbus_message_get_args (reply, error,
+                              DBUS_TYPE_STRING, &name,
+                              0))
+    {
+      _DBUS_ASSERT_ERROR_IS_SET (error);
+      return NULL;
+    }
+  
   return name;
 }
 
 /**
  * Asks the bus to try to acquire a certain service.
  *
+ * @todo these docs are not complete, need to document the
+ * return value and flags
+ * 
+ * @todo if we get an error reply, it has to be converted into
+ * DBusError and returned
+ *
  * @param connection the connection
  * @param service_name the service name
  * @param flags flags
- * @param result address where a result code can be returned. 
- * @returns a result code.
+ * @param error location to store the error
+ * @returns a result code, -1 if error is set
  */ 
 int
 dbus_bus_acquire_service (DBusConnection *connection,
                          const char     *service_name,
                          unsigned int    flags,
-                         DBusResultCode *result)
+                          DBusError      *error)
 {
   DBusMessage *message, *reply;
   int service_result;
-  DBusResultCode code;
   
   message = dbus_message_new (DBUS_SERVICE_DBUS,
                               DBUS_MESSAGE_ACQUIRE_SERVICE);
 
-  if (!message)
+  if (message == NULL)
     {
-      dbus_set_result (result, DBUS_RESULT_NO_MEMORY);
+      _DBUS_SET_OOM (error);
       return -1;
     }
  
@@ -112,26 +121,28 @@ dbus_bus_acquire_service (DBusConnection *connection,
                                 0))
     {
       dbus_message_unref (message);
-      dbus_set_result (result, DBUS_RESULT_NO_MEMORY);
+      _DBUS_SET_OOM (error);
       return -1;
     }
   
-  reply = dbus_connection_send_message_with_reply_and_block (connection, message, -1, result);
+  reply = dbus_connection_send_with_reply_and_block (connection, message, -1,
+                                                     error);
+  
   dbus_message_unref (message);
   
-  if (!reply)
-    return -1;
-
-  code = dbus_message_get_args (reply,
-                               DBUS_TYPE_UINT32, &service_result,
-                               0);
-  if (code != DBUS_RESULT_SUCCESS)
+  if (reply == NULL)
     {
-      dbus_set_result (result, code);
+      _DBUS_ASSERT_ERROR_IS_SET (error);
       return -1;
     }
 
-  dbus_set_result (result, DBUS_RESULT_SUCCESS);
+  if (!dbus_message_get_args (reply, error,
+                              DBUS_TYPE_UINT32, &service_result,
+                              0))
+    {
+      _DBUS_ASSERT_ERROR_IS_SET (error);
+      return -1;
+    }
 
   return service_result;
 }
@@ -139,25 +150,26 @@ dbus_bus_acquire_service (DBusConnection *connection,
 /**
  * Checks whether a certain service exists.
  *
+ * @todo the SERVICE_EXISTS message should use BOOLEAN not UINT32
+ *
  * @param connection the connection
  * @param service_name the service name
- * @param result address where a result code can be returned. 
- * @returns #TRUE if the service exists, #FALSE otherwise.
+ * @param error location to store any errors
+ * @returns #TRUE if the service exists, #FALSE if not or on error
  */
 dbus_bool_t
 dbus_bus_service_exists (DBusConnection *connection,
                         const char     *service_name,
-                        DBusResultCode *result)
+                         DBusError      *error)
 {
   DBusMessage *message, *reply;
   unsigned int exists;
-  DBusResultCode code;
   
   message = dbus_message_new (DBUS_SERVICE_DBUS,
                               DBUS_MESSAGE_SERVICE_EXISTS);
-  if (!message)
+  if (message == NULL)
     {
-      dbus_set_result (result, DBUS_RESULT_NO_MEMORY);
+      _DBUS_SET_OOM (error);
       return FALSE;
     }
   
@@ -166,27 +178,27 @@ dbus_bus_service_exists (DBusConnection *connection,
                                 0))
     {
       dbus_message_unref (message);
-      dbus_set_result (result, DBUS_RESULT_NO_MEMORY);
+      _DBUS_SET_OOM (error);
       return FALSE;
     }
   
-  reply = dbus_connection_send_message_with_reply_and_block (connection, message, -1, result);
+  reply = dbus_connection_send_with_reply_and_block (connection, message, -1, error);
   dbus_message_unref (message);
 
-  if (!reply)
-    return FALSE;
+  if (reply == NULL)
+    {
+      _DBUS_ASSERT_ERROR_IS_SET (error);
+      return FALSE;
+    }
 
-  code = dbus_message_get_args (reply,
-                               DBUS_TYPE_UINT32, &exists,
-                               0);
-  if (code != DBUS_RESULT_SUCCESS)
+  if (!dbus_message_get_args (reply, error,
+                              DBUS_TYPE_UINT32, &exists,
+                              0))
     {
-      dbus_set_result (result, code);
+      _DBUS_ASSERT_ERROR_IS_SET (error);
       return FALSE;
     }
   
-  dbus_set_result (result, DBUS_RESULT_SUCCESS);
-  
   return (exists != FALSE);
 }
 
index 0bd8dec..d1c2bfd 100644 (file)
 
 #include <dbus/dbus-connection.h>
 
-char *      dbus_bus_register_client (DBusConnection *connection,
-                                     DBusResultCode *result);
+char      dbus_bus_register_client (DBusConnection *connection,
+                                      DBusError      *error);
 int         dbus_bus_acquire_service (DBusConnection *connection,
                                      const char     *service_name,
                                      unsigned int    flags,
-                                     DBusResultCode *result);
+                                      DBusError      *error);
 dbus_bool_t dbus_bus_service_exists  (DBusConnection *connection,
                                      const char     *service_name,
-                                     DBusResultCode *result);
+                                      DBusError      *error);
 
 
 #endif /* DBUS_BUS_H */
index 3611b87..bfc27e2 100644 (file)
@@ -187,7 +187,7 @@ _dbus_connection_queue_received_message (DBusConnection *connection,
     return FALSE;
 
   /* If this is a reply we're waiting on, remove timeout for it */
-  reply_serial = _dbus_message_get_reply_serial (message);
+  reply_serial = dbus_message_get_reply_serial (message);
   if (reply_serial != -1)
     {
       reply_handler_data = _dbus_hash_table_lookup_int (connection->pending_replies,
@@ -205,9 +205,11 @@ _dbus_connection_queue_received_message (DBusConnection *connection,
   connection->n_incoming += 1;
 
   _dbus_connection_wakeup_mainloop (connection);
-  
-  _dbus_verbose ("Incoming message %p added to queue, %d incoming\n",
-                 message, connection->n_incoming);
+
+  _dbus_assert (dbus_message_get_name (message) != NULL);
+  _dbus_verbose ("Incoming message %p (%s) added to queue, %d incoming\n",
+                 message, dbus_message_get_name (message),
+                 connection->n_incoming);
   
   return TRUE;
 }
@@ -963,54 +965,88 @@ dbus_connection_get_is_authenticated (DBusConnection *connection)
 }
 
 /**
- * Adds a message to the outgoing message queue. Does not block to
- * write the message to the network; that happens asynchronously. to
- * force the message to be written, call dbus_connection_flush().
+ * Preallocates resources needed to send a message, allowing the message 
+ * to be sent without the possibility of memory allocation failure.
+ * Allows apps to create a future guarantee that they can send
+ * a message regardless of memory shortages.
  *
- * If the function fails, it returns #FALSE and returns the
- * reason for failure via the result parameter.
- * The result parameter can be #NULL if you aren't interested
- * in the reason for the failure.
- * 
- * @param connection the connection.
- * @param message the message to write.
- * @param client_serial return location for client serial.
- * @param result address where result code can be placed.
- * @returns #TRUE on success.
+ * @param connection the connection we're preallocating for.
+ * @returns the preallocated resources, or #NULL
  */
-dbus_bool_t
-dbus_connection_send_message (DBusConnection *connection,
-                              DBusMessage    *message,
-                             dbus_int32_t   *client_serial,
-                              DBusResultCode *result)
+DBusPreallocatedSend*
+dbus_connection_preallocate_send (DBusConnection *connection)
+{
+  /* we store "connection" in the link just to enforce via
+   * assertion that preallocated links are only used
+   * with the connection they were created for.
+   */
+  return (DBusPreallocatedSend*) _dbus_list_alloc_link (connection);
+}
 
+/**
+ * Frees preallocated message-sending resources from
+ * dbus_connection_preallocate_send(). Should only
+ * be called if the preallocated resources are not used
+ * to send a message.
+ *
+ * @param connection the connection
+ * @param preallocated the resources
+ */
+void
+dbus_connection_free_preallocated_send (DBusConnection       *connection,
+                                        DBusPreallocatedSend *preallocated)
 {
-  dbus_int32_t serial;
+  DBusList *link = (DBusList*) preallocated;
+  _dbus_assert (link->data == connection);
+  _dbus_list_free_link (link);
+}
 
+/**
+ * Sends a message using preallocated resources. This function cannot fail.
+ * It works identically to dbus_connection_send() in other respects.
+ * Preallocated resources comes from dbus_connection_preallocate_send().
+ * This function "consumes" the preallocated resources, they need not
+ * be freed separately.
+ *
+ * @param connection the connection
+ * @param preallocated the preallocated resources
+ * @param message the message to send
+ * @param client_serial return location for client serial assigned to the message
+ */
+void
+dbus_connection_send_preallocated (DBusConnection       *connection,
+                                   DBusPreallocatedSend *preallocated,
+                                   DBusMessage          *message,
+                                   dbus_int32_t         *client_serial)
+{
+  DBusList *link = (DBusList*) preallocated;
+  dbus_int32_t serial;
+  
+  _dbus_assert (link->data == connection);
+  _dbus_assert (dbus_message_get_name (message) != NULL);
+  
   dbus_mutex_lock (connection->mutex);
 
-  if (!_dbus_list_prepend (&connection->outgoing_messages,
-                           message))
-    {
-      dbus_set_result (result, DBUS_RESULT_NO_MEMORY);
-      dbus_mutex_unlock (connection->mutex);
-      return FALSE;
-    }
+  link->data = message;
+  _dbus_list_prepend_link (&connection->outgoing_messages,
+                           link);
 
   dbus_message_ref (message);
   connection->n_outgoing += 1;
 
-  _dbus_verbose ("Message %p added to outgoing queue, %d pending to send\n",
-                 message, connection->n_outgoing);
+  _dbus_verbose ("Message %p (%s) added to outgoing queue, %d pending to send\n",
+                 message,
+                 dbus_message_get_name (message),
+                 connection->n_outgoing);
 
-  if (_dbus_message_get_client_serial (message) == -1)
+  if (dbus_message_get_serial (message) == -1)
     {
       serial = _dbus_connection_get_next_client_serial (connection);
-      _dbus_message_set_client_serial (message, serial);
+      _dbus_message_set_serial (message, serial);
     }
   
   if (client_serial)
-    *client_serial = _dbus_message_get_client_serial (message);
+    *client_serial = dbus_message_get_serial (message);
   
   _dbus_message_lock (message);
 
@@ -1021,8 +1057,43 @@ dbus_connection_send_message (DBusConnection *connection,
   _dbus_connection_wakeup_mainloop (connection);
 
   dbus_mutex_unlock (connection->mutex);
-  
-  return TRUE;
+}
+
+/**
+ * Adds a message to the outgoing message queue. Does not block to
+ * write the message to the network; that happens asynchronously. To
+ * force the message to be written, call dbus_connection_flush().
+ * Because this only queues the message, the only reason it can
+ * fail is lack of memory. Even if the connection is disconnected,
+ * no error will be returned.
+ *
+ * If the function fails, it returns #FALSE and returns the
+ * reason for failure via the result parameter.
+ * The result parameter can be #NULL if you aren't interested
+ * in the reason for the failure.
+ * 
+ * @param connection the connection.
+ * @param message the message to write.
+ * @param client_serial return location for client serial.
+ * @returns #TRUE on success.
+ */
+dbus_bool_t
+dbus_connection_send (DBusConnection *connection,
+                      DBusMessage    *message,
+                      dbus_int32_t   *client_serial)
+{
+  DBusPreallocatedSend *preallocated;
+
+  preallocated = dbus_connection_preallocate_send (connection);
+  if (preallocated == NULL)
+    {
+      return FALSE;
+    }
+  else
+    {
+      dbus_connection_send_preallocated (connection, preallocated, message, client_serial);
+      return TRUE;
+    }
 }
 
 static void
@@ -1100,25 +1171,19 @@ reply_handler_data_free (ReplyHandlerData *data)
  * you want a very short or very long timeout.  There is no way to
  * avoid a timeout entirely, other than passing INT_MAX for the
  * timeout to postpone it indefinitely.
- *
- * @todo I think we should rename this function family
- * dbus_connection_send(), send_with_reply(), etc. (i.e.
- * drop the "message" part), the names are too long.
  * 
  * @param connection the connection
  * @param message the message to send
  * @param reply_handler message handler expecting the reply, or #NULL
  * @param timeout_milliseconds timeout in milliseconds or -1 for default
- * @param result return location for result code
  * @returns #TRUE if the message is successfully queued, #FALSE if no memory.
  *
  */
 dbus_bool_t
-dbus_connection_send_message_with_reply (DBusConnection     *connection,
-                                         DBusMessage        *message,
-                                         DBusMessageHandler *reply_handler,
-                                         int                 timeout_milliseconds,
-                                         DBusResultCode     *result)
+dbus_connection_send_with_reply (DBusConnection     *connection,
+                                 DBusMessage        *message,
+                                 DBusMessageHandler *reply_handler,
+                                 int                 timeout_milliseconds)
 {
   DBusTimeout *timeout;
   ReplyHandlerData *data;
@@ -1132,10 +1197,7 @@ dbus_connection_send_message_with_reply (DBusConnection     *connection,
   data = dbus_new0 (ReplyHandlerData, 1);
 
   if (!data)
-    {
-      dbus_set_result (result, DBUS_RESULT_NO_MEMORY);
-      return FALSE;
-    }
+    return FALSE;
   
   timeout = _dbus_timeout_new (timeout_milliseconds, reply_handler_timeout,
                               data, NULL);
@@ -1143,7 +1205,6 @@ dbus_connection_send_message_with_reply (DBusConnection     *connection,
   if (!timeout)
     {
       reply_handler_data_free (data);
-      dbus_set_result (result, DBUS_RESULT_NO_MEMORY);
       return FALSE;
     }
 
@@ -1155,8 +1216,6 @@ dbus_connection_send_message_with_reply (DBusConnection     *connection,
       reply_handler_data_free (data);
       _dbus_timeout_unref (timeout);
       dbus_mutex_unlock (connection->mutex);
-      
-      dbus_set_result (result, DBUS_RESULT_NO_MEMORY);
       return FALSE;
     }
 
@@ -1171,17 +1230,15 @@ dbus_connection_send_message_with_reply (DBusConnection     *connection,
     {
       dbus_mutex_unlock (connection->mutex);
       reply_handler_data_free (data);
-      
-      dbus_set_result (result, DBUS_RESULT_NO_MEMORY);
       return FALSE;
     }
   data->connection_added = TRUE;
   
   /* Assign a serial to the message */
-  if (_dbus_message_get_client_serial (message) == -1)
+  if (dbus_message_get_serial (message) == -1)
     {
       serial = _dbus_connection_get_next_client_serial (connection);
-      _dbus_message_set_client_serial (message, serial);
+      _dbus_message_set_serial (message, serial);
     }
 
   data->handler = reply_handler;
@@ -1195,8 +1252,6 @@ dbus_connection_send_message_with_reply (DBusConnection     *connection,
     {
       dbus_mutex_unlock (connection->mutex);
       reply_handler_data_free (data);
-      
-      dbus_set_result (result, DBUS_RESULT_NO_MEMORY);
       return FALSE;
     }
 
@@ -1206,8 +1261,6 @@ dbus_connection_send_message_with_reply (DBusConnection     *connection,
       dbus_mutex_unlock (connection->mutex);
       dbus_message_unref (reply);
       reply_handler_data_free (data);
-      
-      dbus_set_result (result, DBUS_RESULT_NO_MEMORY);
       return FALSE;
     }
 
@@ -1216,23 +1269,20 @@ dbus_connection_send_message_with_reply (DBusConnection     *connection,
   /* Insert the serial in the pending replies hash. */
   if (!_dbus_hash_table_insert_int (connection->pending_replies, serial, data))
     {
-      dbus_set_result (result, DBUS_RESULT_NO_MEMORY);
       dbus_mutex_unlock (connection->mutex);
-      reply_handler_data_free (data);
-      
+      reply_handler_data_free (data);      
       return FALSE;
     }
 
   dbus_mutex_unlock (connection->mutex);
   
-  if (!dbus_connection_send_message (connection, message, NULL, result))
+  if (!dbus_connection_send (connection, message, NULL))
     {
       /* This will free the handler data too */
       _dbus_hash_table_remove_int (connection->pending_replies, serial);
       return FALSE;
     }
 
-  dbus_set_result (result, DBUS_RESULT_SUCCESS);  
   return TRUE;
 }
 
@@ -1242,9 +1292,9 @@ dbus_connection_send_message_with_reply (DBusConnection     *connection,
  * has been reached. This function is used to do non-reentrant "method calls."
  * If a reply is received, it is returned, and removed from the incoming
  * message queue. If it is not received, #NULL is returned and the
- * result is set to #DBUS_RESULT_NO_REPLY. If something else goes
+ * error is set to #DBUS_ERROR_NO_REPLY. If something else goes
  * wrong, result is set to whatever is appropriate, such as
- * #DBUS_RESULT_NO_MEMORY.
+ * #DBUS_ERROR_NO_MEMORY or #DBUS_ERROR_DISCONNECTED.
  *
  * @todo could use performance improvements (it keeps scanning
  * the whole message queue for example) and has thread issues,
@@ -1253,15 +1303,15 @@ dbus_connection_send_message_with_reply (DBusConnection     *connection,
  * @param connection the connection
  * @param message the message to send
  * @param timeout_milliseconds timeout in milliseconds or -1 for default
- * @param result return location for result code
+ * @param error return location for error message
  * @returns the message that is the reply or #NULL with an error code if the
  * function fails.
  */
 DBusMessage *
-dbus_connection_send_message_with_reply_and_block (DBusConnection     *connection,
-                                                  DBusMessage        *message,
-                                                  int                 timeout_milliseconds,
-                                                  DBusResultCode     *result)
+dbus_connection_send_with_reply_and_block (DBusConnection     *connection,
+                                           DBusMessage        *message,
+                                           int                 timeout_milliseconds,
+                                           DBusError          *error)
 {
   dbus_int32_t client_serial;
   DBusList *link;
@@ -1279,8 +1329,11 @@ dbus_connection_send_message_with_reply_and_block (DBusConnection     *connectio
   if (timeout_milliseconds > _DBUS_ONE_HOUR_IN_MILLISECONDS * 6)
     timeout_milliseconds = _DBUS_ONE_HOUR_IN_MILLISECONDS * 6;
   
-  if (!dbus_connection_send_message (connection, message, &client_serial, result))
-    return NULL;
+  if (!dbus_connection_send (connection, message, &client_serial))
+    {
+      _DBUS_SET_OOM (error);
+      return NULL;
+    }
 
   message = NULL;
   
@@ -1318,13 +1371,10 @@ dbus_connection_send_message_with_reply_and_block (DBusConnection     *connectio
     {
       DBusMessage *reply = link->data;
 
-      if (_dbus_message_get_reply_serial (reply) == client_serial)
+      if (dbus_message_get_reply_serial (reply) == client_serial)
        {
          _dbus_list_remove_link (&connection->incoming_messages, link);
          dbus_message_ref (reply);
-
-         if (result)
-           *result = DBUS_RESULT_SUCCESS;
          
          dbus_mutex_unlock (connection->mutex);
          return reply;
@@ -1345,14 +1395,14 @@ dbus_connection_send_message_with_reply_and_block (DBusConnection     *connectio
         (end_tv_usec - tv_usec) / 1000;
       _dbus_verbose ("%d milliseconds remain\n", timeout_milliseconds);
       _dbus_assert (timeout_milliseconds > 0);
-
+      
       goto block_again; /* not expired yet */
     }
-
+  
   if (dbus_connection_get_is_connected (connection))
-    dbus_set_result (result, DBUS_RESULT_NO_REPLY);
+    dbus_set_error (error, DBUS_ERROR_NO_REPLY, "Message did not receive a reply");
   else
-    dbus_set_result (result, DBUS_RESULT_DISCONNECTED);
+    dbus_set_error (error, DBUS_ERROR_DISCONNECTED, "Disconnected prior to receiving a reply");
 
   dbus_mutex_unlock (connection->mutex);
 
@@ -1631,7 +1681,7 @@ dbus_connection_dispatch_message (DBusConnection *connection)
   
   result = DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
 
-  reply_serial = _dbus_message_get_reply_serial (message);
+  reply_serial = dbus_message_get_reply_serial (message);
   reply_handler_data = _dbus_hash_table_lookup_int (connection->pending_replies,
                                                    reply_serial);
   
index fd631c6..6b48013 100644 (file)
@@ -37,6 +37,7 @@ typedef struct DBusConnection DBusConnection;
 typedef struct DBusWatch DBusWatch;
 typedef struct DBusTimeout DBusTimeout;
 typedef struct DBusMessageHandler DBusMessageHandler;
+typedef struct DBusPreallocatedSend DBusPreallocatedSend;
 
 typedef enum
 {
@@ -85,19 +86,18 @@ DBusMessage*    dbus_connection_pop_message            (DBusConnection *connecti
 dbus_bool_t     dbus_connection_dispatch_message       (DBusConnection *connection);
 
 
-dbus_bool_t  dbus_connection_send_message                      (DBusConnection     *connection,
-                                                               DBusMessage        *message,
-                                                               dbus_int32_t       *client_serial,
-                                                               DBusResultCode     *result);
-dbus_bool_t  dbus_connection_send_message_with_reply           (DBusConnection     *connection,
-                                                               DBusMessage        *message,
-                                                               DBusMessageHandler *reply_handler,
-                                                               int                 timeout_milliseconds,
-                                                               DBusResultCode     *result);
-DBusMessage *dbus_connection_send_message_with_reply_and_block (DBusConnection     *connection,
-                                                               DBusMessage        *message,
-                                                               int                 timeout_milliseconds,
-                                                               DBusResultCode     *result);
+dbus_bool_t  dbus_connection_send                      (DBusConnection     *connection,
+                                                        DBusMessage        *message,
+                                                        dbus_int32_t       *client_serial);
+dbus_bool_t  dbus_connection_send_with_reply           (DBusConnection     *connection,
+                                                        DBusMessage        *message,
+                                                        DBusMessageHandler *reply_handler,
+                                                        int                 timeout_milliseconds);
+DBusMessage *dbus_connection_send_with_reply_and_block (DBusConnection     *connection,
+                                                        DBusMessage        *message,
+                                                        int                 timeout_milliseconds,
+                                                        DBusError          *error);
+
 
 
 void dbus_connection_set_watch_functions      (DBusConnection            *connection,
@@ -169,6 +169,14 @@ void dbus_connection_set_max_live_messages_size (DBusConnection *connection,
                                                  long            size);
 long dbus_connection_get_max_live_messages_size (DBusConnection *connection);
 
+DBusPreallocatedSend* dbus_connection_preallocate_send       (DBusConnection       *connection);
+void                  dbus_connection_free_preallocated_send (DBusConnection       *connection,
+                                                              DBusPreallocatedSend *preallocated);
+void                  dbus_connection_send_preallocated      (DBusConnection       *connection,
+                                                              DBusPreallocatedSend *preallocated,
+                                                              DBusMessage          *message,
+                                                              dbus_int32_t         *client_serial);
+
 
 DBUS_END_DECLS;
 
index e57d353..da49e2e 100644 (file)
@@ -44,9 +44,6 @@
  * @endcode
  *
  * @todo add docs with DBusError
- *
- * @todo add dbus_error_is_set() to check
- * whether an error is set.
  * 
  * @{
  */
@@ -138,11 +135,9 @@ dbus_result_to_string (DBusResultCode code)
 }
 
 /**
- * Initializes a DBusError structure.
- * 
- * @todo calling dbus_error_init() in here is no good,
- * for the same reason a GError* has to be set to NULL
- * before you pass it in.
+ * Initializes a DBusError structure. Does not allocate
+ * any memory; the error only needs to be freed
+ * if it is set at some point. 
  *
  * @param error the DBusError.
  */
@@ -164,7 +159,8 @@ dbus_error_init (DBusError *error)
 }
 
 /**
- * Frees an error created by dbus_error_init().
+ * Frees an error that's been set (or just initialized),
+ * then reinitializes the error as in dbus_error_init().
  *
  * @param error memory where the error is stored.
  */
@@ -177,6 +173,8 @@ dbus_error_free (DBusError *error)
 
   if (!real->const_message)
     dbus_free (real->message);
+
+  dbus_error_init (error);
 }
 
 /**
@@ -211,6 +209,32 @@ dbus_set_error_const (DBusError  *error,
 }
 
 /**
+ * Moves an error src into dest, freeing src and
+ * overwriting dest. Both src and dest must be initialized.
+ * src is reinitialized to an empty error. dest may not
+ * contain an existing error. If the destination is
+ * #NULL, just frees and reinits the source error.
+ *
+ * @param src the source error
+ * @param dest the destination error or #NULL
+ */
+void
+dbus_move_error (DBusError *src,
+                 DBusError *dest)
+{
+  _dbus_assert (!dbus_error_is_set (dest));
+
+  if (dest)
+    {
+      dbus_error_free (dest);
+      *dest = *src;
+      dbus_error_init (src);
+    }
+  else
+    dbus_error_free (src);
+}
+
+/**
  * Checks whether the error is set and has the given
  * name.
  * @param error the error
@@ -246,7 +270,7 @@ dbus_error_has_name (const DBusError *error,
 dbus_bool_t
 dbus_error_is_set (const DBusError *error)
 {
-  _dbus_assert (error != NULL);
+  _dbus_assert (error != NULL);  
   _dbus_assert ((error->name != NULL && error->message != NULL) ||
                 (error->name == NULL && error->message == NULL));
   return error->name != NULL;
index e6b8846..63edbdb 100644 (file)
@@ -56,6 +56,20 @@ struct DBusError
 #define DBUS_ERROR_NO_MEMORY                  "org.freedesktop.DBus.Error.NoMemory"
 #define DBUS_ERROR_SERVICE_DOES_NOT_EXIST     "org.freedesktop.DBus.Error.ServiceDoesNotExist"
 #define DBUS_ERROR_NO_REPLY                   "org.freedesktop.DBus.Error.NoReply"
+#define DBUS_ERROR_IO_ERROR                   "org.freedesktop.DBus.Error.IOError"
+#define DBUS_ERROR_BAD_ADDRESS                "org.freedesktop.DBus.Error.BadAddress"
+#define DBUS_ERROR_NOT_SUPPORTED              "org.freedesktop.DBus.Error.NotSupported"
+#define DBUS_ERROR_LIMITS_EXCEEDED            "org.freedesktop.DBus.Error.LimitsExceeded"
+#define DBUS_ERROR_ACCESS_DENIED              "org.freedesktop.DBus.Error.AccessDenied"
+#define DBUS_ERROR_AUTH_FAILED                "org.freedesktop.DBus.Error.AuthFailed"
+#define DBUS_ERROR_NO_SERVER                  "org.freedesktop.DBus.Error.NoServer"
+#define DBUS_ERROR_TIMEOUT                    "org.freedesktop.DBus.Error.Timeout"
+#define DBUS_ERROR_NO_NETWORK                 "org.freedesktop.DBus.Error.NoNetwork"
+#define DBUS_ERROR_ADDRESS_IN_USE             "org.freedesktop.DBus.Error.AddressInUse"
+#define DBUS_ERROR_DISCONNECTED               "org.freedesktop.DBus.Error.Disconnected"
+#define DBUS_ERROR_INVALID_ARGS               "org.freedesktop.DBus.Error.InvalidArgs"
+#define DBUS_ERROR_FILE_NOT_FOUND             "org.freedesktop.DBus.Error.FileNotFound"
+#define DBUS_ERROR_UNKNOWN_MESSAGE            "org.freedesktop.DBus.Error.UnknownMessage"
 
 typedef enum
 {
@@ -90,6 +104,8 @@ void        dbus_set_error       (DBusError       *error,
 void        dbus_set_error_const (DBusError       *error,
                                   const char      *name,
                                   const char      *message);
+void        dbus_move_error      (DBusError       *src,
+                                  DBusError       *dest);
 dbus_bool_t dbus_error_has_name  (const DBusError *error,
                                   const char      *name);
 dbus_bool_t dbus_error_is_set    (const DBusError *error);
index 8dedb56..acd6d72 100644 (file)
@@ -1,7 +1,7 @@
 /* -*- mode: C; c-file-style: "gnu" -*- */
 /* dbus-internals.c  random utility stuff (internal to D-BUS implementation)
  *
- * Copyright (C) 2002  Red Hat, Inc.
+ * Copyright (C) 2002, 2003  Red Hat, Inc.
  *
  * Licensed under the Academic Free License version 1.2
  * 
  */
 
 /**
+ * Fixed "out of memory" error message, just to avoid
+ * making up a different string every time and wasting
+ * space.
+ */
+const char _dbus_no_memory_message[] = "Not enough memory";
+
+/**
  * Prints a warning message to stderr.
  *
  * @param format printf-style format string.
@@ -181,104 +188,6 @@ _dbus_verbose_real (const char *format,
 }
 
 /**
- * Converts a UNIX errno into a DBusResultCode.
- *
- * @todo should cover more errnos, specifically those
- * from open().
- * 
- * @param error_number the errno.
- * @returns the result code.
- */
-DBusResultCode
-_dbus_result_from_errno (int error_number)
-{
-  switch (error_number)
-    {
-    case 0:
-      return DBUS_RESULT_SUCCESS;
-      
-#ifdef EPROTONOSUPPORT
-    case EPROTONOSUPPORT:
-      return DBUS_RESULT_NOT_SUPPORTED;
-#endif
-#ifdef EAFNOSUPPORT
-    case EAFNOSUPPORT:
-      return DBUS_RESULT_NOT_SUPPORTED;
-#endif
-#ifdef ENFILE
-    case ENFILE:
-      return DBUS_RESULT_LIMITS_EXCEEDED; /* kernel out of memory */
-#endif
-#ifdef EMFILE
-    case EMFILE:
-      return DBUS_RESULT_LIMITS_EXCEEDED;
-#endif
-#ifdef EACCES
-    case EACCES:
-      return DBUS_RESULT_ACCESS_DENIED;
-#endif
-#ifdef EPERM
-    case EPERM:
-      return DBUS_RESULT_ACCESS_DENIED;
-#endif
-#ifdef ENOBUFS
-    case ENOBUFS:
-      return DBUS_RESULT_NO_MEMORY;
-#endif
-#ifdef ENOMEM
-    case ENOMEM:
-      return DBUS_RESULT_NO_MEMORY;
-#endif
-#ifdef EINVAL
-    case EINVAL:
-      return DBUS_RESULT_FAILED;
-#endif
-#ifdef EBADF
-    case EBADF:
-      return DBUS_RESULT_FAILED;
-#endif
-#ifdef EFAULT
-    case EFAULT:
-      return DBUS_RESULT_FAILED;
-#endif
-#ifdef ENOTSOCK
-    case ENOTSOCK:
-      return DBUS_RESULT_FAILED;
-#endif
-#ifdef EISCONN
-    case EISCONN:
-      return DBUS_RESULT_FAILED;
-#endif
-#ifdef ECONNREFUSED
-    case ECONNREFUSED:
-      return DBUS_RESULT_NO_SERVER;
-#endif
-#ifdef ETIMEDOUT
-    case ETIMEDOUT:
-      return DBUS_RESULT_TIMEOUT;
-#endif
-#ifdef ENETUNREACH
-    case ENETUNREACH:
-      return DBUS_RESULT_NO_NETWORK;
-#endif
-#ifdef EADDRINUSE
-    case EADDRINUSE:
-      return DBUS_RESULT_ADDRESS_IN_USE;
-#endif
-#ifdef EEXIST
-    case EEXIST:
-      return DBUS_RESULT_FILE_NOT_FOUND;
-#endif
-#ifdef ENOENT
-    case ENOENT:
-      return DBUS_RESULT_FILE_NOT_FOUND;
-#endif
-    }
-
-  return DBUS_RESULT_FAILED;
-}
-
-/**
  * Duplicates a string. Result must be freed with
  * dbus_free(). Returns #NULL if memory allocation fails.
  * If the string to be duplicated is #NULL, returns #NULL.
index 19a5cdc..2576982 100644 (file)
@@ -94,6 +94,8 @@ do {
 #define _DBUS_STRUCT_OFFSET(struct_type, member)       \
     ((long) ((unsigned char*) &((struct_type*) 0)->member))
 
+#define _DBUS_ASSERT_ERROR_IS_SET(error) _dbus_assert ((error) == NULL || dbus_error_is_set ((error)))
+
 /* This alignment thing is from ORBit2 */
 /* Align a value upward to a boundary, expressed as a number of bytes.
  * E.g. align to an 8-byte boundary with argument of 8.
@@ -146,6 +148,9 @@ void _dbus_verbose_bytes_of_string (const DBusString    *str,
 
 const char* _dbus_type_to_string (int type);
 
+extern const char _dbus_no_memory_message[];
+#define _DBUS_SET_OOM(error) dbus_set_error ((error), DBUS_ERROR_NO_MEMORY, _dbus_no_memory_message)
+
 #ifdef DBUS_BUILD_TESTS
 /* Memory debugging */
 void        _dbus_set_fail_alloc_counter       (int  until_next_fail);
index c5c6a0b..db432be 100644 (file)
@@ -399,6 +399,7 @@ _dbus_keyring_reload (DBusKeyring *keyring,
   int n_keys;
   int i;
   long now;
+  DBusError tmp_error;
   
   if (!_dbus_string_init (&contents, _DBUS_INT_MAX))
     {
@@ -434,14 +435,15 @@ _dbus_keyring_reload (DBusKeyring *keyring,
       have_lock = TRUE;
     }
 
-  result = _dbus_file_get_contents (&contents, 
-                                    &keyring->filename);
-
-  if (result != DBUS_RESULT_SUCCESS)
+  dbus_error_init (&tmp_error);
+  if (!_dbus_file_get_contents (&contents, 
+                                &keyring->filename,
+                                &tmp_error))
     {
       _dbus_verbose ("Failed to load keyring file: %s\n",
-                     dbus_result_to_string (result));
+                     tmp_error.message);
       /* continue with empty keyring file, so we recreate it */
+      dbus_error_free (&tmp_error);
     }
 
   if (!_dbus_string_validate_ascii (&contents, 0,
index 7b30692..d0ca8df 100644 (file)
@@ -678,6 +678,19 @@ _dbus_list_foreach (DBusList          **list,
     }
 }
 
+/**
+ * Check whether length is exactly one.
+ *
+ * @param list the list
+ * @returns #TRUE if length is exactly one
+ */
+dbus_bool_t
+_dbus_list_length_is_one (DBusList **list)
+{
+  return (*list != NULL &&
+          (*list)->next == *list);
+}
+
 /** @} */
 
 #ifdef DBUS_BUILD_TESTS
@@ -713,6 +726,11 @@ verify_list (DBusList **list)
   while (link != *list);
 
   _dbus_assert (length == _dbus_list_get_length (list));
+
+  if (length == 1)
+    _dbus_assert (_dbus_list_length_is_one (list));
+  else
+    _dbus_assert (!_dbus_list_length_is_one (list));
 }
 
 static dbus_bool_t
index 2c55c6b..3f23f2e 100644 (file)
@@ -73,6 +73,8 @@ void        _dbus_list_append_link    (DBusList **list,
 void        _dbus_list_prepend_link   (DBusList **list,
                                       DBusList  *link);
 
+dbus_bool_t _dbus_list_length_is_one  (DBusList **list);
+
 void _dbus_list_foreach (DBusList            **list,
                          DBusForeachFunction   function,
                          void                 *data);
index 54b5de7..e34e1b5 100644 (file)
@@ -314,7 +314,7 @@ _dbus_message_data_load (DBusString       *dest,
                          const DBusString *filename)
 {
   DBusString file;
-  DBusResultCode result;
+  DBusError error;
   DBusString line;
   dbus_bool_t retval;
   int line_no;
@@ -340,14 +340,15 @@ _dbus_message_data_load (DBusString       *dest,
     _dbus_string_get_const_data (filename, &s);
     _dbus_verbose ("Loading %s\n", s);
   }
-  
-  if ((result = _dbus_file_get_contents (&file, filename)) != DBUS_RESULT_SUCCESS)
+
+  dbus_error_init (&error);
+  if (!_dbus_file_get_contents (&file, filename, &error))
     {
       const char *s;
       _dbus_string_get_const_data (filename, &s);
       _dbus_warn ("Getting contents of %s failed: %s\n",
-                  s, dbus_result_to_string (result));
-                     
+                  s, error.message);
+      dbus_error_free (&error);
       goto out;
     }
 
index 44ce62a..86796da 100644 (file)
@@ -34,17 +34,12 @@ void _dbus_message_get_network_data  (DBusMessage       *message,
                                      const DBusString **header,
                                      const DBusString **body);
 
-void         _dbus_message_lock              (DBusMessage  *message);
-void         _dbus_message_unlock            (DBusMessage  *message);
-void         _dbus_message_set_client_serial (DBusMessage  *message,
-                                             dbus_int32_t  client_serial);
-dbus_int32_t _dbus_message_get_client_serial (DBusMessage  *message);
-dbus_bool_t  _dbus_message_set_reply_serial  (DBusMessage  *message,
-                                              dbus_int32_t  reply_serial);
-dbus_int32_t _dbus_message_get_reply_serial  (DBusMessage  *message);
-void         _dbus_message_add_size_counter  (DBusMessage  *message,
-                                             DBusCounter  *counter);
-
+void         _dbus_message_lock             (DBusMessage  *message);
+void         _dbus_message_unlock           (DBusMessage  *message);
+void         _dbus_message_set_serial       (DBusMessage  *message,
+                                             dbus_int32_t  serial);
+void         _dbus_message_add_size_counter (DBusMessage  *message,
+                                             DBusCounter  *counter);
 
 DBusMessageLoader* _dbus_message_loader_new                   (void);
 void               _dbus_message_loader_ref                   (DBusMessageLoader  *loader);
index a25480c..6a3c661 100644 (file)
@@ -532,28 +532,22 @@ set_string_field (DBusMessage *message,
 }
 
 /**
- * Sets the client serial of a message. 
+ * Sets the serial number of a message. 
  * This can only be done once on a message.
- *
- * @todo client_serial should be called simply
- * "serial"; it's in outgoing messages for both
- * the client and the server, it's only client-specific
- * in the message bus case. It's more like origin_serial
- * or something.
  * 
  * @param message the message
- * @param client_serial the client serial
+ * @param serial the serial
  */
 void
-_dbus_message_set_client_serial (DBusMessage  *message,
-                                dbus_int32_t  client_serial)
+_dbus_message_set_serial (DBusMessage  *message,
+                          dbus_int32_t  serial)
 {
   _dbus_assert (!message->locked);
-  _dbus_assert (_dbus_message_get_client_serial (message) < 0);
+  _dbus_assert (dbus_message_get_serial (message) < 0);
   
   set_int_field (message, FIELD_CLIENT_SERIAL,
-                 client_serial);
-  message->client_serial = client_serial;
+                 serial);
+  message->client_serial = serial;
 }
 
 /**
@@ -565,7 +559,7 @@ _dbus_message_set_client_serial (DBusMessage  *message,
  * @returns #FALSE if not enough memory
  */
 dbus_bool_t
-_dbus_message_set_reply_serial (DBusMessage  *message,
+dbus_message_set_reply_serial (DBusMessage  *message,
                                 dbus_int32_t  reply_serial)
 {
   _dbus_assert (!message->locked);
@@ -581,19 +575,15 @@ _dbus_message_set_reply_serial (DBusMessage  *message,
 }
 
 /**
- * Returns the client serial of a message or
- * -1 if none has been specified.
- *
- * @todo see note in _dbus_message_set_client_serial()
- * about how client_serial is a misnomer
- *
- * @todo this function should be public, after renaming it.
+ * Returns the serial of a message or -1 if none has been specified.
+ * The message's serial number is provided by the application sending
+ * the message and is used to identify replies to this message.
  *
  * @param message the message
  * @returns the client serial
  */
 dbus_int32_t
-_dbus_message_get_client_serial (DBusMessage *message)
+dbus_message_get_serial (DBusMessage *message)
 {
   return message->client_serial;
 }
@@ -606,7 +596,7 @@ _dbus_message_get_client_serial (DBusMessage *message)
  * @returns the reply serial
  */
 dbus_int32_t
-_dbus_message_get_reply_serial  (DBusMessage *message)
+dbus_message_get_reply_serial  (DBusMessage *message)
 {
   return message->reply_serial;
 }
@@ -845,8 +835,8 @@ dbus_message_new_reply (DBusMessage *original_message)
   if (message == NULL)
     return NULL;
 
-  if (!_dbus_message_set_reply_serial (message,
-                                       _dbus_message_get_client_serial (original_message)))
+  if (!dbus_message_set_reply_serial (message,
+                                      dbus_message_get_serial (original_message)))
     {
       dbus_message_unref (message);
       return NULL;
@@ -881,8 +871,8 @@ dbus_message_new_error_reply (DBusMessage *original_message,
   if (message == NULL)
     return NULL;
 
-  if (!_dbus_message_set_reply_serial (message,
-                                       _dbus_message_get_client_serial (original_message)))
+  if (!dbus_message_set_reply_serial (message,
+                                      dbus_message_get_serial (original_message)))
     {
       dbus_message_unref (message);
       return NULL;
@@ -1542,12 +1532,14 @@ dbus_message_append_dict (DBusMessage *message,
  * stored. The list is terminated with 0.
  *
  * @param message the message
+ * @param error error to be filled in on failure
  * @param first_arg_type the first argument type
  * @param ... location for first argument value, then list of type-location pairs
- * @returns result code
+ * @returns #FALSE if the error was set
  */
-DBusResultCode
+dbus_bool_t
 dbus_message_get_args (DBusMessage *message,
+                       DBusError   *error,
                       int          first_arg_type,
                       ...)
 {
@@ -1555,7 +1547,7 @@ dbus_message_get_args (DBusMessage *message,
   va_list var_args;
 
   va_start (var_args, first_arg_type);
-  retval = dbus_message_get_args_valist (message, first_arg_type, var_args);
+  retval = dbus_message_get_args_valist (message, error, first_arg_type, var_args);
   va_end (var_args);
 
   return retval;
@@ -1575,22 +1567,31 @@ dbus_message_get_args (DBusMessage *message,
  *
  * @see dbus_message_get_args
  * @param message the message
+ * @param error error to be filled in
  * @param first_arg_type type of the first argument
  * @param var_args return location for first argument, followed by list of type/location pairs
- * @returns result code
+ * @returns #FALSE if error was set
  */
-DBusResultCode
+dbus_bool_t
 dbus_message_get_args_valist (DBusMessage *message,
+                              DBusError   *error,
                              int          first_arg_type,
                              va_list      var_args)
 {
   int spec_type, msg_type, i;
   DBusMessageIter *iter;
-
+  dbus_bool_t retval;
+  
   iter = dbus_message_get_args_iter (message);
 
   if (iter == NULL)
-    return DBUS_RESULT_NO_MEMORY;
+    {
+      dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
+                      "No memory to get message arguments");
+      return FALSE;
+    }
+
+  retval = FALSE;
   
   spec_type = first_arg_type;
   i = 0;
@@ -1601,13 +1602,13 @@ dbus_message_get_args_valist (DBusMessage *message,
       
       if (msg_type != spec_type)
        {
-         _dbus_verbose ("Argument %d is specified to be of type \"%s\", but "
-                        "is actually of type \"%s\"\n", i,
-                        _dbus_type_to_string (spec_type),
-                        _dbus_type_to_string (msg_type));
-         dbus_message_iter_unref (iter);
+          dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
+                          "Argument %d is specified to be of type \"%s\", but "
+                          "is actually of type \"%s\"\n", i,
+                          _dbus_type_to_string (spec_type),
+                          _dbus_type_to_string (msg_type));
 
-         return DBUS_RESULT_INVALID_ARGS;
+          goto out;
        }
 
       switch (spec_type)
@@ -1661,7 +1662,11 @@ dbus_message_get_args_valist (DBusMessage *message,
            *ptr = dbus_message_iter_get_string (iter);
 
            if (!*ptr)
-             return DBUS_RESULT_NO_MEMORY;
+              {
+                dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
+                                "No memory for argument %d", i);
+                goto out;
+              }
            
            break;
          }
@@ -1675,8 +1680,11 @@ dbus_message_get_args_valist (DBusMessage *message,
            len = va_arg (var_args, int *);
 
            if (!dbus_message_iter_get_boolean_array (iter, ptr, len))
-             return DBUS_RESULT_NO_MEMORY;
-           
+              {
+                dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
+                                "No memory for argument %d", i);
+                goto out;
+              }
            break;
          }
          
@@ -1689,7 +1697,11 @@ dbus_message_get_args_valist (DBusMessage *message,
            len = va_arg (var_args, int *);
 
            if (!dbus_message_iter_get_int32_array (iter, ptr, len))
-             return DBUS_RESULT_NO_MEMORY;
+              {
+                dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
+                                "No memory for argument %d", i);
+                goto out;
+              }
            
            break;
          }
@@ -1703,7 +1715,11 @@ dbus_message_get_args_valist (DBusMessage *message,
            len = va_arg (var_args, int *);
 
            if (!dbus_message_iter_get_uint32_array (iter, ptr, len))
-             return DBUS_RESULT_NO_MEMORY;
+              {
+                dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
+                                "No memory for argument %d", i);
+                goto out;
+              }
            
            break;
          }
@@ -1717,8 +1733,11 @@ dbus_message_get_args_valist (DBusMessage *message,
            len = va_arg (var_args, int *);
 
            if (!dbus_message_iter_get_double_array (iter, ptr, len))
-             return DBUS_RESULT_NO_MEMORY;
-           
+              {
+                dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
+                                "No memory for argument %d", i);
+                goto out;
+              }
            break;
          }
          
@@ -1731,8 +1750,11 @@ dbus_message_get_args_valist (DBusMessage *message,
            len = va_arg (var_args, int *);
 
            if (!dbus_message_iter_get_byte_array (iter, ptr, len))
-             return DBUS_RESULT_NO_MEMORY;
-           
+              {
+                dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
+                                "No memory for argument %d", i);
+                goto out;
+              }
            break;
          }
        case DBUS_TYPE_STRING_ARRAY:
@@ -1744,7 +1766,11 @@ dbus_message_get_args_valist (DBusMessage *message,
            len = va_arg (var_args, int *);
 
            if (!dbus_message_iter_get_string_array (iter, ptr, len))
-             return DBUS_RESULT_NO_MEMORY;
+              {
+                dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
+                                "No memory for argument %d", i);
+                goto out;
+              }
            break;
          }
        case DBUS_TYPE_DICT:
@@ -1754,7 +1780,11 @@ dbus_message_get_args_valist (DBusMessage *message,
            dict = va_arg (var_args, DBusDict **);
 
            if (!dbus_message_iter_get_dict (iter, dict))
-             return DBUS_RESULT_NO_MEMORY;
+              {
+                dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
+                                "No memory for argument %d", i);
+                goto out;
+              }
            break;
          }
        default:          
@@ -1763,17 +1793,20 @@ dbus_message_get_args_valist (DBusMessage *message,
       
       spec_type = va_arg (var_args, int);
       if (spec_type != 0 && !dbus_message_iter_next (iter))
-       {
-         _dbus_verbose ("More fields than exist in the message were specified or field is corrupt\n");
+        {
+          dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
+                          "Message has only %d arguments, but more were expected", i);
+          goto out;
+        }
 
-         dbus_message_iter_unref (iter);  
-         return DBUS_RESULT_INVALID_ARGS;
-       }
       i++;
     }
-
+  
+  retval = TRUE;
+  
+ out:
   dbus_message_iter_unref (iter);
-  return DBUS_RESULT_SUCCESS;
+  return retval;
 }
 
 /**
@@ -2318,6 +2351,10 @@ dbus_message_name_is (DBusMessage *message,
  * DBusTransport implementation. The DBusTransport then hands off
  * the loaded messages to a DBusConnection, making the messages
  * visible to the application.
+ *
+ * @todo write tests for break-loader that a) randomly delete header
+ * fields and b) set string fields to zero-length and other funky
+ * values.
  * 
  */
 
@@ -2624,6 +2661,13 @@ decode_header_data (const DBusString   *data,
         }
     }
 
+ if (fields[FIELD_NAME].offset < 0)
+   {
+     _dbus_verbose ("No %s field provided\n",
+                    DBUS_HEADER_FIELD_NAME);
+     return FALSE;
+   }
+  
   if (message_padding)
     *message_padding = header_len - pos;  
   
@@ -2970,13 +3014,13 @@ check_message_handling (DBusMessage *message)
   retval = FALSE;
   iter = NULL;
   
-  client_serial = _dbus_message_get_client_serial (message);
+  client_serial = dbus_message_get_serial (message);
 
-  /* can't use set_client_serial due to the assertions at the start of it */
+  /* can't use set_serial due to the assertions at the start of it */
   set_int_field (message, FIELD_CLIENT_SERIAL,
                  client_serial);
-
-  if (client_serial != _dbus_message_get_client_serial (message))
+  
+  if (client_serial != dbus_message_get_serial (message))
     {
       _dbus_warn ("get/set cycle for client_serial did not succeed\n");
       goto failed;
@@ -3215,14 +3259,15 @@ dbus_internal_do_not_use_load_message_file (const DBusString    *filename,
 
   if (is_raw)
     {
-      DBusResultCode result;
+      DBusError error;
 
-      result = _dbus_file_get_contents (data, filename);
-      if (result != DBUS_RESULT_SUCCESS)
+      dbus_error_init (&error);
+      if (!_dbus_file_get_contents (data, filename, &error))
         {
           const char *s;      
           _dbus_string_get_const_data (filename, &s);
-          _dbus_warn ("Could not load message file %s\n", s);
+          _dbus_warn ("Could not load message file %s: %s\n", s, error.message);
+          dbus_error_free (&error);
           goto failed;
         }
     }
@@ -3397,7 +3442,7 @@ process_test_subdir (const DBusString          *test_base_dir,
   DBusString filename;
   DBusDirIter *dir;
   dbus_bool_t retval;
-  DBusResultCode result;
+  DBusError error;
 
   retval = FALSE;
   dir = NULL;
@@ -3417,22 +3462,23 @@ process_test_subdir (const DBusString          *test_base_dir,
   _dbus_string_free (&filename);
   if (!_dbus_string_init (&filename, _DBUS_INT_MAX))
     _dbus_assert_not_reached ("didn't allocate filename string\n");
-  
-  dir = _dbus_directory_open (&test_directory, &result);
+
+  dbus_error_init (&error);
+  dir = _dbus_directory_open (&test_directory, &error);
   if (dir == NULL)
     {
       const char *s;
       _dbus_string_get_const_data (&test_directory, &s);
       _dbus_warn ("Could not open %s: %s\n", s,
-                  dbus_result_to_string (result));
+                  error.message);
+      dbus_error_free (&error);
       goto failed;
     }
 
   printf ("Testing:\n");
   
-  result = DBUS_RESULT_SUCCESS;
  next:
-  while (_dbus_directory_get_next_file (dir, &filename, &result))
+  while (_dbus_directory_get_next_file (dir, &filename, &error))
     {
       DBusString full_path;
       dbus_bool_t is_raw;
@@ -3480,12 +3526,13 @@ process_test_subdir (const DBusString          *test_base_dir,
         _dbus_string_free (&full_path);
     }
 
-  if (result != DBUS_RESULT_SUCCESS)
+  if (dbus_error_is_set (&error))
     {
       const char *s;
       _dbus_string_get_const_data (&test_directory, &s);
       _dbus_warn ("Could not get next file in %s: %s\n",
-                  s, dbus_result_to_string (result));
+                  s, error.message);
+      dbus_error_free (&error);
       goto failed;
     }
     
@@ -3563,7 +3610,7 @@ _dbus_message_test (const char *test_data_dir)
   
   /* Test the vararg functions */
   message = dbus_message_new ("org.freedesktop.DBus.Test", "testMessage");
-  _dbus_message_set_client_serial (message, 1);
+  _dbus_message_set_serial (message, 1);
   dbus_message_append_args (message,
                            DBUS_TYPE_INT32, -0x12345678,
                            DBUS_TYPE_STRING, "Test string",
@@ -3574,13 +3621,13 @@ _dbus_message_test (const char *test_data_dir)
                                  _dbus_string_get_length (&message->header));
   _dbus_verbose_bytes_of_string (&message->body, 0,
                                  _dbus_string_get_length (&message->body));
-  
-  if (dbus_message_get_args (message,
-                            DBUS_TYPE_INT32, &our_int,
-                            DBUS_TYPE_STRING, &our_str,
-                            DBUS_TYPE_DOUBLE, &our_double,
-                            DBUS_TYPE_BOOLEAN, &our_bool,
-                            0) != DBUS_RESULT_SUCCESS)
+
+  if (!dbus_message_get_args (message, NULL,
+                              DBUS_TYPE_INT32, &our_int,
+                              DBUS_TYPE_STRING, &our_str,
+                              DBUS_TYPE_DOUBLE, &our_double,
+                              DBUS_TYPE_BOOLEAN, &our_bool,
+                              0))
     _dbus_assert_not_reached ("Could not get arguments");
 
   if (our_int != -0x12345678)
@@ -3599,8 +3646,8 @@ _dbus_message_test (const char *test_data_dir)
   dbus_message_unref (message);
   
   message = dbus_message_new ("org.freedesktop.DBus.Test", "testMessage");
-  _dbus_message_set_client_serial (message, 1);
-  _dbus_message_set_reply_serial (message, 0x12345678);
+  _dbus_message_set_serial (message, 1);
+  dbus_message_set_reply_serial (message, 0x12345678);
 
   dbus_message_append_string (message, "Test string");
   dbus_message_append_int32 (message, -0x12345678);
@@ -3645,7 +3692,7 @@ _dbus_message_test (const char *test_data_dir)
   if (!message)
     _dbus_assert_not_reached ("received a NULL message");
 
-  if (_dbus_message_get_reply_serial (message) != 0x12345678)
+  if (dbus_message_get_reply_serial (message) != 0x12345678)
     _dbus_assert_not_reached ("reply serial fields differ");
   
   message_iter_test (message);
index 4ea6306..d30a0a3 100644 (file)
@@ -48,17 +48,21 @@ DBusMessage *dbus_message_new_from_message (const DBusMessage *message);
 void         dbus_message_ref   (DBusMessage *message);
 void         dbus_message_unref (DBusMessage *message);
 
-const char* dbus_message_get_name             (DBusMessage *message);
-const char* dbus_message_get_service          (DBusMessage *message);
-dbus_bool_t dbus_message_set_sender           (DBusMessage *message,
-                                              const char  *sender);
-const char* dbus_message_get_sender           (DBusMessage *message);
-void        dbus_message_set_is_error         (DBusMessage *message,
-                                              dbus_bool_t  is_error_reply);
-dbus_bool_t dbus_message_get_is_error         (DBusMessage *message);
+const char*  dbus_message_get_name         (DBusMessage  *message);
+const char*  dbus_message_get_service      (DBusMessage  *message);
+dbus_bool_t  dbus_message_set_sender       (DBusMessage  *message,
+                                            const char   *sender);
+const char*  dbus_message_get_sender       (DBusMessage  *message);
+void         dbus_message_set_is_error     (DBusMessage  *message,
+                                            dbus_bool_t   is_error_reply);
+dbus_bool_t  dbus_message_get_is_error     (DBusMessage  *message);
+dbus_bool_t  dbus_message_name_is          (DBusMessage  *message,
+                                            const char   *name);
+dbus_int32_t dbus_message_get_serial       (DBusMessage  *message);
+dbus_bool_t  dbus_message_set_reply_serial (DBusMessage  *message,
+                                            dbus_int32_t  reply_serial);
+dbus_int32_t dbus_message_get_reply_serial (DBusMessage  *message);
 
-dbus_bool_t dbus_message_name_is (DBusMessage *message,
-                                 const char  *name);
 
 dbus_bool_t dbus_message_append_args          (DBusMessage          *message,
                                               int                   first_arg_type,
@@ -99,13 +103,14 @@ dbus_bool_t dbus_message_append_dict          (DBusMessage          *message,
                                               DBusDict             *dict);
 
 DBusMessageIter *dbus_message_get_args_iter   (DBusMessage *message);
-DBusResultCode   dbus_message_get_args        (DBusMessage *message,
-                                              int          first_arg_type,
-                                              ...);
-DBusResultCode   dbus_message_get_args_valist (DBusMessage *message,
-                                              int          first_arg_type,
-                                              va_list      var_args);
-
+dbus_bool_t      dbus_message_get_args        (DBusMessage *message,
+                                               DBusError   *error,
+                                               int          first_arg_type,
+                                               ...);
+dbus_bool_t      dbus_message_get_args_valist (DBusMessage *message,
+                                               DBusError   *error,
+                                               int          first_arg_type,
+                                               va_list      var_args);
 
 
 void          dbus_message_iter_ref               (DBusMessageIter   *iter);
index 2f73e36..8f04712 100644 (file)
@@ -752,6 +752,7 @@ process_test_data (const char *test_data_dir)
   int line_no;
   dbus_bool_t retval;
   int success_count;
+  DBusError error;
   
   retval = FALSE;
   
@@ -784,21 +785,24 @@ process_test_data (const char *test_data_dir)
   if (!_dbus_concat_dir_and_file (&results_file, &tmp))
     _dbus_assert_not_reached ("no memory");
 
-  if (_dbus_file_get_contents (&tests, &tests_file) != DBUS_RESULT_SUCCESS)
+  dbus_error_init (&error);
+  if (!_dbus_file_get_contents (&tests, &tests_file, &error))
     {
       const char *s;
       _dbus_string_get_const_data (&tests_file, &s);
-      fprintf (stderr, "could not load test data file %s\n",
-               s);
+      fprintf (stderr, "could not load test data file %s: %s\n",
+               s, error.message);
+      dbus_error_free (&error);
       goto out;
     }
 
-  if (_dbus_file_get_contents (&results, &results_file) != DBUS_RESULT_SUCCESS)
+  if (!_dbus_file_get_contents (&results, &results_file, &error))
     {
       const char *s;
       _dbus_string_get_const_data (&results_file, &s);
-      fprintf (stderr, "could not load results data file %s\n",
-               s);
+      fprintf (stderr, "could not load results data file %s: %s\n",
+               s, error.message);
+      dbus_error_free (&error);
       goto out;
     }
 
index d096ce3..5d0be32 100644 (file)
@@ -1,7 +1,7 @@
 /* -*- mode: C; c-file-style: "gnu" -*- */
 /* dbus-sysdeps.c Wrappers around system/libc features (internal to D-BUS implementation)
  * 
- * Copyright (C) 2002  Red Hat, Inc.
+ * Copyright (C) 2002, 2003  Red Hat, Inc.
  *
  * Licensed under the Academic Free License version 1.2
  * 
@@ -1604,11 +1604,13 @@ _dbus_get_current_time (long *tv_sec,
  *
  * @param str the string to append to
  * @param filename filename to load
- * @returns result
+ * @param error place to set an error
+ * @returns #FALSE if error was set
  */
-DBusResultCode
+dbus_bool_t
 _dbus_file_get_contents (DBusString       *str,
-                         const DBusString *filename)
+                         const DBusString *filename,
+                         DBusError        *error)
 {
   int fd;
   struct stat sb;
@@ -1621,28 +1623,32 @@ _dbus_file_get_contents (DBusString       *str,
   /* O_BINARY useful on Cygwin */
   fd = open (filename_c, O_RDONLY | O_BINARY);
   if (fd < 0)
-    return _dbus_result_from_errno (errno);
+    {
+      dbus_set_error (error, _dbus_error_from_errno (errno),
+                      "%s", _dbus_strerror (errno));
+      return FALSE;
+    }
 
   if (fstat (fd, &sb) < 0)
     {
-      DBusResultCode result;      
-
-      result = _dbus_result_from_errno (errno); /* prior to close() */
+      dbus_set_error (error, _dbus_error_from_errno (errno),
+                      "%s", _dbus_strerror (errno));
 
       _dbus_verbose ("fstat() failed: %s",
                      _dbus_strerror (errno));
       
       close (fd);
       
-      return result;
+      return FALSE;
     }
 
   if (sb.st_size > _DBUS_ONE_MEGABYTE)
     {
-      _dbus_verbose ("File size %lu is too large.\n",
+      dbus_set_error (error, DBUS_ERROR_FAILED,
+                      "File size %lu is too large.\n",
                      (unsigned long) sb.st_size);
       close (fd);
-      return DBUS_RESULT_FAILED;
+      return FALSE;
     }
   
   total = 0;
@@ -1657,34 +1663,35 @@ _dbus_file_get_contents (DBusString       *str,
                                    sb.st_size - total);
           if (bytes_read <= 0)
             {
-              DBusResultCode result;
-              
-              result = _dbus_result_from_errno (errno); /* prior to close() */
+              dbus_set_error (error, _dbus_error_from_errno (errno),
+                              "%s", _dbus_strerror (errno));
 
               _dbus_verbose ("read() failed: %s",
                              _dbus_strerror (errno));
               
               close (fd);
               _dbus_string_set_length (str, orig_len);
-              return result;
+              return FALSE;
             }
           else
             total += bytes_read;
         }
 
       close (fd);
-      return DBUS_RESULT_SUCCESS;
+      return TRUE;
     }
   else if (sb.st_size != 0)
     {
       _dbus_verbose ("Can only open regular files at the moment.\n");
+      dbus_set_error (error, DBUS_ERROR_FAILED,
+                      "Not a regular file");
       close (fd);
-      return DBUS_RESULT_FAILED;
+      return FALSE;
     }
   else
     {
       close (fd);
-      return DBUS_RESULT_SUCCESS;
+      return TRUE;
     }
 }
 
@@ -1972,12 +1979,12 @@ struct DBusDirIter
  * Open a directory to iterate over.
  *
  * @param filename the directory name
- * @param result return location for error code if #NULL returned
+ * @param error exception return object or #NULL
  * @returns new iterator, or #NULL on error
  */
 DBusDirIter*
 _dbus_directory_open (const DBusString *filename,
-                      DBusResultCode   *result)
+                      DBusError        *error)
 {
   DIR *d;
   DBusDirIter *iter;
@@ -1988,15 +1995,16 @@ _dbus_directory_open (const DBusString *filename,
   d = opendir (filename_c);
   if (d == NULL)
     {
-      dbus_set_result (result, _dbus_result_from_errno (errno));
+      dbus_set_error (error, _dbus_error_from_errno (errno),
+                      "%s", _dbus_strerror (errno));
       return NULL;
     }
-  
   iter = dbus_new0 (DBusDirIter, 1);
   if (iter == NULL)
     {
       closedir (d);
-      dbus_set_result (result, DBUS_RESULT_NO_MEMORY);
+      dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
+                      "Could not allocate memory for directory iterator");
       return NULL;
     }
 
@@ -2006,39 +2014,38 @@ _dbus_directory_open (const DBusString *filename,
 }
 
 /**
- * Get next file in the directory. Will not return "." or ".."
- * on UNIX. If an error occurs, the contents of "filename"
- * are undefined. #DBUS_RESULT_SUCCESS is always returned
- * in result if no error occurs.
+ * Get next file in the directory. Will not return "." or ".."  on
+ * UNIX. If an error occurs, the contents of "filename" are
+ * undefined. The error is never set if the function succeeds.
  *
  * @todo for thread safety, I think we have to use
  * readdir_r(). (GLib has the same issue, should file a bug.)
  *
  * @param iter the iterator
  * @param filename string to be set to the next file in the dir
- * @param result return location for error, or #DBUS_RESULT_SUCCESS
+ * @param error return location for error
  * @returns #TRUE if filename was filled in with a new filename
  */
 dbus_bool_t
 _dbus_directory_get_next_file (DBusDirIter      *iter,
                                DBusString       *filename,
-                               DBusResultCode   *result)
+                               DBusError        *error)
 {
   /* we always have to put something in result, since return
    * value means whether there's a filename and doesn't
    * reliably indicate whether an error was set.
    */
   struct dirent *ent;
-  
-  dbus_set_result (result, DBUS_RESULT_SUCCESS);
 
  again:
   errno = 0;
   ent = readdir (iter->d);
   if (ent == NULL)
     {
-      dbus_set_result (result,
-                       _dbus_result_from_errno (errno));
+      if (errno != 0)
+        dbus_set_error (error,
+                        _dbus_error_from_errno (errno),
+                        "%s", _dbus_strerror (errno));
       return FALSE;
     }
   else if (ent->d_name[0] == '.' &&
@@ -2050,7 +2057,8 @@ _dbus_directory_get_next_file (DBusDirIter      *iter,
       _dbus_string_set_length (filename, 0);
       if (!_dbus_string_append (filename, ent->d_name))
         {
-          dbus_set_result (result, DBUS_RESULT_NO_MEMORY);
+          dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
+                          "No memory to read directory entry");
           return FALSE;
         }
       else
@@ -2501,4 +2509,249 @@ _dbus_fd_set_close_on_exec (int fd)
   fcntl (fd, F_SETFD, val);
 }
 
+
+/**
+ * Converts a UNIX errno into a DBusResultCode.
+ *
+ * @todo should cover more errnos, specifically those
+ * from open().
+ * 
+ * @param error_number the errno.
+ * @returns the result code.
+ */
+DBusResultCode
+_dbus_result_from_errno (int error_number)
+{
+  switch (error_number)
+    {
+    case 0:
+      return DBUS_RESULT_SUCCESS;
+      
+#ifdef EPROTONOSUPPORT
+    case EPROTONOSUPPORT:
+      return DBUS_RESULT_NOT_SUPPORTED;
+#endif
+#ifdef EAFNOSUPPORT
+    case EAFNOSUPPORT:
+      return DBUS_RESULT_NOT_SUPPORTED;
+#endif
+#ifdef ENFILE
+    case ENFILE:
+      return DBUS_RESULT_LIMITS_EXCEEDED; /* kernel out of memory */
+#endif
+#ifdef EMFILE
+    case EMFILE:
+      return DBUS_RESULT_LIMITS_EXCEEDED;
+#endif
+#ifdef EACCES
+    case EACCES:
+      return DBUS_RESULT_ACCESS_DENIED;
+#endif
+#ifdef EPERM
+    case EPERM:
+      return DBUS_RESULT_ACCESS_DENIED;
+#endif
+#ifdef ENOBUFS
+    case ENOBUFS:
+      return DBUS_RESULT_NO_MEMORY;
+#endif
+#ifdef ENOMEM
+    case ENOMEM:
+      return DBUS_RESULT_NO_MEMORY;
+#endif
+#ifdef EINVAL
+    case EINVAL:
+      return DBUS_RESULT_FAILED;
+#endif
+#ifdef EBADF
+    case EBADF:
+      return DBUS_RESULT_FAILED;
+#endif
+#ifdef EFAULT
+    case EFAULT:
+      return DBUS_RESULT_FAILED;
+#endif
+#ifdef ENOTSOCK
+    case ENOTSOCK:
+      return DBUS_RESULT_FAILED;
+#endif
+#ifdef EISCONN
+    case EISCONN:
+      return DBUS_RESULT_FAILED;
+#endif
+#ifdef ECONNREFUSED
+    case ECONNREFUSED:
+      return DBUS_RESULT_NO_SERVER;
+#endif
+#ifdef ETIMEDOUT
+    case ETIMEDOUT:
+      return DBUS_RESULT_TIMEOUT;
+#endif
+#ifdef ENETUNREACH
+    case ENETUNREACH:
+      return DBUS_RESULT_NO_NETWORK;
+#endif
+#ifdef EADDRINUSE
+    case EADDRINUSE:
+      return DBUS_RESULT_ADDRESS_IN_USE;
+#endif
+#ifdef EEXIST
+    case EEXIST:
+      return DBUS_RESULT_FILE_NOT_FOUND;
+#endif
+#ifdef ENOENT
+    case ENOENT:
+      return DBUS_RESULT_FILE_NOT_FOUND;
+#endif
+    }
+
+  return DBUS_RESULT_FAILED;
+}
+
+/**
+ * Converts a UNIX errno into a #DBusError name.
+ *
+ * @todo should cover more errnos, specifically those
+ * from open().
+ * 
+ * @param error_number the errno.
+ * @returns an error name
+ */
+const char*
+_dbus_error_from_errno (int error_number)
+{
+  switch (error_number)
+    {
+    case 0:
+      return DBUS_ERROR_FAILED;
+      
+#ifdef EPROTONOSUPPORT
+    case EPROTONOSUPPORT:
+      return DBUS_ERROR_NOT_SUPPORTED;
+#endif
+#ifdef EAFNOSUPPORT
+    case EAFNOSUPPORT:
+      return DBUS_ERROR_NOT_SUPPORTED;
+#endif
+#ifdef ENFILE
+    case ENFILE:
+      return DBUS_ERROR_LIMITS_EXCEEDED; /* kernel out of memory */
+#endif
+#ifdef EMFILE
+    case EMFILE:
+      return DBUS_ERROR_LIMITS_EXCEEDED;
+#endif
+#ifdef EACCES
+    case EACCES:
+      return DBUS_ERROR_ACCESS_DENIED;
+#endif
+#ifdef EPERM
+    case EPERM:
+      return DBUS_ERROR_ACCESS_DENIED;
+#endif
+#ifdef ENOBUFS
+    case ENOBUFS:
+      return DBUS_ERROR_NO_MEMORY;
+#endif
+#ifdef ENOMEM
+    case ENOMEM:
+      return DBUS_ERROR_NO_MEMORY;
+#endif
+#ifdef EINVAL
+    case EINVAL:
+      return DBUS_ERROR_FAILED;
+#endif
+#ifdef EBADF
+    case EBADF:
+      return DBUS_ERROR_FAILED;
+#endif
+#ifdef EFAULT
+    case EFAULT:
+      return DBUS_ERROR_FAILED;
+#endif
+#ifdef ENOTSOCK
+    case ENOTSOCK:
+      return DBUS_ERROR_FAILED;
+#endif
+#ifdef EISCONN
+    case EISCONN:
+      return DBUS_ERROR_FAILED;
+#endif
+#ifdef ECONNREFUSED
+    case ECONNREFUSED:
+      return DBUS_ERROR_NO_SERVER;
+#endif
+#ifdef ETIMEDOUT
+    case ETIMEDOUT:
+      return DBUS_ERROR_TIMEOUT;
+#endif
+#ifdef ENETUNREACH
+    case ENETUNREACH:
+      return DBUS_ERROR_NO_NETWORK;
+#endif
+#ifdef EADDRINUSE
+    case EADDRINUSE:
+      return DBUS_ERROR_ADDRESS_IN_USE;
+#endif
+#ifdef EEXIST
+    case EEXIST:
+      return DBUS_ERROR_FILE_NOT_FOUND;
+#endif
+#ifdef ENOENT
+    case ENOENT:
+      return DBUS_ERROR_FILE_NOT_FOUND;
+#endif
+    }
+
+  return DBUS_ERROR_FAILED;
+}
+
+/**
+ * Exit the process, returning the given value.
+ *
+ * @param code the exit code
+ */
+void
+_dbus_exit (int code)
+{
+  _exit (code);
+}
+
+/**
+ * stat() wrapper.
+ *
+ * @param filename the filename to stat
+ * @param statbuf the stat info to fill in
+ * @param error return location for error
+ * @returns #FALSE if error was set
+ */
+dbus_bool_t
+_dbus_stat (const DBusString *filename,
+            DBusStat         *statbuf,
+            DBusError        *error)
+{
+  const char *filename_c;
+  struct stat sb;
+  
+  _dbus_string_get_const_data (filename, &filename_c);
+
+  if (stat (filename_c, &sb) < 0)
+    {
+      dbus_set_error (error, _dbus_error_from_errno (errno),
+                      "%s", _dbus_strerror (errno));
+      return FALSE;
+    }
+
+  statbuf->mode = sb.st_mode;
+  statbuf->nlink = sb.st_nlink;
+  statbuf->uid = sb.st_uid;
+  statbuf->gid = sb.st_gid;
+  statbuf->size = sb.st_size;
+  statbuf->atime = sb.st_atime;
+  statbuf->mtime = sb.st_mtime;
+  statbuf->ctime = sb.st_ctime;
+
+  return TRUE;
+}
+
 /** @} end of sysdeps */
index fb8362e..f1ac47c 100644 (file)
@@ -138,8 +138,9 @@ void _dbus_sleep_milliseconds (int milliseconds);
 void _dbus_get_current_time (long *tv_sec,
                              long *tv_usec);
 
-DBusResultCode _dbus_file_get_contents   (DBusString       *str,
-                                          const DBusString *filename);
+dbus_bool_t _dbus_file_get_contents   (DBusString       *str,
+                                       const DBusString *filename,
+                                       DBusError        *error);
 DBusResultCode _dbus_string_save_to_file (const DBusString *str,
                                           const DBusString *filename);
 
@@ -156,17 +157,18 @@ dbus_bool_t _dbus_concat_dir_and_file (DBusString       *dir,
 typedef struct DBusDirIter DBusDirIter;
 
 DBusDirIter* _dbus_directory_open          (const DBusString *filename,
-                                            DBusResultCode   *result);
+                                            DBusError        *error);
 dbus_bool_t  _dbus_directory_get_next_file (DBusDirIter      *iter,
                                             DBusString       *filename,
-                                            DBusResultCode   *result);
+                                            DBusError        *error);
 void         _dbus_directory_close         (DBusDirIter      *iter);
 
 
 dbus_bool_t _dbus_generate_random_bytes (DBusString *str,
                                          int         n_bytes);
 
-const char *_dbus_errno_to_string (int         errnum);
+const char *_dbus_errno_to_string  (int errnum);
+const char* _dbus_error_from_errno (int error_number);
 
 typedef void (* DBusSpawnChildSetupFunc) (void *user_data);
 
@@ -180,6 +182,24 @@ void _dbus_disable_sigpipe (void);
 
 void _dbus_fd_set_close_on_exec (int fd);
 
+void _dbus_exit (int code);
+
+typedef struct
+{
+  unsigned long mode;
+  unsigned long nlink;
+  unsigned long uid;
+  unsigned long gid;
+  unsigned long size;
+  unsigned long atime;
+  unsigned long mtime;
+  unsigned long ctime;
+} DBusStat;
+
+dbus_bool_t _dbus_stat (const DBusString *filename,
+                        DBusStat         *statbuf,
+                        DBusError        *error);
+
 DBUS_END_DECLS;
 
 #endif /* DBUS_SYSDEPS_H */
index fe9cd6b..b5c4402 100644 (file)
@@ -7,13 +7,13 @@ main (int argc, char **argv)
 {
   DBusConnection *connection;
   DBusResultCode result;
-  DBusMessage *message, *reply;
-  
+  DBusMessage *message, *reply;  
   GMainLoop *loop;
+  DBusError error;
   
   if (argc < 2)
     {
-      fprintf (stderr, "Give the server address as an argument\n");
+      g_printerr ("Give the server address as an argument\n");
       return 1;
     }
 
@@ -22,8 +22,8 @@ main (int argc, char **argv)
   connection = dbus_connection_open (argv[1], &result);
   if (connection == NULL)
     {
-      fprintf (stderr, "Failed to open connection to %s: %s\n", argv[1],
-              dbus_result_to_string (result));
+      g_printerr ("Failed to open connection to %s: %s\n", argv[1],
+                  dbus_result_to_string (result));
       return 1;
     }
 
@@ -31,7 +31,15 @@ main (int argc, char **argv)
 
   message = dbus_message_new ("org.freedesktop.DBus", "org.freedesktop.DBus.Hello");
 
-  reply = dbus_connection_send_message_with_reply_and_block (connection, message, -1, &result);
+  dbus_error_init (&error);
+  reply = dbus_connection_send_with_reply_and_block (connection, message, -1, &error);
+  if (reply == NULL)
+    {
+      g_printerr ("Error on hello message: %s\n", error.message);
+      dbus_error_free (&error);
+      return 1;
+    }
+  
   g_print ("reply name: %s\n", dbus_message_get_name (reply));
   
   g_main_loop_run (loop);
index ca78dbb..23ec3f3 100644 (file)
@@ -37,12 +37,13 @@ thread_func (gpointer data)
        }
       g_free (str);
 
-      if (!dbus_connection_send_message (connection,
-                                        message,
-                                        NULL, NULL))
+      if (!dbus_connection_send (connection,
+                                 message,
+                                 NULL))
        {
-         g_print ("thread %d: send message failerd\n", threadnr);
+         g_print ("thread %d: send message failed\n", threadnr);
        }
+      
       dbus_message_unref (message);
       
       counter ++;
index 342e806..e059e6c 100644 (file)
@@ -62,24 +62,34 @@ test_hello_client1_handler (DBusMessageHandler *handler,
 
   if (!test_hello_succeeding)
     goto out;
+
+#if 1
+  printf ("In stage %d got message %s\n",
+          client1_stage, dbus_message_get_name (message));
+#endif
   
   if (dbus_message_name_is (message, DBUS_MESSAGE_HELLO))
     {
       TEST_HELLO_HANDLE_FAIL (client1_stage == 0);
 
-      TEST_HELLO_HANDLE_FAIL ((dbus_message_get_args (message,
-                                                     DBUS_TYPE_STRING, &client1_name,
-                                                     0) == DBUS_RESULT_SUCCESS));
+      TEST_HELLO_HANDLE_FAIL (dbus_message_get_args (message, NULL,
+                                                     DBUS_TYPE_STRING, &client1_name,
+                                                     0));
 
       client1_stage += 1;
     }
   else if (dbus_message_name_is (message, DBUS_MESSAGE_SERVICE_CREATED))
     {
-      TEST_HELLO_HANDLE_FAIL (client1_stage == 1 || client1_stage == 3);
+      TEST_HELLO_HANDLE_FAIL (dbus_message_get_args (message, NULL,
+                                                     DBUS_TYPE_STRING, &tmp,
+                                                     0));
 
-      TEST_HELLO_HANDLE_FAIL ((dbus_message_get_args (message,
-                                                     DBUS_TYPE_STRING, &tmp,
-                                                     0) == DBUS_RESULT_SUCCESS));
+#if 0
+      printf ("ServiceCreated is %s\n", tmp);
+#endif
+      
+      TEST_HELLO_HANDLE_FAIL (client1_stage == 1 || client1_stage == 3);
+              
       if (client1_stage == 1)
        TEST_HELLO_HANDLE_FAIL (strcmp (client1_name, tmp) == 0);
       else
@@ -94,9 +104,9 @@ test_hello_client1_handler (DBusMessageHandler *handler,
     {
       TEST_HELLO_HANDLE_FAIL (client1_stage == 2);
 
-      TEST_HELLO_HANDLE_FAIL ((dbus_message_get_args (message,
-                                                     DBUS_TYPE_STRING, &tmp,
-                                                     0) == DBUS_RESULT_SUCCESS));
+      TEST_HELLO_HANDLE_FAIL (dbus_message_get_args (message, NULL,
+                                                     DBUS_TYPE_STRING, &tmp,
+                                                     0));
       TEST_HELLO_HANDLE_FAIL (strcmp (client1_name, tmp) == 0);
 
       client1_stage += 1;
@@ -132,9 +142,9 @@ test_hello_client2_handler (DBusMessageHandler *handler,
     {
       TEST_HELLO_HANDLE_FAIL (client2_stage == 0);
 
-      TEST_HELLO_HANDLE_FAIL ((dbus_message_get_args (message,
-                                                     DBUS_TYPE_STRING, &client2_name,
-                                                     0) == DBUS_RESULT_SUCCESS));
+      TEST_HELLO_HANDLE_FAIL (dbus_message_get_args (message, NULL,
+                                                     DBUS_TYPE_STRING, &client2_name,
+                                                     0));
 
       client2_stage += 1;
     }
@@ -142,9 +152,9 @@ test_hello_client2_handler (DBusMessageHandler *handler,
     {
       TEST_HELLO_HANDLE_FAIL (client2_stage == 1);
 
-      TEST_HELLO_HANDLE_FAIL ((dbus_message_get_args (message,
-                                                     DBUS_TYPE_STRING, &tmp,
-                                                     0) == DBUS_RESULT_SUCCESS));
+      TEST_HELLO_HANDLE_FAIL (dbus_message_get_args (message, NULL,
+                                                     DBUS_TYPE_STRING, &tmp,
+                                                     0));
       TEST_HELLO_HANDLE_FAIL (strcmp (client2_name, tmp) == 0);
       
       client2_stage += 1;
@@ -153,9 +163,9 @@ test_hello_client2_handler (DBusMessageHandler *handler,
     {
       TEST_HELLO_HANDLE_FAIL (client2_stage == 2);
 
-      TEST_HELLO_HANDLE_FAIL ((dbus_message_get_args (message,
-                                                     DBUS_TYPE_STRING, &tmp,
-                                                     0) == DBUS_RESULT_SUCCESS));
+      TEST_HELLO_HANDLE_FAIL (dbus_message_get_args (message, NULL,
+                                                     DBUS_TYPE_STRING, &tmp,
+                                                     0));
       TEST_HELLO_HANDLE_FAIL (strcmp (client2_name, tmp) == 0);
 
       client2_stage += 1;
@@ -177,9 +187,9 @@ static dbus_bool_t
 test_hello_replies (void)
 {
   DBusConnection *connection;
-  DBusResultCode result;
   DBusMessage *message;
   DBusMessageHandler *handler;
+  DBusResultCode result;
   
   /* First start client 1 */
   connection = dbus_connection_open ("debug:name=test-server", &result);
@@ -188,7 +198,8 @@ test_hello_replies (void)
                              DBUS_MESSAGE_HELLO);
   handler = dbus_message_handler_new (test_hello_client1_handler, NULL, NULL);
   dbus_connection_add_filter (connection, handler);
-  dbus_connection_send_message (connection, message, NULL, NULL);
+  if (!dbus_connection_send (connection, message, NULL))
+    die ("no memory to send message");
   dbus_message_unref (message);
 
   /* Then start client 2 */
@@ -198,7 +209,8 @@ test_hello_replies (void)
                              DBUS_MESSAGE_HELLO);
   handler = dbus_message_handler_new (test_hello_client2_handler, NULL, NULL);
   dbus_connection_add_filter (connection, handler);
-  dbus_connection_send_message (connection, message, NULL, NULL);
+  if (!dbus_connection_send (connection, message, NULL))
+    die ("no memory to send message");
   dbus_message_unref (message);
 
   bus_test_loop_run ();
index 0b9d018..0de1a78 100644 (file)
@@ -1,6 +1,9 @@
 # A simple dict
 
 VALID_HEADER
+FIELD_NAME name
+TYPE STRING
+STRING 'org.freedesktop.Foo'
 END_LENGTH Header
 ALIGN 8
 START_LENGTH Body
index 0532e68..ce99a28 100644 (file)
@@ -1,8 +1,11 @@
 # Dict with different values
 
 VALID_HEADER
-END_LENGTH Header
+FIELD_NAME name
+TYPE STRING
+STRING 'org.freedesktop.Foo'
 ALIGN 8
+END_LENGTH Header
 START_LENGTH Body
 TYPE DICT
 STRING_ARRAY { 'boolean', 'int32', 'uint32', 'double', 'string', 'boolean_array', 'int32_array', 'uint32_array', 'double_array', 'string_array' }
index 6a7d5eb..cc9c5a7 100644 (file)
@@ -1,6 +1,9 @@
 # Message with lots of different argument types
 
 VALID_HEADER
+FIELD_NAME name
+TYPE STRING
+STRING 'org.freedesktop.Foo'
 END_LENGTH Header
 ALIGN 8
 START_LENGTH Body
index c21c84d..ab5b5a8 100644 (file)
@@ -3,6 +3,10 @@
 ## VALID_HEADER includes a LENGTH Header and LENGTH Body
 VALID_HEADER
 
+FIELD_NAME name
+TYPE STRING
+STRING 'org.freedesktop.Foo'
+
 ## this byte array is filled with zeros to the natural length 
 ## of the header
 FIELD_NAME unkn
index 3f002ed..8eed1e5 100644 (file)
@@ -10,6 +10,9 @@ LENGTH Header
 LENGTH Body
 ## client serial
 INT32 7
+FIELD_NAME name
+TYPE STRING
+STRING 'org.freedesktop.Foo'
 ALIGN 8
 END_LENGTH Header
 START_LENGTH Body
index a0283aa..7bb1872 100644 (file)
@@ -2,6 +2,9 @@
 
 ## VALID_HEADER includes a LENGTH Header and LENGTH Body
 VALID_HEADER
+FIELD_NAME name
+TYPE STRING
+STRING 'org.freedesktop.Foo'
 ALIGN 8
 END_LENGTH Header
 START_LENGTH Body
index 47d7314..de32957 100644 (file)
@@ -28,10 +28,10 @@ main (int    argc,
 
   /* Send a message to get things going */
   message = dbus_message_new ("org.freedesktop.DBus.Test", "org.freedesktop.DBus.Test");
-  dbus_connection_send_message (connection,
-                                message,
-                               NULL, 
-                                NULL);
+  if (!dbus_connection_send (connection,
+                             message,
+                             NULL))
+    fprintf (stderr, "No memory to send reply\n");
   dbus_message_unref (message);
   
   do_mainloop ();
index cc12365..f3894bd 100644 (file)
@@ -14,6 +14,7 @@ main (int    argc,
   DBusString decoded;
   DBusString filename;
   const char *s;
+  DBusError error;
   
   if (argc < 2)
     {
@@ -29,8 +30,13 @@ main (int    argc,
   if (!_dbus_string_init (&decoded, _DBUS_INT_MAX))
     return 1;
 
-  if (_dbus_file_get_contents (&contents, &filename) != DBUS_RESULT_SUCCESS)
-    return 1;
+  dbus_error_init (&error);
+  if (!_dbus_file_get_contents (&contents, &filename, &error))
+    {
+      fprintf (stderr, "Failed to load file: %s\n", error.message);
+      dbus_error_free (&error);
+      return 1;
+    }
 
   if (!_dbus_string_base64_decode (&contents, 0,
                                    &decoded, 0))
index 1a31e64..d8e91b7 100644 (file)
@@ -168,10 +168,10 @@ check_messages (void)
              fprintf (stderr, "Received message %d, sending reply\n", count);
              
              reply = dbus_message_new ("org.freedesktop.DBus.Test", "org.freedesktop.DBus.Test");
-             dbus_connection_send_message (connection,
-                                           reply,
-                                           NULL, 
-                                           NULL);
+             if (!dbus_connection_send (connection,
+                                         reply,
+                                         NULL))
+                fprintf (stderr, "No memory to send reply\n");
              dbus_message_unref (reply);
              
              dbus_message_unref (message);