2003-03-16 Havoc Pennington <hp@pobox.com>
authorHavoc Pennington <hp@redhat.com>
Mon, 17 Mar 2003 01:54:37 +0000 (01:54 +0000)
committerHavoc Pennington <hp@redhat.com>
Mon, 17 Mar 2003 01:54:37 +0000 (01:54 +0000)
* dbus/dbus-watch.c (_dbus_watch_new): handle failure to malloc
the watch

* dbus/dbus-server-debug-pipe.c (_dbus_transport_debug_pipe_new):
add some missing dbus_set_result

* bus/dispatch.c (bus_dispatch_add_connection): handle failure to
alloc the DBusMessageHandler

* dbus/dbus-transport.c (_dbus_transport_disconnect): don't ref
the transport here, since we call this from the finalizer; it
resulted in a double-finalize.

* dbus/dbus-transport.c (_dbus_transport_disconnect): fix a bug
where we tried to use transport->connection that was NULL,
happened when transport was disconnected early on due to OOM

* bus/*.c: adapt to handle OOM for watches/timeouts

* dbus/dbus-transport-unix.c: port to handle OOM during
watch handling

* dbus/dbus-auth.c (_dbus_auth_get_unused_bytes): return a
reference to unused bytes instead of a copy

* dbus/dbus-server.c (dbus_server_handle_watch): return FALSE for
out of memory

* dbus/dbus-connection.c (dbus_connection_handle_watch): return
FALSE on OOM

* dbus/dbus-timeout.c (dbus_timeout_handle): return FALSE for out
of memory

29 files changed:
ChangeLog
bus/bus.c
bus/connection.c
bus/dispatch.c
bus/loop.c
bus/loop.h
bus/test.c
bus/utils.c
bus/utils.h
dbus/dbus-auth-script.c
dbus/dbus-auth.c
dbus/dbus-auth.h
dbus/dbus-connection.c
dbus/dbus-connection.h
dbus/dbus-server-debug-pipe.c
dbus/dbus-server-debug.c
dbus/dbus-server-protected.h
dbus/dbus-server-unix.c
dbus/dbus-server.c
dbus/dbus-server.h
dbus/dbus-sysdeps.c
dbus/dbus-timeout.c
dbus/dbus-timeout.h
dbus/dbus-transport-debug.c
dbus/dbus-transport-protected.h
dbus/dbus-transport-unix.c
dbus/dbus-transport.c
dbus/dbus-transport.h
dbus/dbus-watch.c

index e31696d..f38c924 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,39 @@
+2003-03-16  Havoc Pennington  <hp@pobox.com>
+
+       * dbus/dbus-watch.c (_dbus_watch_new): handle failure to malloc
+       the watch
+
+       * dbus/dbus-server-debug-pipe.c (_dbus_transport_debug_pipe_new):
+       add some missing dbus_set_result
+
+       * bus/dispatch.c (bus_dispatch_add_connection): handle failure to 
+       alloc the DBusMessageHandler
+
+       * dbus/dbus-transport.c (_dbus_transport_disconnect): don't ref
+       the transport here, since we call this from the finalizer; it 
+       resulted in a double-finalize.
+
+       * dbus/dbus-transport.c (_dbus_transport_disconnect): fix a bug 
+       where we tried to use transport->connection that was NULL, 
+       happened when transport was disconnected early on due to OOM
+
+       * bus/*.c: adapt to handle OOM for watches/timeouts
+
+       * dbus/dbus-transport-unix.c: port to handle OOM during 
+       watch handling
+       
+       * dbus/dbus-auth.c (_dbus_auth_get_unused_bytes): return a
+       reference to unused bytes instead of a copy
+
+       * dbus/dbus-server.c (dbus_server_handle_watch): return FALSE for
+       out of memory
+
+       * dbus/dbus-connection.c (dbus_connection_handle_watch): return
+       FALSE on OOM
+
+       * dbus/dbus-timeout.c (dbus_timeout_handle): return FALSE for out
+       of memory
+
 2003-03-16  Anders Carlsson  <andersca@codefactory.se>
 
        * doc/dbus-specification.sgml:
index 589dda1..a1bc662 100644 (file)
--- a/bus/bus.c
+++ b/bus/bus.c
@@ -39,14 +39,14 @@ struct BusContext
   BusRegistry *registry;
 };
 
-static void
+static dbus_bool_t
 server_watch_callback (DBusWatch     *watch,
                        unsigned int   condition,
                        void          *data)
 {
   BusContext *context = data;
 
-  dbus_server_handle_watch (context->server, watch, condition);  
+  return dbus_server_handle_watch (context->server, watch, condition);
 }
 
 static dbus_bool_t
@@ -69,6 +69,7 @@ static void
 server_timeout_callback (DBusTimeout   *timeout,
                          void          *data)
 {
+  /* can return FALSE on OOM but we just let it fire again later */
   dbus_timeout_handle (timeout);
 }
 
index 80afc7e..a861668 100644 (file)
@@ -133,20 +133,23 @@ bus_connection_disconnected (DBusConnection *connection)
   dbus_connection_unref (connection);
 }
 
-static void
+static dbus_bool_t
 connection_watch_callback (DBusWatch     *watch,
                            unsigned int   condition,
                            void          *data)
 {
   DBusConnection *connection = data;
+  dbus_bool_t retval;
 
   dbus_connection_ref (connection);
   
-  dbus_connection_handle_watch (connection, watch, condition);
+  retval = dbus_connection_handle_watch (connection, watch, condition);
 
   bus_connection_dispatch_all_messages (connection);
   
   dbus_connection_unref (connection);
+
+  return retval;
 }
 
 static dbus_bool_t
@@ -171,7 +174,8 @@ connection_timeout_callback (DBusTimeout   *timeout,
   DBusConnection *connection = data;
 
   dbus_connection_ref (connection);
-  
+
+  /* can return FALSE on OOM but we just let it fire again later */
   dbus_timeout_handle (timeout);
 
   bus_connection_dispatch_all_messages (connection);
index 639b950..b4b03d9 100644 (file)
@@ -365,7 +365,12 @@ bus_dispatch_add_connection (DBusConnection *connection)
     return FALSE;
   
   handler = dbus_message_handler_new (bus_dispatch_message_handler, NULL, NULL);  
-
+  if (handler == NULL)
+    {
+      message_handler_slot_unref ();
+      return FALSE;
+    }
+  
   if (!dbus_connection_add_filter (connection, handler))
     {
       dbus_message_handler_unref (handler);
index ea0ec10..93096dc 100644 (file)
@@ -50,6 +50,8 @@ typedef struct
   Callback callback;
   BusWatchFunction function;
   DBusWatch *watch;
+  /* last watch handle failed due to OOM */
+  unsigned int last_iteration_oom : 1;
 } WatchCallback;
 
 typedef struct
@@ -78,6 +80,7 @@ watch_callback_new (DBusWatch        *watch,
 
   cb->watch = watch;
   cb->function = function;
+  cb->last_iteration_oom = FALSE;
   cb->callback.type = CALLBACK_WATCH;
   cb->callback.data = data;
   cb->callback.free_data_func = free_data_func;
@@ -278,11 +281,13 @@ bus_loop_iterate (dbus_bool_t block)
   int n_ready;
   int initial_serial;
   long timeout;
-
+  dbus_bool_t oom_watch_pending;
+  
   retval = FALSE;
       
   fds = NULL;
   watches_for_fds = NULL;
+  oom_watch_pending = FALSE;
 
 #if 0
   _dbus_verbose (" iterate %d timeouts %d watches\n",
@@ -306,7 +311,8 @@ bus_loop_iterate (dbus_bool_t block)
         {
           WatchCallback *wcb = WATCH_CALLBACK (cb);
 
-          if (dbus_watch_get_enabled (wcb->watch))
+          if (!wcb->last_iteration_oom &&
+              dbus_watch_get_enabled (wcb->watch))
             ++n_fds;
         }
       
@@ -341,7 +347,15 @@ bus_loop_iterate (dbus_bool_t block)
               unsigned int flags;
               WatchCallback *wcb = WATCH_CALLBACK (cb);
 
-              if (dbus_watch_get_enabled (wcb->watch))
+              if (wcb->last_iteration_oom)
+                {
+                  /* we skip this one this time, but reenable it next time,
+                   * and have a timeout on this iteration
+                   */
+                  wcb->last_iteration_oom = FALSE;
+                  oom_watch_pending = TRUE;
+                }
+              else if (dbus_watch_get_enabled (wcb->watch))
                 {
                   watches_for_fds[i] = wcb;
                   
@@ -423,7 +437,13 @@ bus_loop_iterate (dbus_bool_t block)
 
   if (!block)
     timeout = 0;
-      
+
+  /* if a watch is OOM, don't wait longer than the OOM
+   * wait to re-enable it
+   */
+  if (oom_watch_pending)
+    timeout = MIN (timeout, bus_get_oom_wait ());
+  
   n_ready = _dbus_poll (fds, n_fds, timeout);
 
   initial_serial = callback_list_serial;
@@ -538,9 +558,10 @@ bus_loop_iterate (dbus_bool_t block)
               if (condition != 0 &&
                   dbus_watch_get_enabled (wcb->watch))
                 {
-                  (* wcb->function) (wcb->watch,
-                                     condition,
-                                     ((Callback*)wcb)->data);
+                  if (!(* wcb->function) (wcb->watch,
+                                          condition,
+                                          ((Callback*)wcb)->data))
+                    wcb->last_iteration_oom = TRUE;
 
                   retval = TRUE;
                 }
index 72b356b..b217a77 100644 (file)
 
 #include <dbus/dbus.h>
 
-typedef void (* BusWatchFunction)   (DBusWatch     *watch,
-                                     unsigned int   condition,
-                                     void          *data);
-typedef void (* BusTimeoutFunction) (DBusTimeout   *timeout,
-                                     void          *data);
+typedef dbus_bool_t (* BusWatchFunction)   (DBusWatch     *watch,
+                                            unsigned int   condition,
+                                            void          *data);
+typedef void        (* BusTimeoutFunction) (DBusTimeout   *timeout,
+                                            void          *data);
 
 dbus_bool_t bus_loop_add_watch      (DBusWatch          *watch,
                                      BusWatchFunction    function,
index 09e40f3..7de1d81 100644 (file)
  */
 static DBusList *clients = NULL;
 
-static void
+static dbus_bool_t
 client_watch_callback (DBusWatch     *watch,
                            unsigned int   condition,
                            void          *data)
 {
   DBusConnection *connection = data;
-
+  dbus_bool_t retval;
+  
   dbus_connection_ref (connection);
   
-  dbus_connection_handle_watch (connection, watch, condition);
+  retval = dbus_connection_handle_watch (connection, watch, condition);
 
   dbus_connection_unref (connection);
+
+  return retval;
 }
 
 static dbus_bool_t
@@ -71,7 +74,8 @@ client_timeout_callback (DBusTimeout   *timeout,
   DBusConnection *connection = data;
 
   dbus_connection_ref (connection);
-  
+
+  /* can return FALSE on OOM but we just let it fire again later */
   dbus_timeout_handle (timeout);
 
   dbus_connection_unref (connection);
index 8a68d8a..090e27f 100644 (file)
 
 const char bus_no_memory_message[] = "Memory allocation failure in message bus";
 
-void
-bus_wait_for_memory (void)
+int
+bus_get_oom_wait (void)
 {
 #ifdef DBUS_BUILD_TESTS
   /* make tests go fast */
-  _dbus_sleep_milliseconds (10);
+  return 10;
 #else
-  _dbus_sleep_milliseconds (500);
+  return 500;
 #endif
 }
 
 void
+bus_wait_for_memory (void)
+{
+  _dbus_sleep_milliseconds (bus_get_oom_wait ());
+}
+
+void
 bus_connection_dispatch_all_messages (DBusConnection *connection)
 {
   while (bus_connection_dispatch_one_message (connection))
index 968ece3..5b30de6 100644 (file)
@@ -27,6 +27,7 @@
 
 #include <dbus/dbus.h>
 
+int  bus_get_oom_wait    (void);
 void bus_wait_for_memory (void);
 
 extern const char bus_no_memory_message[];
index 336d63e..d954c8d 100644 (file)
@@ -437,14 +437,23 @@ _dbus_auth_script_run (const DBusString *filename)
                 _dbus_string_free (&username);
               }
           }
-          
-          if (!_dbus_auth_bytes_received (auth, &to_send))
-            {
-              _dbus_warn ("not enough memory to call bytes_received, or can't add bytes to auth object already in end state\n");
-              _dbus_string_free (&to_send);
-              goto out;
-            }
 
+          {
+            DBusString *buffer;
+
+            _dbus_auth_get_buffer (auth, &buffer);
+            if (!_dbus_string_copy (&to_send, 0,
+                                    buffer, _dbus_string_get_length (buffer)))
+              {
+                _dbus_warn ("not enough memory to call bytes_received, or can't add bytes to auth object already in end state\n");
+                _dbus_string_free (&to_send);
+                _dbus_auth_return_buffer (auth, buffer, 0);
+                goto out;
+              }
+
+            _dbus_auth_return_buffer (auth, buffer, _dbus_string_get_length (&to_send));
+          }
+          
           _dbus_string_free (&to_send);
         }
       else if (_dbus_string_starts_with_c_str (&line,
@@ -510,7 +519,7 @@ _dbus_auth_script_run (const DBusString *filename)
                                                "EXPECT_UNUSED"))
         {
           DBusString expected;
-          DBusString unused;
+          const DBusString *unused;
           
           _dbus_string_delete_first_word (&line);
 
@@ -528,35 +537,20 @@ _dbus_auth_script_run (const DBusString *filename)
               goto out;
             }
 
-          if (!_dbus_string_init (&unused, _DBUS_INT_MAX))
-            {
-              _dbus_warn ("no mem to allocate string unused\n");
-              _dbus_string_free (&expected);
-              goto out;
-            }
-
-          if (!_dbus_auth_get_unused_bytes (auth, &unused))
-            {
-              _dbus_warn ("couldn't get unused bytes\n");
-              _dbus_string_free (&expected);
-              _dbus_string_free (&unused);
-              goto out;
-            }
+          _dbus_auth_get_unused_bytes (auth, &unused);
           
-          if (_dbus_string_equal (&expected, &unused))
+          if (_dbus_string_equal (&expected, unused))
             {
               _dbus_string_free (&expected);
-              _dbus_string_free (&unused);
             }
           else
             {
               const char *e1, *h1;
               _dbus_string_get_const_data (&expected, &e1);
-              _dbus_string_get_const_data (&unused, &h1);
+              _dbus_string_get_const_data (unused, &h1);
               _dbus_warn ("Expected unused bytes '%s' and have '%s'\n",
                           e1, h1);
               _dbus_string_free (&expected);
-              _dbus_string_free (&unused);
               goto out;
             }
         }
index 4b1f550..9e2b1d9 100644 (file)
@@ -169,6 +169,7 @@ struct DBusAuth
   unsigned int authenticated_pending_begin : 1;  /**< Authenticated once we get BEGIN */
   unsigned int already_got_mechanisms : 1;       /**< Client already got mech list */
   unsigned int already_asked_for_initial_response : 1; /**< Already sent a blank challenge to get an initial response */
+  unsigned int buffer_outstanding : 1; /**< Buffer is "checked out" for reading data into */
 };
 
 typedef struct
@@ -1996,35 +1997,40 @@ _dbus_auth_bytes_sent (DBusAuth *auth,
 }
 
 /**
- * Stores bytes received from the peer we're conversing with.
+ * Get a buffer to be used for reading bytes from the peer we're conversing
+ * with. Bytes should be appended to this buffer.
  *
  * @param auth the auth conversation
- * @param str the received bytes.
- * @returns #FALSE if not enough memory to store the bytes or we were already authenticated.
+ * @param buffer return location for buffer to append bytes to
  */
-dbus_bool_t
-_dbus_auth_bytes_received (DBusAuth   *auth,
-                           const DBusString *str)
+void
+_dbus_auth_get_buffer (DBusAuth     *auth,
+                       DBusString **buffer)
 {
   _dbus_assert (auth != NULL);
-  _dbus_assert (str != NULL);
+  _dbus_assert (!auth->buffer_outstanding);
   
-  if (DBUS_AUTH_IN_END_STATE (auth))
-    return FALSE;
+  *buffer = &auth->incoming;
 
-  auth->needed_memory = FALSE;
-  
-  if (!_dbus_string_copy (str, 0,
-                          &auth->incoming,
-                          _dbus_string_get_length (&auth->incoming)))
-    {
-      auth->needed_memory = TRUE;
-      return FALSE;
-    }
+  auth->buffer_outstanding = TRUE;
+}
 
-  _dbus_auth_do_work (auth);
-  
-  return TRUE;
+/**
+ * Returns a buffer with new data read into it.
+ *
+ * @param auth the auth conversation
+ * @param buffer the buffer being returned
+ * @param bytes_read number of new bytes added
+ */
+void
+_dbus_auth_return_buffer (DBusAuth               *auth,
+                          DBusString             *buffer,
+                          int                     bytes_read)
+{
+  _dbus_assert (buffer == &auth->incoming);
+  _dbus_assert (auth->buffer_outstanding);
+
+  auth->buffer_outstanding = FALSE;
 }
 
 /**
@@ -2034,22 +2040,32 @@ _dbus_auth_bytes_received (DBusAuth   *auth,
  * succeeded.
  *
  * @param auth the auth conversation
- * @param str string to append the unused bytes to
- * @returns #FALSE if not enough memory to return the bytes
+ * @param str return location for pointer to string of unused bytes
  */
-dbus_bool_t
-_dbus_auth_get_unused_bytes (DBusAuth   *auth,
-                             DBusString *str)
+void
+_dbus_auth_get_unused_bytes (DBusAuth           *auth,
+                             const DBusString **str)
 {
   if (!DBUS_AUTH_IN_END_STATE (auth))
-    return FALSE;
-  
-  if (!_dbus_string_move (&auth->incoming,
-                          0, str,
-                          _dbus_string_get_length (str)))
-    return FALSE;
+    return;
 
-  return TRUE;
+  *str = &auth->incoming;
+}
+
+
+/**
+ * Gets rid of unused bytes returned by _dbus_auth_get_unused_bytes()
+ * after we've gotten them and successfully moved them elsewhere.
+ *
+ * @param auth the auth conversation
+ */
+void
+_dbus_auth_delete_unused_bytes (DBusAuth *auth)
+{
+  if (!DBUS_AUTH_IN_END_STATE (auth))
+    return;
+
+  _dbus_string_set_length (&auth->incoming, 0);
 }
 
 /**
index 0339a4f..8309fe3 100644 (file)
@@ -42,34 +42,38 @@ typedef enum
   DBUS_AUTH_STATE_AUTHENTICATED
 } DBusAuthState;
 
-DBusAuth*     _dbus_auth_server_new        (void);
-DBusAuth*     _dbus_auth_client_new        (void);
-void          _dbus_auth_ref               (DBusAuth               *auth);
-void          _dbus_auth_unref             (DBusAuth               *auth);
-DBusAuthState _dbus_auth_do_work           (DBusAuth               *auth);
-dbus_bool_t   _dbus_auth_get_bytes_to_send (DBusAuth               *auth,
-                                            const DBusString      **str);
-void          _dbus_auth_bytes_sent        (DBusAuth               *auth,
-                                            int                     bytes_sent);
-dbus_bool_t   _dbus_auth_bytes_received    (DBusAuth               *auth,
-                                            const DBusString       *str);
-dbus_bool_t   _dbus_auth_get_unused_bytes  (DBusAuth               *auth,
-                                            DBusString             *str);
-dbus_bool_t   _dbus_auth_needs_encoding    (DBusAuth               *auth);
-dbus_bool_t   _dbus_auth_encode_data       (DBusAuth               *auth,
-                                            const DBusString       *plaintext,
-                                            DBusString             *encoded);
-dbus_bool_t   _dbus_auth_needs_decoding    (DBusAuth               *auth);
-dbus_bool_t   _dbus_auth_decode_data       (DBusAuth               *auth,
-                                            const DBusString       *encoded,
-                                            DBusString             *plaintext);
-void          _dbus_auth_set_credentials   (DBusAuth               *auth,
-                                            const DBusCredentials  *credentials);
+DBusAuth*     _dbus_auth_server_new          (void);
+DBusAuth*     _dbus_auth_client_new          (void);
+void          _dbus_auth_ref                 (DBusAuth               *auth);
+void          _dbus_auth_unref               (DBusAuth               *auth);
+DBusAuthState _dbus_auth_do_work             (DBusAuth               *auth);
+dbus_bool_t   _dbus_auth_get_bytes_to_send   (DBusAuth               *auth,
+                                              const DBusString      **str);
+void          _dbus_auth_bytes_sent          (DBusAuth               *auth,
+                                              int                     bytes_sent);
+void          _dbus_auth_get_buffer          (DBusAuth               *auth,
+                                              DBusString            **buffer);
+void          _dbus_auth_return_buffer       (DBusAuth               *auth,
+                                              DBusString             *buffer,
+                                              int                     bytes_read);
+void          _dbus_auth_get_unused_bytes    (DBusAuth               *auth,
+                                              const DBusString      **str);
+void          _dbus_auth_delete_unused_bytes (DBusAuth               *auth);
+dbus_bool_t   _dbus_auth_needs_encoding      (DBusAuth               *auth);
+dbus_bool_t   _dbus_auth_encode_data         (DBusAuth               *auth,
+                                              const DBusString       *plaintext,
+                                              DBusString             *encoded);
+dbus_bool_t   _dbus_auth_needs_decoding      (DBusAuth               *auth);
+dbus_bool_t   _dbus_auth_decode_data         (DBusAuth               *auth,
+                                              const DBusString       *encoded,
+                                              DBusString             *plaintext);
+void          _dbus_auth_set_credentials     (DBusAuth               *auth,
+                                              const DBusCredentials  *credentials);
+void          _dbus_auth_get_identity        (DBusAuth               *auth,
+                                              DBusCredentials        *credentials);
+dbus_bool_t   _dbus_auth_set_context         (DBusAuth               *auth,
+                                              const DBusString       *context);
 
-void          _dbus_auth_get_identity      (DBusAuth               *auth,
-                                            DBusCredentials        *credentials);
-dbus_bool_t   _dbus_auth_set_context       (DBusAuth               *auth,
-                                            const DBusString       *context);
 
 DBUS_END_DECLS;
 
index 7f9423a..d6ee104 100644 (file)
@@ -1166,7 +1166,7 @@ dbus_connection_send (DBusConnection *connection,
     }
 }
 
-static void
+static dbus_bool_t
 reply_handler_timeout (void *data)
 {
   DBusConnection *connection;
@@ -1187,6 +1187,8 @@ reply_handler_timeout (void *data)
   reply_handler_data->timeout_added = FALSE;
   
   dbus_mutex_unlock (connection->mutex);
+
+  return TRUE;
 }
 
 static void
@@ -2171,21 +2173,33 @@ dbus_connection_set_wakeup_main_function (DBusConnection            *connection,
  * is ready for reading or writing, or has an exception such
  * as a hangup.
  *
+ * If this function returns #FALSE, then the file descriptor may still
+ * be ready for reading or writing, but more memory is needed in order
+ * to do the reading or writing. If you ignore the #FALSE return, your
+ * application may spin in a busy loop on the file descriptor until
+ * memory becomes available, but nothing more catastrophic should
+ * happen.
+ *
  * @param connection the connection.
  * @param watch the watch.
  * @param condition the current condition of the file descriptors being watched.
+ * @returns #FALSE if the IO condition may not have been fully handled due to lack of memory
  */
-void
+dbus_bool_t
 dbus_connection_handle_watch (DBusConnection              *connection,
                               DBusWatch                   *watch,
                               unsigned int                 condition)
 {
+  dbus_bool_t retval;
+  
   dbus_mutex_lock (connection->mutex);
   _dbus_connection_acquire_io_path (connection, -1);
-  _dbus_transport_handle_watch (connection->transport,
-                               watch, condition);
+  retval = _dbus_transport_handle_watch (connection->transport,
+                                         watch, condition);
   _dbus_connection_release_io_path (connection);
   dbus_mutex_unlock (connection->mutex);
+
+  return retval;
 }
 
 /**
index b4e6007..9b135a5 100644 (file)
@@ -120,7 +120,7 @@ void               dbus_connection_set_wakeup_main_function  (DBusConnection
                                                               DBusWakeupMainFunction      wakeup_main_function,
                                                               void                       *data,
                                                               DBusFreeFunction            free_data_function);
-void               dbus_connection_handle_watch              (DBusConnection             *connection,
+dbus_bool_t        dbus_connection_handle_watch              (DBusConnection             *connection,
                                                               DBusWatch                  *watch,
                                                               unsigned int                condition);
 
@@ -138,7 +138,7 @@ void*       dbus_timeout_get_data     (DBusTimeout      *timeout);
 void        dbus_timeout_set_data     (DBusTimeout      *timeout,
                                        void             *data,
                                        DBusFreeFunction  free_data_function);
-void        dbus_timeout_handle       (DBusTimeout      *timeout);
+dbus_bool_t dbus_timeout_handle       (DBusTimeout      *timeout);
 dbus_bool_t dbus_timeout_get_enabled  (DBusTimeout      *timeout);
 
 /* Handlers */
index 8f57ae8..46e78dd 100644 (file)
@@ -73,12 +73,13 @@ debug_finalize (DBusServer *server)
   dbus_free (server);
 }
 
-static void
+static dbus_bool_t
 debug_handle_watch (DBusServer  *server,
                    DBusWatch   *watch,
                    unsigned int flags)
 {
-  
+
+  return TRUE;
 }
 
 static void
@@ -211,6 +212,7 @@ _dbus_transport_debug_pipe_new (const char     *server_name,
     {
       _dbus_close (client_fd, NULL);
       _dbus_close (server_fd, NULL);
+      dbus_set_result (result, DBUS_RESULT_NO_MEMORY);
       return NULL;
     }
 
@@ -222,6 +224,7 @@ _dbus_transport_debug_pipe_new (const char     *server_name,
     {
       _dbus_transport_unref (client_transport);
       _dbus_close (server_fd, NULL);
+      dbus_set_result (result, DBUS_RESULT_NO_MEMORY);
       return NULL;
     }
 
@@ -234,6 +237,7 @@ _dbus_transport_debug_pipe_new (const char     *server_name,
   if (connection == NULL)
     {
       _dbus_transport_unref (client_transport);
+      dbus_set_result (result, DBUS_RESULT_NO_MEMORY);
       return NULL;
     }
 
index b1318e3..3b7e78d 100644 (file)
@@ -71,11 +71,12 @@ debug_finalize (DBusServer *server)
 {
 }
 
-static void
+static dbus_bool_t
 debug_handle_watch (DBusServer  *server,
                    DBusWatch   *watch,
                    unsigned int flags)
 {
+  return TRUE;
 }
 
 static void
@@ -184,7 +185,7 @@ typedef struct
   DBusTimeout *timeout;
 } ServerAndTransport;
 
-static void
+static dbus_bool_t
 handle_new_client (void *data)
 {
   ServerAndTransport *st = data;
@@ -196,13 +197,13 @@ handle_new_client (void *data)
   
   transport = _dbus_transport_debug_server_new (st->transport);
   if (transport == NULL)
-    return;
+    return FALSE;
 
   connection = _dbus_connection_new_for_transport (transport);
   _dbus_transport_unref (transport);
 
   if (connection == NULL)
-    return;
+    return FALSE;
 
   /* See if someone wants to handle this new connection,
    * self-referencing for paranoia
@@ -223,6 +224,8 @@ handle_new_client (void *data)
 
   /* killing timeout frees both "st" and "timeout" */
   _dbus_timeout_unref (st->timeout);
+
+  return TRUE;
 }
 
 /**
index bbedeea..d47215b 100644 (file)
@@ -36,17 +36,17 @@ typedef struct DBusServerVTable DBusServerVTable;
 
 struct DBusServerVTable
 {
-  void (* finalize)      (DBusServer *server);
+  void        (* finalize)      (DBusServer *server);
   /**< The finalize method must free the server. */
 
-  void (* handle_watch)  (DBusServer  *server,
-                          DBusWatch   *watch,
-                          unsigned int flags);
+  dbus_bool_t (* handle_watch)  (DBusServer  *server,
+                                 DBusWatch   *watch,
+                                 unsigned int flags);
   /**< The handle_watch method handles reading/writing
    * data as indicated by the flags.
    */
   
-  void (* disconnect)    (DBusServer *server);
+  void        (* disconnect)    (DBusServer *server);
   /**< Disconnect this server. */
 };
 
index a181a92..88cc9ed 100644 (file)
@@ -70,7 +70,8 @@ unix_finalize (DBusServer *server)
  * us to drop the last ref to the connection before
  * disconnecting it. That is invalid.
  */
-static void
+/* Return value is just for memory, not other failures. */
+static dbus_bool_t
 handle_new_client_fd (DBusServer *server,
                       int         client_fd)
 {
@@ -80,13 +81,13 @@ handle_new_client_fd (DBusServer *server,
   _dbus_verbose ("Creating new client connection with fd %d\n", client_fd);
           
   if (!_dbus_set_fd_nonblocking (client_fd, NULL))
-    return;
+    return TRUE;
   
   transport = _dbus_transport_new_for_fd (client_fd, TRUE);
   if (transport == NULL)
     {
       close (client_fd);
-      return;
+      return FALSE;
     }
 
   /* note that client_fd is now owned by the transport, and will be
@@ -97,7 +98,7 @@ handle_new_client_fd (DBusServer *server,
   _dbus_transport_unref (transport);
   
   if (connection == NULL)
-    return;
+    return FALSE;
 
   _dbus_connection_set_connection_counter (connection,
                                            server->connection_counter);
@@ -116,9 +117,11 @@ handle_new_client_fd (DBusServer *server,
   
   /* If no one grabbed a reference, the connection will die. */
   dbus_connection_unref (connection);
+
+  return TRUE;
 }
 
-static void
+static dbus_bool_t
 unix_handle_watch (DBusServer  *server,
                    DBusWatch   *watch,
                    unsigned int flags)
@@ -151,7 +154,9 @@ unix_handle_watch (DBusServer  *server,
       else
         {
          _dbus_fd_set_close_on_exec (client_fd);         
-          handle_new_client_fd (server, client_fd);
+
+          if (!handle_new_client_fd (server, client_fd))
+            _dbus_verbose ("Rejected client connection due to lack of memory\n");
         }
     }
 
@@ -160,6 +165,8 @@ unix_handle_watch (DBusServer  *server,
 
   if (flags & DBUS_WATCH_HANGUP)
     _dbus_verbose ("Hangup on server listening socket\n");
+
+  return TRUE;
 }
   
 static void
index 79ed7ed..ba48cd9 100644 (file)
@@ -498,12 +498,19 @@ dbus_server_set_timeout_functions (DBusServer                *server,
  * Called to notify the server when a previously-added watch
  * is ready for reading or writing, or has an exception such
  * as a hangup.
+ * 
+ * If this function returns #FALSE, then the file descriptor may still
+ * be ready for reading or writing, but more memory is needed in order
+ * to do the reading or writing. If you ignore the #FALSE return, your
+ * application may spin in a busy loop on the file descriptor until
+ * memory becomes available, but nothing more catastrophic should
+ * happen.
  *
  * @param server the server.
  * @param watch the watch.
  * @param condition the current condition of the file descriptors being watched.
  */
-void
+dbus_bool_t
 dbus_server_handle_watch (DBusServer              *server,
                           DBusWatch               *watch,
                           unsigned int             condition)
@@ -512,7 +519,7 @@ dbus_server_handle_watch (DBusServer              *server,
 
   _dbus_watch_sanitize_condition (watch, &condition);
   
-  (* server->vtable->handle_watch) (server, watch, condition);
+  return (* server->vtable->handle_watch) (server, watch, condition);
 }
 
 /**
index 589237f..7563244 100644 (file)
@@ -61,7 +61,7 @@ dbus_bool_t dbus_server_set_timeout_functions       (DBusServer                *
                                                      DBusTimeoutToggledFunction toggled_function,
                                                      void                      *data,
                                                      DBusFreeFunction           free_data_function);
-void        dbus_server_handle_watch                (DBusServer                *server,
+dbus_bool_t dbus_server_handle_watch                (DBusServer                *server,
                                                      DBusWatch                 *watch,
                                                      unsigned int               condition);
 void        dbus_server_set_max_connections         (DBusServer                *server,
index e6e0b27..8abcc5f 100644 (file)
@@ -130,7 +130,8 @@ _dbus_getenv (const char *varname)
  * the data it reads to the DBusString buffer. It appends
  * up to the given count, and returns the same value
  * and same errno as read(). The only exception is that
- * _dbus_read() handles EINTR for you.
+ * _dbus_read() handles EINTR for you. _dbus_read() can
+ * return ENOMEM, even though regular UNIX read doesn't.
  *
  * @param fd the file descriptor to read from
  * @param buffer the buffer to append data to
index 9825872..a77363b 100644 (file)
@@ -405,12 +405,19 @@ dbus_timeout_set_data (DBusTimeout      *timeout,
  * This function should be called when the timeout
  * occurs.
  *
+ * If this function returns #FALSE, then there wasn't
+ * enough memory to handle the timeout. Typically just
+ * letting the timeout fire again next time it naturally
+ * times out is an adequate response to that problem,
+ * but you could try to do more if you wanted.
+ *
  * @param timeout the DBusTimeout object.
+ * @returns #FALSE if there wasn't enough memory 
  */
-void
+dbus_bool_t
 dbus_timeout_handle (DBusTimeout *timeout)
 {
-  (* timeout->handler) (timeout->handler_data);
+  return (* timeout->handler) (timeout->handler_data);
 }
 
 
index 0ff5dc5..2f136ae 100644 (file)
@@ -32,7 +32,7 @@ typedef struct DBusTimeoutList DBusTimeoutList;
 
 /* Public methods on DBusTimeout are in dbus-connection.h */
 
-typedef void (* DBusTimeoutHandler) (void *data);
+typedef dbus_bool_t (* DBusTimeoutHandler) (void *data);
 
 DBusTimeout* _dbus_timeout_new   (int                 interval,
                                  DBusTimeoutHandler  handler,
index a7db3a6..d477339 100644 (file)
 #define DEFAULT_INTERVAL 1
 
 /**
- * Hack due to lack of OOM handling in a couple places
+ * Hack due to lack of OOM handling in a couple places.
+ * Need to alloc timeout permanently and enabled/disable so
+ * that check_timeout won't fail in messages_pending
  */
 #define WAIT_FOR_MEMORY() _dbus_sleep_milliseconds (250)
 
-static void check_timeout (DBusTransport *transport);
+static dbus_bool_t check_timeout (DBusTransport *transport);
 
 /**
  * Opaque object representing a debug transport.
@@ -123,18 +125,21 @@ move_messages (DBusTransport *transport)
   return TRUE;
 }
 
-static void
+static dbus_bool_t
 timeout_handler (void *data)
 {
   DBusTransport *transport = data;
   
-  while (!move_messages (transport))
-    WAIT_FOR_MEMORY ();
+  if (!move_messages (transport))
+    return FALSE;
+
+  if (!check_timeout (transport))
+    return FALSE;
 
-  check_timeout (transport);
+  return TRUE;
 }
 
-static void
+static dbus_bool_t
 check_timeout (DBusTransport *transport)
 {
   DBusTransportDebug *debug_transport = (DBusTransportDebug*) transport;
@@ -150,9 +155,9 @@ check_timeout (DBusTransport *transport)
           /* FIXME this can be fixed now, by enabling/disabling
            * the timeout instead of adding it here
            */
-          while (!_dbus_connection_add_timeout (transport->connection,
-                                                debug_transport->timeout))
-            WAIT_FOR_MEMORY ();
+          if (!_dbus_connection_add_timeout (transport->connection,
+                                             debug_transport->timeout))
+            return FALSE;
           debug_transport->timeout_added = TRUE;
         }
     }
@@ -165,6 +170,8 @@ check_timeout (DBusTransport *transport)
           debug_transport->timeout_added = FALSE;
         }
     }
+
+  return TRUE;
 }
 
 static void
@@ -189,11 +196,12 @@ debug_finalize (DBusTransport *transport)
   dbus_free (transport);
 }
 
-static void
+static dbus_bool_t
 debug_handle_watch (DBusTransport *transport,
                    DBusWatch     *watch,
                    unsigned int   flags)
 {
+  return TRUE;
 }
 
 static void
@@ -204,7 +212,8 @@ debug_disconnect (DBusTransport *transport)
 static dbus_bool_t
 debug_connection_set (DBusTransport *transport)
 {
-  check_timeout (transport);
+  if (!check_timeout (transport))
+    return FALSE;
   return TRUE;
 }
 
@@ -212,7 +221,8 @@ static void
 debug_messages_pending (DBusTransport *transport,
                        int            messages_pending)
 {
-  check_timeout (transport);
+  while (!check_timeout (transport))
+    WAIT_FOR_MEMORY ();
 }
 
 static void
index 0f6c45e..8ee605c 100644 (file)
@@ -36,36 +36,36 @@ typedef struct DBusTransportVTable DBusTransportVTable;
 
 struct DBusTransportVTable
 {
-  void (* finalize)           (DBusTransport *transport);
+  void        (* finalize)              (DBusTransport *transport);
   /**< The finalize method must free the transport. */
 
-  void (* handle_watch)       (DBusTransport *transport,
-                               DBusWatch     *watch,
-                               unsigned int   flags);
+  dbus_bool_t (* handle_watch)          (DBusTransport *transport,
+                                         DBusWatch     *watch,
+                                         unsigned int   flags);
   /**< The handle_watch method handles reading/writing
    * data as indicated by the flags.
    */
 
-  void (* disconnect)         (DBusTransport *transport);
+  void        (* disconnect)            (DBusTransport *transport);
   /**< Disconnect this transport. */
 
-  dbus_bool_t (* connection_set)     (DBusTransport *transport);
+  dbus_bool_t (* connection_set)        (DBusTransport *transport);
   /**< Called when transport->connection has been filled in */
 
-  void (* messages_pending)   (DBusTransport *transport,
-                               int            queue_length);
+  void        (* messages_pending)      (DBusTransport *transport,
+                                         int            queue_length);
   /**< Called when the outgoing message queue goes from empty
    * to non-empty or vice versa.
    */
 
-  void (* do_iteration)       (DBusTransport *transport,
-                               unsigned int   flags,
-                               int            timeout_milliseconds);
+  void        (* do_iteration)          (DBusTransport *transport,
+                                         unsigned int   flags,
+                                         int            timeout_milliseconds);
   /**< Called to do a single "iteration" (block on select/poll
    * followed by reading or writing data).
    */
 
-  void (* live_messages_changed) (DBusTransport *transport);
+  void        (* live_messages_changed) (DBusTransport *transport);
   /**< Outstanding messages counter changed */
 };
 
index 9ea5ce1..5cbbb1f 100644 (file)
@@ -61,9 +61,12 @@ struct DBusTransportUnix
                                          *   outgoing message that have
                                          *   been written.
                                          */
-  DBusString encoded_message;           /**< Encoded version of current
+  DBusString encoded_outgoing;          /**< Encoded version of current
                                          *   outgoing message.
                                          */
+  DBusString encoded_incoming;          /**< Encoded version of current
+                                         *   incoming data.
+                                         */
 };
 
 static void
@@ -99,7 +102,8 @@ unix_finalize (DBusTransport *transport)
   
   free_watches (transport);
 
-  _dbus_string_free (&unix_transport->encoded_message);
+  _dbus_string_free (&unix_transport->encoded_outgoing);
+  _dbus_string_free (&unix_transport->encoded_incoming);
   
   _dbus_transport_finalize_base (transport);
 
@@ -180,51 +184,39 @@ do_io_error (DBusTransport *transport)
 
 /* return value is whether we successfully read any new data. */
 static dbus_bool_t
-read_data_into_auth (DBusTransport *transport)
+read_data_into_auth (DBusTransport *transport,
+                     dbus_bool_t   *oom)
 {
   DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport;
-  DBusString buffer;
+  DBusString *buffer;
   int bytes_read;
   
-  if (!_dbus_string_init (&buffer, _DBUS_INT_MAX))
-    {
-      /* just disconnect if we don't have memory
-       * to do an authentication
-       */
-      _dbus_verbose ("No memory for authentication\n");
-      do_io_error (transport);
-      return FALSE;
-    }
+  *oom = FALSE;
+
+  _dbus_auth_get_buffer (transport->auth, &buffer);
   
   bytes_read = _dbus_read (unix_transport->fd,
-                           &buffer, unix_transport->max_bytes_read_per_iteration);
+                           buffer, unix_transport->max_bytes_read_per_iteration);
+
+  _dbus_auth_return_buffer (transport->auth, buffer,
+                            bytes_read > 0 ? bytes_read : 0);
 
   if (bytes_read > 0)
     {
       _dbus_verbose (" read %d bytes in auth phase\n", bytes_read);
-      
-      if (_dbus_auth_bytes_received (transport->auth,
-                                     &buffer))
-        {
-          _dbus_string_free (&buffer);
-          return TRUE; /* We did read some data! woo! */
-        }
-      else
-        {
-          /* just disconnect if we don't have memory to do an
-           * authentication, don't fool with trying to save the buffer
-           * and who knows what.
-           */
-          _dbus_verbose ("No memory for authentication\n");
-          do_io_error (transport);
-        }
+
+      return TRUE;
     }
   else if (bytes_read < 0)
     {
       /* EINTR already handled for us */
-      
-      if (errno == EAGAIN ||
-          errno == EWOULDBLOCK)
+
+      if (errno == ENOMEM)
+        {
+          *oom = TRUE;
+        }
+      else if (errno == EAGAIN ||
+               errno == EWOULDBLOCK)
         ; /* do nothing, just return FALSE below */
       else
         {
@@ -232,15 +224,18 @@ read_data_into_auth (DBusTransport *transport)
                          _dbus_strerror (errno));
           do_io_error (transport);
         }
+
+      return FALSE;
     }
-  else if (bytes_read == 0)
+  else
     {
+      _dbus_assert (bytes_read == 0);
+      
       _dbus_verbose ("Disconnected from remote app\n");
-      do_io_error (transport);      
+      do_io_error (transport);
+
+      return FALSE;
     }
-  
-  _dbus_string_free (&buffer);
-  return FALSE;
 }
 
 /* Return value is whether we successfully wrote any bytes */
@@ -283,98 +278,6 @@ write_data_from_auth (DBusTransport *transport)
 }
 
 static void
-recover_unused_bytes (DBusTransport *transport)
-{
-  
-  if (_dbus_auth_needs_decoding (transport->auth))
-    {
-      DBusString plaintext;
-      DBusString encoded;
-      DBusString *buffer;
-      int orig_len;
-      
-      if (!_dbus_string_init (&plaintext, _DBUS_INT_MAX))
-        goto nomem;
-
-      if (!_dbus_string_init (&encoded, _DBUS_INT_MAX))
-        {
-          _dbus_string_free (&plaintext);
-          goto nomem;
-        }
-      
-      if (!_dbus_auth_get_unused_bytes (transport->auth,
-                                        &encoded))
-        {
-          _dbus_string_free (&plaintext);
-          _dbus_string_free (&encoded);
-          goto nomem;
-        }
-      
-      if (!_dbus_auth_decode_data (transport->auth,
-                                   &encoded, &plaintext))
-        {
-          _dbus_string_free (&plaintext);
-          _dbus_string_free (&encoded);
-          goto nomem;
-        }
-      
-      _dbus_message_loader_get_buffer (transport->loader,
-                                       &buffer);
-      
-      orig_len = _dbus_string_get_length (buffer);
-
-      if (!_dbus_string_move (&plaintext, 0, buffer,
-                              orig_len))
-        {
-          _dbus_string_free (&plaintext);
-          _dbus_string_free (&encoded);
-          goto nomem;
-        }
-      
-      _dbus_verbose (" %d unused bytes sent to message loader\n", 
-                     _dbus_string_get_length (buffer) -
-                     orig_len);
-      
-      _dbus_message_loader_return_buffer (transport->loader,
-                                          buffer,
-                                          _dbus_string_get_length (buffer) -
-                                          orig_len);
-
-      _dbus_string_free (&plaintext);
-      _dbus_string_free (&encoded);
-    }
-  else
-    {
-      DBusString *buffer;
-      int orig_len;
-
-      _dbus_message_loader_get_buffer (transport->loader,
-                                       &buffer);
-                
-      orig_len = _dbus_string_get_length (buffer);
-                
-      if (!_dbus_auth_get_unused_bytes (transport->auth,
-                                        buffer))
-        goto nomem;
-                
-      _dbus_verbose (" %d unused bytes sent to message loader\n", 
-                     _dbus_string_get_length (buffer) -
-                     orig_len);
-      
-      _dbus_message_loader_return_buffer (transport->loader,
-                                          buffer,
-                                          _dbus_string_get_length (buffer) -
-                                          orig_len);
-    }
-  
-  return;
-
- nomem:
-  _dbus_verbose ("Not enough memory to transfer unused bytes from auth conversation\n");
-  do_io_error (transport);
-}
-
-static void
 exchange_credentials (DBusTransport *transport,
                       dbus_bool_t    do_reading,
                       dbus_bool_t    do_writing)
@@ -418,16 +321,20 @@ exchange_credentials (DBusTransport *transport,
     }
 }
 
-static void
+static dbus_bool_t
 do_authentication (DBusTransport *transport,
                    dbus_bool_t    do_reading,
                    dbus_bool_t    do_writing)
-{  
+{
+  dbus_bool_t oom;
+  
   _dbus_transport_ref (transport);
+
+  oom = FALSE;
   
   while (!_dbus_transport_get_is_authenticated (transport) &&
          _dbus_transport_get_is_connected (transport))
-    {
+    {      
       exchange_credentials (transport, do_reading, do_writing);
       
       if (transport->send_credentials_pending ||
@@ -443,14 +350,14 @@ do_authentication (DBusTransport *transport,
         {
         case DBUS_AUTH_STATE_WAITING_FOR_INPUT:
           _dbus_verbose (" auth state: waiting for input\n");
-          if (!do_reading || !read_data_into_auth (transport))
+          if (!do_reading || !read_data_into_auth (transport, &oom))
             goto out;
           break;
       
         case DBUS_AUTH_STATE_WAITING_FOR_MEMORY:
-          /* Screw it, just disconnect */
           _dbus_verbose (" auth state: waiting for memory\n");
-          do_io_error (transport);
+          oom = TRUE;
+          goto out;
           break;
       
         case DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND:
@@ -466,7 +373,8 @@ do_authentication (DBusTransport *transport,
       
         case DBUS_AUTH_STATE_AUTHENTICATED_WITH_UNUSED_BYTES:
           _dbus_verbose (" auth state: auth with unused bytes\n");
-          recover_unused_bytes (transport);
+          /* We'll recover the unused bytes in dbus-transport.c */
+          goto out;
           break;
           
         case DBUS_AUTH_STATE_AUTHENTICATED:
@@ -474,26 +382,34 @@ do_authentication (DBusTransport *transport,
           break;
         }
     }
-
+  
  out:
   check_read_watch (transport);
   check_write_watch (transport);
   _dbus_transport_unref (transport);
+
+  if (oom)
+    return FALSE;
+  else
+    return TRUE;
 }
 
-static void
+/* returns false on oom */
+static dbus_bool_t
 do_writing (DBusTransport *transport)
 {
   int total;
   DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport;
-
+  dbus_bool_t oom;
+  
   /* No messages without authentication! */
   if (!_dbus_transport_get_is_authenticated (transport))
-    return;
+    return TRUE;
 
   if (transport->disconnected)
-    return;
-  
+    return TRUE;
+
+  oom = FALSE;
   total = 0;
 
   while (!transport->disconnected &&
@@ -513,9 +429,9 @@ do_writing (DBusTransport *transport)
           goto out;
         }
 
-      if (unix_transport->write_watch == NULL)
+      if (!dbus_watch_get_enabled (unix_transport->write_watch))
         {
-          _dbus_verbose ("write watch removed, not writing more stuff\n");
+          _dbus_verbose ("write watch disabled, not writing more stuff\n");
           goto out;
         }
       
@@ -535,21 +451,25 @@ do_writing (DBusTransport *transport)
 
       if (_dbus_auth_needs_encoding (transport->auth))
         {
-          if (_dbus_string_get_length (&unix_transport->encoded_message) == 0)
+          if (_dbus_string_get_length (&unix_transport->encoded_outgoing) == 0)
             {
               if (!_dbus_auth_encode_data (transport->auth,
-                                           header, &unix_transport->encoded_message))
-                goto out;
+                                           header, &unix_transport->encoded_outgoing))
+                {
+                  oom = TRUE;
+                  goto out;
+                }
               
               if (!_dbus_auth_encode_data (transport->auth,
-                                           body, &unix_transport->encoded_message))
+                                           body, &unix_transport->encoded_outgoing))
                 {
-                  _dbus_string_set_length (&unix_transport->encoded_message, 0);
+                  _dbus_string_set_length (&unix_transport->encoded_outgoing, 0);
+                  oom = TRUE;
                   goto out;
                 }
             }
           
-          total_bytes_to_write = _dbus_string_get_length (&unix_transport->encoded_message);
+          total_bytes_to_write = _dbus_string_get_length (&unix_transport->encoded_outgoing);
 
 #if 0
           _dbus_verbose ("encoded message is %d bytes\n",
@@ -558,7 +478,7 @@ do_writing (DBusTransport *transport)
           
           bytes_written =
             _dbus_write (unix_transport->fd,
-                         &unix_transport->encoded_message,
+                         &unix_transport->encoded_outgoing,
                          unix_transport->message_bytes_written,
                          total_bytes_to_write - unix_transport->message_bytes_written);
         }
@@ -621,7 +541,7 @@ do_writing (DBusTransport *transport)
           if (unix_transport->message_bytes_written == total_bytes_to_write)
             {
               unix_transport->message_bytes_written = 0;
-              _dbus_string_set_length (&unix_transport->encoded_message, 0);
+              _dbus_string_set_length (&unix_transport->encoded_outgoing, 0);
 
               _dbus_connection_message_sent (transport->connection,
                                              message);
@@ -630,20 +550,27 @@ do_writing (DBusTransport *transport)
     }
 
  out:
-  return; /* I think some C compilers require a statement after a label */
+  if (oom)
+    return FALSE;
+  else
+    return TRUE;
 }
 
-static void
+/* returns false on out-of-memory */
+static dbus_bool_t
 do_reading (DBusTransport *transport)
 {
   DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport;
   DBusString *buffer;
   int bytes_read;
   int total;
+  dbus_bool_t oom;
 
   /* No messages without authentication! */
   if (!_dbus_transport_get_is_authenticated (transport))
-    return;
+    return TRUE;
+
+  oom = FALSE;
   
   total = 0;
 
@@ -651,8 +578,8 @@ do_reading (DBusTransport *transport)
 
   /* See if we've exceeded max messages and need to disable reading */
   check_read_watch (transport);
-  if (unix_transport->read_watch == NULL)
-    return;
+  if (!dbus_watch_get_enabled (unix_transport->read_watch))
+    return TRUE;
   
   if (total > unix_transport->max_bytes_read_per_iteration)
     {
@@ -666,15 +593,16 @@ do_reading (DBusTransport *transport)
 
   if (_dbus_auth_needs_decoding (transport->auth))
     {
-      DBusString encoded;
-
-      if (!_dbus_string_init (&encoded, _DBUS_INT_MAX))
-        goto out; /* not enough memory for the moment */
-
-      bytes_read = _dbus_read (unix_transport->fd,
-                               &encoded,
-                               unix_transport->max_bytes_read_per_iteration);
+      if (_dbus_string_get_length (&unix_transport->encoded_incoming) > 0)
+        bytes_read = _dbus_string_get_length (&unix_transport->encoded_incoming);
+      else
+        bytes_read = _dbus_read (unix_transport->fd,
+                                 &unix_transport->encoded_incoming,
+                                 unix_transport->max_bytes_read_per_iteration);
 
+      _dbus_assert (_dbus_string_get_length (&unix_transport->encoded_incoming) ==
+                    bytes_read);
+      
       if (bytes_read > 0)
         {
           int orig_len;
@@ -685,24 +613,20 @@ do_reading (DBusTransport *transport)
           orig_len = _dbus_string_get_length (buffer);
           
           if (!_dbus_auth_decode_data (transport->auth,
-                                       &encoded, buffer))
+                                       &unix_transport->encoded_incoming,
+                                       buffer))
             {
-              /* FIXME argh, we are really fucked here - nowhere to
-               * put "encoded" while we wait for more memory.  Just
-               * screw it for now and disconnect.  The failure may be
-               * due to badly-encoded data instead of lack of memory
-               * anyhow.
-               */
-              _dbus_verbose ("Disconnected from remote app due to failure decoding data\n");
-              do_io_error (transport);
+              _dbus_verbose ("Out of memory decoding incoming data\n");
+              oom = TRUE;
+              goto out;
             }
 
           _dbus_message_loader_return_buffer (transport->loader,
                                               buffer,
                                               _dbus_string_get_length (buffer) - orig_len);
-        }
 
-      _dbus_string_free (&encoded);
+          _dbus_string_set_length (&unix_transport->encoded_incoming, 0);
+        }
     }
   else
     {
@@ -720,9 +644,15 @@ do_reading (DBusTransport *transport)
   if (bytes_read < 0)
     {
       /* EINTR already handled for us */
-      
-      if (errno == EAGAIN ||
-          errno == EWOULDBLOCK)
+
+      if (errno == ENOMEM)
+        {
+          _dbus_verbose ("Out of memory in read()/do_reading()\n");
+          oom = TRUE;
+          goto out;
+        }
+      else if (errno == EAGAIN ||
+               errno == EWOULDBLOCK)
         goto out;
       else
         {
@@ -745,7 +675,10 @@ do_reading (DBusTransport *transport)
       total += bytes_read;      
 
       if (_dbus_transport_queue_messages (transport) == DBUS_DISPATCH_NEED_MEMORY)
-        goto out;
+        {
+          oom = TRUE;
+          goto out;
+        }
       
       /* Try reading more data until we get EAGAIN and return, or
        * exceed max bytes per iteration.  If in blocking mode of
@@ -755,10 +688,13 @@ do_reading (DBusTransport *transport)
     }
 
  out:
-  return; /* I think some C compilers require a statement after a label */
+  if (oom)
+    return FALSE;
+  else
+    return TRUE;
 }
 
-static void
+static dbus_bool_t
 unix_handle_watch (DBusTransport *transport,
                    DBusWatch     *watch,
                    unsigned int   flags)
@@ -771,7 +707,7 @@ unix_handle_watch (DBusTransport *transport,
   if (flags & (DBUS_WATCH_HANGUP | DBUS_WATCH_ERROR))
     {
       _dbus_transport_disconnect (transport);
-      return;
+      return TRUE;
     }
   
   if (watch == unix_transport->read_watch &&
@@ -780,8 +716,11 @@ unix_handle_watch (DBusTransport *transport,
 #if 0
       _dbus_verbose ("handling read watch\n");
 #endif
-      do_authentication (transport, TRUE, FALSE);
-      do_reading (transport);
+      if (!do_authentication (transport, TRUE, FALSE))
+        return FALSE;
+      
+      if (!do_reading (transport))
+        return FALSE;
     }
   else if (watch == unix_transport->write_watch &&
            (flags & DBUS_WATCH_WRITABLE))
@@ -789,9 +728,14 @@ unix_handle_watch (DBusTransport *transport,
 #if 0
       _dbus_verbose ("handling write watch\n");
 #endif
-      do_authentication (transport, FALSE, TRUE);
-      do_writing (transport);
+      if (!do_authentication (transport, FALSE, TRUE))
+        return FALSE;
+      
+      if (!do_writing (transport))
+        return FALSE;
     }
+
+  return TRUE;
 }
 
 static void
@@ -1031,26 +975,30 @@ _dbus_transport_new_for_fd (int         fd,
   if (unix_transport == NULL)
     return NULL;
 
-  if (!_dbus_string_init (&unix_transport->encoded_message,
+  if (!_dbus_string_init (&unix_transport->encoded_outgoing,
                           _DBUS_INT_MAX))
     goto failed_0;
 
+  if (!_dbus_string_init (&unix_transport->encoded_incoming,
+                          _DBUS_INT_MAX))
+    goto failed_1;
+  
   unix_transport->write_watch = _dbus_watch_new (fd,
                                                  DBUS_WATCH_WRITABLE,
                                                  FALSE);
   if (unix_transport->write_watch == NULL)
-    goto failed_1;
+    goto failed_2;
   
   unix_transport->read_watch = _dbus_watch_new (fd,
                                                 DBUS_WATCH_READABLE,
                                                 FALSE);
   if (unix_transport->read_watch == NULL)
-    goto failed_2;
+    goto failed_3;
   
   if (!_dbus_transport_init_base (&unix_transport->base,
                                   &unix_vtable,
                                   server))
-    goto failed_3;
+    goto failed_4;
   
   unix_transport->fd = fd;
   unix_transport->message_bytes_written = 0;
@@ -1061,12 +1009,14 @@ _dbus_transport_new_for_fd (int         fd,
   
   return (DBusTransport*) unix_transport;
 
- failed_3:
+ failed_4:
   _dbus_watch_unref (unix_transport->read_watch);
- failed_2:
+ failed_3:
   _dbus_watch_unref (unix_transport->write_watch);
+ failed_2:
+  _dbus_string_free (&unix_transport->encoded_incoming);
  failed_1:
-  _dbus_string_free (&unix_transport->encoded_message);  
+  _dbus_string_free (&unix_transport->encoded_outgoing);
  failed_0:
   dbus_free (unix_transport);
   return NULL;
index b2355ea..8087f5b 100644 (file)
@@ -265,6 +265,8 @@ _dbus_transport_open (const char     *address,
 void
 _dbus_transport_ref (DBusTransport *transport)
 {
+  _dbus_assert (transport->refcount > 0);
+  
   transport->refcount += 1;
 }
 
@@ -306,14 +308,12 @@ _dbus_transport_disconnect (DBusTransport *transport)
   if (transport->disconnected)
     return;
 
-  _dbus_transport_ref (transport);
   (* transport->vtable->disconnect) (transport);
   
   transport->disconnected = TRUE;
 
-  _dbus_connection_notify_disconnected (transport->connection);
-  
-  _dbus_transport_unref (transport);
+  if (transport->connection)
+    _dbus_connection_notify_disconnected (transport->connection);
 }
 
 /**
@@ -394,30 +394,35 @@ _dbus_transport_get_is_authenticated (DBusTransport *transport)
  * @param transport the transport.
  * @param watch the watch.
  * @param condition the current state of the watched file descriptor.
+ * @returns #FALSE if not enough memory to fully handle the watch
  */
-void
+dbus_bool_t
 _dbus_transport_handle_watch (DBusTransport           *transport,
                               DBusWatch               *watch,
                               unsigned int             condition)
 {
+  dbus_bool_t retval;
+  
   _dbus_assert (transport->vtable->handle_watch != NULL);
 
   if (transport->disconnected)
-    return;
+    return TRUE;
 
   if (dbus_watch_get_fd (watch) < 0)
     {
       _dbus_warn ("Tried to handle an invalidated watch; this watch should have been removed\n");
-      return;
+      return TRUE;
     }
   
   _dbus_watch_sanitize_condition (watch, &condition);
 
   _dbus_transport_ref (transport);
   _dbus_watch_ref (watch);
-  (* transport->vtable->handle_watch) (transport, watch, condition);
+  retval = (* transport->vtable->handle_watch) (transport, watch, condition);
   _dbus_watch_unref (watch);
   _dbus_transport_unref (transport);
+
+  return retval;
 }
 
 /**
@@ -506,6 +511,98 @@ _dbus_transport_do_iteration (DBusTransport  *transport,
   _dbus_transport_unref (transport);
 }
 
+static dbus_bool_t
+recover_unused_bytes (DBusTransport *transport)
+{
+  if (_dbus_auth_do_work (transport->auth) != DBUS_AUTH_STATE_AUTHENTICATED_WITH_UNUSED_BYTES)
+    return TRUE;
+  
+  if (_dbus_auth_needs_decoding (transport->auth))
+    {
+      DBusString plaintext;
+      const DBusString *encoded;
+      DBusString *buffer;
+      int orig_len;
+      
+      if (!_dbus_string_init (&plaintext, _DBUS_INT_MAX))
+        goto nomem;
+      
+      _dbus_auth_get_unused_bytes (transport->auth,
+                                   &encoded);
+
+      if (!_dbus_auth_decode_data (transport->auth,
+                                   encoded, &plaintext))
+        {
+          _dbus_string_free (&plaintext);
+          goto nomem;
+        }
+      
+      _dbus_message_loader_get_buffer (transport->loader,
+                                       &buffer);
+      
+      orig_len = _dbus_string_get_length (buffer);
+      
+      if (!_dbus_string_move (&plaintext, 0, buffer,
+                              orig_len))
+        {
+          _dbus_string_free (&plaintext);
+          goto nomem;
+        }
+      
+      _dbus_verbose (" %d unused bytes sent to message loader\n", 
+                     _dbus_string_get_length (buffer) -
+                     orig_len);
+      
+      _dbus_message_loader_return_buffer (transport->loader,
+                                          buffer,
+                                          _dbus_string_get_length (buffer) -
+                                          orig_len);
+
+      _dbus_auth_delete_unused_bytes (transport->auth);
+      
+      _dbus_string_free (&plaintext);
+    }
+  else
+    {
+      const DBusString *bytes;
+      DBusString *buffer;
+      int orig_len;
+      dbus_bool_t succeeded;
+
+      _dbus_message_loader_get_buffer (transport->loader,
+                                       &buffer);
+                
+      orig_len = _dbus_string_get_length (buffer);
+                
+      _dbus_auth_get_unused_bytes (transport->auth,
+                                   &bytes);
+
+      succeeded = TRUE;
+      if (!_dbus_string_copy (bytes, 0, buffer, _dbus_string_get_length (buffer)))
+        succeeded = FALSE;
+      
+      _dbus_verbose (" %d unused bytes sent to message loader\n", 
+                     _dbus_string_get_length (buffer) -
+                     orig_len);
+      
+      _dbus_message_loader_return_buffer (transport->loader,
+                                          buffer,
+                                          _dbus_string_get_length (buffer) -
+                                          orig_len);
+
+      if (succeeded)
+        _dbus_auth_delete_unused_bytes (transport->auth);
+      else
+        goto nomem;
+    }
+
+  return TRUE;
+
+ nomem:
+  _dbus_verbose ("Not enough memory to transfer unused bytes from auth conversation\n");
+  return FALSE;
+}
+
 /**
  * Reports our current dispatch status (whether there's buffered
  * data to be queued as messages, or not, or we need memory).
@@ -519,6 +616,21 @@ _dbus_transport_get_dispatch_status (DBusTransport *transport)
   if (_dbus_counter_get_value (transport->live_messages_size) >= transport->max_live_messages_size)
     return DBUS_DISPATCH_COMPLETE; /* complete for now */
 
+  if (!_dbus_transport_get_is_authenticated (transport))
+    {
+      switch (_dbus_auth_do_work (transport->auth))
+        {
+        case DBUS_AUTH_STATE_WAITING_FOR_MEMORY:
+          return DBUS_DISPATCH_NEED_MEMORY;
+        case DBUS_AUTH_STATE_AUTHENTICATED_WITH_UNUSED_BYTES:
+          if (!recover_unused_bytes (transport))
+            return DBUS_DISPATCH_NEED_MEMORY;
+          break;
+        default:
+          break;
+        }
+    }
+  
   if (!_dbus_message_loader_queue_messages (transport->loader))
     return DBUS_DISPATCH_NEED_MEMORY;
 
index ad3299c..639a7d5 100644 (file)
@@ -37,7 +37,7 @@ void               _dbus_transport_unref                      (DBusTransport  *t
 void               _dbus_transport_disconnect                 (DBusTransport  *transport);
 dbus_bool_t        _dbus_transport_get_is_connected           (DBusTransport  *transport);
 dbus_bool_t        _dbus_transport_get_is_authenticated       (DBusTransport  *transport);
-void               _dbus_transport_handle_watch               (DBusTransport  *transport,
+dbus_bool_t        _dbus_transport_handle_watch               (DBusTransport  *transport,
                                                                DBusWatch      *watch,
                                                                unsigned int    condition);
 dbus_bool_t        _dbus_transport_set_connection             (DBusTransport  *transport,
index 1fdbc7a..c4f1af4 100644 (file)
@@ -63,6 +63,9 @@ _dbus_watch_new (int          fd,
   _dbus_assert ((flags & VALID_WATCH_FLAGS) == flags);
   
   watch = dbus_new0 (DBusWatch, 1);
+  if (watch == NULL)
+    return NULL;
+  
   watch->refcount = 1;
   watch->fd = fd;
   watch->flags = flags;