summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHavoc Pennington <hp@redhat.com>2003-03-17 01:54:37 +0000
committerHavoc Pennington <hp@redhat.com>2003-03-17 01:54:37 +0000
commitb4a1100f4f81534e2aac0141afda750f318223d4 (patch)
tree9573e47181fc32c40f4784df0d22b2c6ee4143c4
parent3caaa342e8db2cba690bb9e1a228ef3862e203d8 (diff)
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
-rw-r--r--ChangeLog36
-rw-r--r--bus/bus.c5
-rw-r--r--bus/connection.c10
-rw-r--r--bus/dispatch.c7
-rw-r--r--bus/loop.c35
-rw-r--r--bus/loop.h10
-rw-r--r--bus/test.c12
-rw-r--r--bus/utils.c14
-rw-r--r--bus/utils.h1
-rw-r--r--dbus/dbus-auth-script.c46
-rw-r--r--dbus/dbus-auth.c82
-rw-r--r--dbus/dbus-auth.h58
-rw-r--r--dbus/dbus-connection.c22
-rw-r--r--dbus/dbus-connection.h4
-rw-r--r--dbus/dbus-server-debug-pipe.c8
-rw-r--r--dbus/dbus-server-debug.c11
-rw-r--r--dbus/dbus-server-protected.h10
-rw-r--r--dbus/dbus-server-unix.c19
-rw-r--r--dbus/dbus-server.c11
-rw-r--r--dbus/dbus-server.h2
-rw-r--r--dbus/dbus-sysdeps.c3
-rw-r--r--dbus/dbus-timeout.c11
-rw-r--r--dbus/dbus-timeout.h2
-rw-r--r--dbus/dbus-transport-debug.c36
-rw-r--r--dbus/dbus-transport-protected.h24
-rw-r--r--dbus/dbus-transport-unix.c340
-rw-r--r--dbus/dbus-transport.c128
-rw-r--r--dbus/dbus-transport.h2
-rw-r--r--dbus/dbus-watch.c3
29 files changed, 581 insertions, 371 deletions
diff --git a/ChangeLog b/ChangeLog
index e31696d2..f38c924a 100644
--- 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:
diff --git a/bus/bus.c b/bus/bus.c
index 589dda1b..a1bc6622 100644
--- 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);
}
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);
diff --git a/bus/loop.c b/bus/loop.c
index ea0ec106..93096dc5 100644
--- a/bus/loop.c
+++ b/bus/loop.c
@@ -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;
}
diff --git a/bus/loop.h b/bus/loop.h
index 72b356b2..b217a776 100644
--- a/bus/loop.h
+++ b/bus/loop.h
@@ -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,
diff --git a/bus/test.c b/bus/test.c
index 09e40f34..7de1d811 100644
--- a/bus/test.c
+++ b/bus/test.c
@@ -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;