diff options
| -rw-r--r-- | ChangeLog | 36 | ||||
| -rw-r--r-- | bus/bus.c | 5 | ||||
| -rw-r--r-- | bus/connection.c | 10 | ||||
| -rw-r--r-- | bus/dispatch.c | 7 | ||||
| -rw-r--r-- | bus/loop.c | 35 | ||||
| -rw-r--r-- | bus/loop.h | 10 | ||||
| -rw-r--r-- | bus/test.c | 12 | ||||
| -rw-r--r-- | bus/utils.c | 14 | ||||
| -rw-r--r-- | bus/utils.h | 1 | ||||
| -rw-r--r-- | dbus/dbus-auth-script.c | 46 | ||||
| -rw-r--r-- | dbus/dbus-auth.c | 82 | ||||
| -rw-r--r-- | dbus/dbus-auth.h | 58 | ||||
| -rw-r--r-- | dbus/dbus-connection.c | 22 | ||||
| -rw-r--r-- | dbus/dbus-connection.h | 4 | ||||
| -rw-r--r-- | dbus/dbus-server-debug-pipe.c | 8 | ||||
| -rw-r--r-- | dbus/dbus-server-debug.c | 11 | ||||
| -rw-r--r-- | dbus/dbus-server-protected.h | 10 | ||||
| -rw-r--r-- | dbus/dbus-server-unix.c | 19 | ||||
| -rw-r--r-- | dbus/dbus-server.c | 11 | ||||
| -rw-r--r-- | dbus/dbus-server.h | 2 | ||||
| -rw-r--r-- | dbus/dbus-sysdeps.c | 3 | ||||
| -rw-r--r-- | dbus/dbus-timeout.c | 11 | ||||
| -rw-r--r-- | dbus/dbus-timeout.h | 2 | ||||
| -rw-r--r-- | dbus/dbus-transport-debug.c | 36 | ||||
| -rw-r--r-- | dbus/dbus-transport-protected.h | 24 | ||||
| -rw-r--r-- | dbus/dbus-transport-unix.c | 340 | ||||
| -rw-r--r-- | dbus/dbus-transport.c | 128 | ||||
| -rw-r--r-- | dbus/dbus-transport.h | 2 | ||||
| -rw-r--r-- | dbus/dbus-watch.c | 3 | 
29 files changed, 581 insertions, 371 deletions
| @@ -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: @@ -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);  } diff --git a/bus/connection.c b/bus/connection.c index 80afc7e1..a8616683 100644 --- a/bus/connection.c +++ b/bus/connection.c @@ -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); diff --git a/bus/dispatch.c b/bus/dispatch.c index 639b9509..b4b03d96 100644 --- a/bus/dispatch.c +++ b/bus/dispatch.c @@ -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); @@ -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;                  } @@ -26,11 +26,11 @@  #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, @@ -35,18 +35,21 @@   */  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); diff --git a/bus/utils.c b/bus/utils.c index 8a68d8a4..090e27f0 100644 --- a/bus/utils.c +++ b/bus/utils.c @@ -28,18 +28,24 @@  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)) diff --git a/bus/utils.h b/bus/utils.h index 968ece37..5b30de60 100644 --- a/bus/utils.h +++ b/bus/utils.h @@ -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[]; diff --git a/dbus/dbus-auth-script.c b/dbus/dbus-auth-script.c index 336d63e1..d954c8dd 100644 --- a/dbus/dbus-auth-script.c +++ b/dbus/dbus-auth-script.c @@ -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;              }          } diff --git a/dbus/dbus-auth.c b/dbus/dbus-auth.c index 4b1f5504..9e2b1d95 100644 --- a/dbus/dbus-auth.c +++ b/dbus/dbus-auth.c @@ -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);  }  /** diff --git a/dbus/dbus-auth.h b/dbus/dbus-auth.h index 0339a4f8..8309fe33 100644 --- a/dbus/dbus-auth.h +++ b/dbus/dbus-auth.h @@ -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; diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c index 7f9423af..d6ee104a 100644 --- a/dbus/dbus-connection.c +++ b/dbus/dbus-connection.c @@ -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;  }  /** diff --git a/dbus/dbus-connection.h b/dbus/dbus-connection.h index b4e6007d..9b135a5d 100644 --- a/dbus/dbus-connection.h +++ b/dbus/dbus-connection.h @@ -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 */ diff --git a/dbus/dbus-server-debug-pipe.c b/dbus/dbus-server-debug-pipe.c index 8f57ae8d..46e78ddd 100644 --- a/dbus/dbus-server-debug-pipe.c +++ b/dbus/dbus-server-debug-pipe.c @@ -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;      } diff --git a/dbus/dbus-server-debug.c b/dbus/dbus-server-debug.c index b1318e32..3b7e78dd 100644 --- a/dbus/dbus-server-debug.c +++ b/dbus/dbus-server-debug.c @@ -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;  }  /** diff --git a/dbus/dbus-server-protected.h b/dbus/dbus-server-protected.h index bbedeea3..d47215b7 100644 --- a/dbus/dbus-server-protected.h +++ b/dbus/dbus-server-protected.h @@ -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. */  }; diff --git a/dbus/dbus-server-unix.c b/dbus/dbus-server-unix.c index a181a925..88cc9ed7 100644 --- a/dbus/dbus-server-unix.c +++ b/dbus/dbus-server-unix.c @@ -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 diff --git a/dbus/dbus-server.c b/dbus/dbus-server.c index 79ed7ed4..ba48cd97 100644 --- a/dbus/dbus-server.c +++ b/dbus/dbus-server.c @@ -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);  }  /** diff --git a/dbus/dbus-server.h b/dbus/dbus-server.h index 589237f1..75632440 100644 --- a/dbus/dbus-server.h +++ b/dbus/dbus-server.h @@ -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, diff --git a/dbus/dbus-sysdeps.c b/dbus/dbus-sysdeps.c index e6e0b276..8abcc5fc 100644 --- a/dbus/dbus-sysdeps.c +++ b/dbus/dbus-sysdeps.c @@ -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 diff --git a/dbus/dbus-timeout.c b/dbus/dbus-timeout.c index 9825872e..a77363be 100644 --- a/dbus/dbus-timeout.c +++ b/dbus/dbus-timeout.c @@ -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);  } diff --git a/dbus/dbus-timeout.h b/dbus/dbus-timeout.h index 0ff5dc56..2f136ae0 100644 --- a/dbus/dbus-timeout.h +++ b/dbus/dbus-timeout.h @@ -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, diff --git a/dbus/dbus-transport-debug.c b/dbus/dbus-transport-debug.c index a7db3a6e..d477339a 100644 --- a/dbus/dbus-transport-debug.c +++ b/dbus/dbus-transport-debug.c @@ -48,11 +48,13 @@  #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 diff --git a/dbus/dbus-transport-protected.h b/dbus/dbus-transport-protected.h index 0f6c45ed..8ee605c0 100644 --- a/dbus/dbus-transport-protected.h +++ b/dbus/dbus-transport-protected.h @@ -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 */  }; diff --git a/dbus/dbus-transport-unix.c b/dbus/dbus-transport-unix.c index 9ea5ce11..5cbbb1f4 100644 --- a/dbus/dbus-transport-unix.c +++ b/dbus/dbus-transport-unix.c @@ -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; diff --git a/dbus/dbus-transport.c b/dbus/dbus-transport.c index b2355ea5..8087f5b0 100644 --- a/dbus/dbus-transport.c +++ b/dbus/dbus-transport.c @@ -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; diff --git a/dbus/dbus-transport.h b/dbus/dbus-transport.h index ad3299c2..639a7d50 100644 --- a/dbus/dbus-transport.h +++ b/dbus/dbus-transport.h @@ -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, diff --git a/dbus/dbus-watch.c b/dbus/dbus-watch.c index 1fdbc7ac..c4f1af4a 100644 --- a/dbus/dbus-watch.c +++ b/dbus/dbus-watch.c @@ -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; | 
