Commit b4a1100f authored by Havoc Pennington's avatar Havoc Pennington

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
parent 3caaa342
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);
}
......
......@@ -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);
......
......@@ -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);
......
......@@ -28,17 +28,23 @@
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)
{
......
......@@ -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[];
......
......@@ -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;
}
}
......
......@@ -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);
}
/**
......
......@@ -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;
......
......@@ -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;
}
/**
......
......@@ -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 */
......
......@@ -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;
}
......
......@@ -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;
}
/**
......
......@@ -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. */
};
......