From 1820f3bd0a5a4b0ab14dbcc80ba1b68d2c48e01d Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Thu, 24 Apr 2003 21:26:25 +0000 Subject: 2003-04-24 Havoc Pennington * bus/dispatch.c: somehow missed some name_is * dbus/dbus-timeout.c (_dbus_timeout_set_enabled) (_dbus_timeout_set_interval): new * bus/connection.c (bus_connections_setup_connection): record time when each connection is first set up, and expire them after the auth timeout passes. --- ChangeLog | 11 ++++ bus/connection.c | 154 ++++++++++++++++++++++++++++++++++++++++++++----- bus/connection.h | 40 +++++++------ bus/dispatch.c | 52 ++++++++--------- dbus/dbus-connection.c | 10 ++-- dbus/dbus-timeout.c | 43 +++++++++++++- dbus/dbus-timeout.h | 16 +++-- test/test-service.c | 6 +- 8 files changed, 257 insertions(+), 75 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8faf50d3..f770a533 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2003-04-24 Havoc Pennington + + * bus/dispatch.c: somehow missed some name_is + + * dbus/dbus-timeout.c (_dbus_timeout_set_enabled) + (_dbus_timeout_set_interval): new + + * bus/connection.c (bus_connections_setup_connection): record time + when each connection is first set up, and expire them after the + auth timeout passes. + 2003-04-24 Havoc Pennington * dbus/dbus-message.c (dbus_message_name_is): rename diff --git a/bus/connection.c b/bus/connection.c index 146e3769..68429b2d 100644 --- a/bus/connection.c +++ b/bus/connection.c @@ -27,6 +27,7 @@ #include "utils.h" #include #include +#include static void bus_connection_remove_transactions (DBusConnection *connection); @@ -39,6 +40,7 @@ struct BusConnections int n_incomplete; /**< Length of incomplete list */ BusContext *context; DBusHashTable *completed_by_user; /**< Number of completed connections for each UID */ + DBusTimeout *expire_timeout; /**< Timeout for expiring incomplete connections. */ }; static int connection_data_slot = -1; @@ -55,8 +57,13 @@ typedef struct DBusMessage *oom_message; DBusPreallocatedSend *oom_preallocated; BusClientPolicy *policy; + + long connection_tv_sec; /**< Time when we connected (seconds component) */ + long connection_tv_usec; /**< Time when we connected (microsec component) */ } BusConnectionData; +static dbus_bool_t expire_incomplete_timeout (void *data); + #define BUS_CONNECTION_DATA(connection) (dbus_connection_get_data ((connection), connection_data_slot)) static dbus_bool_t @@ -178,10 +185,7 @@ bus_connection_disconnected (DBusConnection *connection) * handle it other than sleeping; we can't "fail" the operation of * disconnecting a client, and preallocating a broadcast "service is * now gone" message for every client-service pair seems kind of - * involved. Probably we need to do that though, and also - * extend BusTransaction to be able to revert generic - * stuff, not just sending a message (so we can e.g. revert - * removal of service owners). + * involved. Probably we need to do that though. */ while ((service = _dbus_list_get_last (&d->services_owned))) { @@ -400,34 +404,59 @@ free_connection_data (void *data) dbus_free (d); } +static void +call_timeout_callback (DBusTimeout *timeout, + void *data) +{ + /* can return FALSE on OOM but we just let it fire again later */ + dbus_timeout_handle (timeout); +} + BusConnections* bus_connections_new (BusContext *context) { BusConnections *connections; if (!connection_data_slot_ref ()) - return NULL; + goto failed_0; connections = dbus_new0 (BusConnections, 1); if (connections == NULL) - { - connection_data_slot_unref (); - return NULL; - } + goto failed_1; connections->completed_by_user = _dbus_hash_table_new (DBUS_HASH_ULONG, NULL, NULL); if (connections->completed_by_user == NULL) - { - dbus_free (connections); - connection_data_slot_unref (); - return NULL; - } + goto failed_2; + + connections->expire_timeout = _dbus_timeout_new (100, /* irrelevant */ + expire_incomplete_timeout, + connections, NULL); + if (connections->expire_timeout == NULL) + goto failed_3; + + _dbus_timeout_set_enabled (connections->expire_timeout, FALSE); + + if (!_dbus_loop_add_timeout (bus_context_get_loop (context), + connections->expire_timeout, + call_timeout_callback, NULL, NULL)) + goto failed_4; connections->refcount = 1; connections->context = context; return connections; + + failed_4: + _dbus_timeout_unref (connections->expire_timeout); + failed_3: + _dbus_hash_table_unref (connections->completed_by_user); + failed_2: + dbus_free (connections); + failed_1: + connection_data_slot_unref (); + failed_0: + return NULL; } void @@ -474,6 +503,12 @@ bus_connections_unref (BusConnections *connections) _dbus_assert (connections->n_completed == 0); + _dbus_loop_remove_timeout (bus_context_get_loop (connections->context), + connections->expire_timeout, + call_timeout_callback, NULL); + + _dbus_timeout_unref (connections->expire_timeout); + _dbus_hash_table_unref (connections->completed_by_user); dbus_free (connections); @@ -497,6 +532,9 @@ bus_connections_setup_connection (BusConnections *connections, d->connections = connections; d->connection = connection; + _dbus_get_current_time (&d->connection_tv_sec, + &d->connection_tv_usec); + _dbus_assert (connection_data_slot >= 0); if (!dbus_connection_set_data (connection, @@ -556,7 +594,14 @@ bus_connections_setup_connection (BusConnections *connections, dbus_connection_ref (connection); /* Note that we might disconnect ourselves here, but it only takes - * effect on return to the main loop. + * effect on return to the main loop. We call this to free up + * expired connections if possible, and to queue the timeout for our + * own expiration. + */ + bus_connections_expire_incomplete (connections); + + /* And we might also disconnect ourselves here, but again it + * only takes effect on return to main loop. */ if (connections->n_incomplete > bus_context_get_max_incomplete_connections (connections->context)) @@ -613,6 +658,85 @@ bus_connections_setup_connection (BusConnections *connections, return retval; } +void +bus_connections_expire_incomplete (BusConnections *connections) +{ + int next_interval; + long tv_sec, tv_usec; + DBusList *link; + int auth_timeout; + + if (connections->incomplete == NULL) + return; + + _dbus_get_current_time (&tv_sec, &tv_usec); + auth_timeout = bus_context_get_auth_timeout (connections->context); + next_interval = -1; + + link = _dbus_list_get_first_link (&connections->incomplete); + while (link != NULL) + { + DBusList *next = _dbus_list_get_next_link (&connections->incomplete, link); + DBusConnection *connection; + BusConnectionData *d; + double elapsed; + + connection = link->data; + + d = BUS_CONNECTION_DATA (connection); + + _dbus_assert (d != NULL); + + elapsed = ((double) tv_sec - (double) d->connection_tv_sec) * 1000.0 + + ((double) tv_usec - (double) d->connection_tv_usec) / 1000.0; + + if (elapsed > (double) auth_timeout) + { + _dbus_verbose ("Timing out authentication for connection %p\n", connection); + dbus_connection_disconnect (connection); + } + else + { + /* We can end the loop, since the connections are in oldest-first order */ + next_interval = auth_timeout - (int) elapsed; + _dbus_verbose ("Connection %p authentication expires in %d milliseconds\n", + connection, next_interval); + + break; + } + + link = next; + } + + if (next_interval >= 0) + { + _dbus_timeout_set_interval (connections->expire_timeout, + next_interval); + _dbus_timeout_set_enabled (connections->expire_timeout, TRUE); + + _dbus_verbose ("Enabled incomplete connections timeout with interval %d, %d incomplete connections\n", + next_interval, connections->n_incomplete); + } + else + { + _dbus_timeout_set_enabled (connections->expire_timeout, FALSE); + + _dbus_verbose ("Disabled incomplete connections timeout, %d incomplete connections\n", + connections->n_incomplete); + } +} + +static dbus_bool_t +expire_incomplete_timeout (void *data) +{ + BusConnections *connections = data; + + /* note that this may remove the timeout */ + bus_connections_expire_incomplete (connections); + + return TRUE; +} + dbus_bool_t bus_connection_get_groups (DBusConnection *connection, unsigned long **groups, diff --git a/bus/connection.h b/bus/connection.h index 0d4d3a10..fe5a3769 100644 --- a/bus/connection.h +++ b/bus/connection.h @@ -32,25 +32,27 @@ typedef dbus_bool_t (* BusConnectionForeachFunction) (DBusConnection *connection void *data); -BusConnections* bus_connections_new (BusContext *context); -void bus_connections_ref (BusConnections *connections); -void bus_connections_unref (BusConnections *connections); -dbus_bool_t bus_connections_setup_connection (BusConnections *connections, - DBusConnection *connection); -void bus_connections_foreach (BusConnections *connections, - BusConnectionForeachFunction function, - void *data); -void bus_connections_foreach_active (BusConnections *connections, - BusConnectionForeachFunction function, - void *data); -BusContext* bus_connections_get_context (BusConnections *connections); -BusContext* bus_connection_get_context (DBusConnection *connection); -BusConnections* bus_connection_get_connections (DBusConnection *connection); -BusRegistry* bus_connection_get_registry (DBusConnection *connection); -BusActivation* bus_connection_get_activation (DBusConnection *connection); -dbus_bool_t bus_connections_check_limits (BusConnections *connections, - DBusConnection *requesting_completion, - DBusError *error); +BusConnections* bus_connections_new (BusContext *context); +void bus_connections_ref (BusConnections *connections); +void bus_connections_unref (BusConnections *connections); +dbus_bool_t bus_connections_setup_connection (BusConnections *connections, + DBusConnection *connection); +void bus_connections_foreach (BusConnections *connections, + BusConnectionForeachFunction function, + void *data); +void bus_connections_foreach_active (BusConnections *connections, + BusConnectionForeachFunction function, + void *data); +BusContext* bus_connections_get_context (BusConnections *connections); +BusContext* bus_connection_get_context (DBusConnection *connection); +BusConnections* bus_connection_get_connections (DBusConnection *connection); +BusRegistry* bus_connection_get_registry (DBusConnection *connection); +BusActivation* bus_connection_get_activation (DBusConnection *connection); +dbus_bool_t bus_connections_check_limits (BusConnections *connections, + DBusConnection *requesting_completion, + DBusError *error); +void bus_connections_expire_incomplete (BusConnections *connections); + dbus_bool_t bus_connection_is_active (DBusConnection *connection); diff --git a/bus/dispatch.c b/bus/dispatch.c index 14c6531e..2f865bf7 100644 --- a/bus/dispatch.c +++ b/bus/dispatch.c @@ -457,7 +457,7 @@ check_service_deleted_foreach (DBusConnection *connection, connection, DBUS_MESSAGE_SERVICE_DELETED); goto out; } - else if (!dbus_message_name_is (message, DBUS_MESSAGE_SERVICE_DELETED)) + else if (!dbus_message_has_name (message, DBUS_MESSAGE_SERVICE_DELETED)) { _dbus_warn ("Received message %s on %p, expecting %s\n", dbus_message_get_name (message), @@ -624,7 +624,7 @@ check_service_created_foreach (DBusConnection *connection, connection, DBUS_MESSAGE_SERVICE_CREATED); goto out; } - else if (!dbus_message_name_is (message, DBUS_MESSAGE_SERVICE_CREATED)) + else if (!dbus_message_has_name (message, DBUS_MESSAGE_SERVICE_CREATED)) { _dbus_warn ("Received message %s on %p, expecting %s\n", dbus_message_get_name (message), @@ -747,7 +747,7 @@ check_hello_message (BusContext *context, _dbus_verbose ("Received %s on %p\n", dbus_message_get_name (message), connection); - if (!dbus_message_sender_is (message, DBUS_SERVICE_DBUS)) + if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS)) { _dbus_warn ("Message has wrong sender %s\n", dbus_message_get_sender (message) ? @@ -757,8 +757,8 @@ check_hello_message (BusContext *context, if (dbus_message_get_is_error (message)) { - if (dbus_message_name_is (message, - DBUS_ERROR_NO_MEMORY)) + if (dbus_message_has_name (message, + DBUS_ERROR_NO_MEMORY)) { ; /* good, this is a valid response */ } @@ -773,8 +773,8 @@ check_hello_message (BusContext *context, { CheckServiceCreatedData scd; - if (dbus_message_name_is (message, - DBUS_MESSAGE_HELLO)) + if (dbus_message_has_name (message, + DBUS_MESSAGE_HELLO)) { ; /* good, expected */ } @@ -985,7 +985,7 @@ check_nonexistent_service_activation (BusContext *context, if (dbus_message_get_is_error (message)) { - if (!dbus_message_sender_is (message, DBUS_SERVICE_DBUS)) + if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS)) { _dbus_warn ("Message has wrong sender %s\n", dbus_message_get_sender (message) ? @@ -993,13 +993,13 @@ check_nonexistent_service_activation (BusContext *context, goto out; } - if (dbus_message_name_is (message, - DBUS_ERROR_NO_MEMORY)) + if (dbus_message_has_name (message, + DBUS_ERROR_NO_MEMORY)) { ; /* good, this is a valid response */ } - else if (dbus_message_name_is (message, - DBUS_ERROR_ACTIVATE_SERVICE_NOT_FOUND)) + else if (dbus_message_has_name (message, + DBUS_ERROR_ACTIVATE_SERVICE_NOT_FOUND)) { ; /* good, this is expected also */ } @@ -1045,7 +1045,7 @@ check_base_service_activated (BusContext *context, message = initial_message; dbus_message_ref (message); - if (dbus_message_name_is (message, DBUS_MESSAGE_SERVICE_CREATED)) + if (dbus_message_has_name (message, DBUS_MESSAGE_SERVICE_CREATED)) { char *service_name; CheckServiceCreatedData scd; @@ -1134,7 +1134,7 @@ check_service_activated (BusContext *context, message = initial_message; dbus_message_ref (message); - if (dbus_message_name_is (message, DBUS_MESSAGE_SERVICE_CREATED)) + if (dbus_message_has_name (message, DBUS_MESSAGE_SERVICE_CREATED)) { char *service_name; CheckServiceCreatedData scd; @@ -1195,7 +1195,7 @@ check_service_activated (BusContext *context, goto out; } - if (!dbus_message_name_is (message, DBUS_MESSAGE_ACTIVATE_SERVICE)) + if (!dbus_message_has_name (message, DBUS_MESSAGE_ACTIVATE_SERVICE)) { _dbus_warn ("Expected reply to %s, got message %s instead\n", DBUS_MESSAGE_ACTIVATE_SERVICE, @@ -1380,7 +1380,7 @@ check_send_exit_to_service (BusContext *context, dbus_message_get_name (message)); goto out; } - else if (!dbus_message_name_is (message, DBUS_ERROR_NO_MEMORY)) + else if (!dbus_message_has_name (message, DBUS_ERROR_NO_MEMORY)) { _dbus_warn ("not expecting error %s when asking test service to exit\n", dbus_message_get_name (message)); @@ -1445,7 +1445,7 @@ check_got_error (BusContext *context, error_name = first_error_name; while (error_name != NULL) { - if (dbus_message_name_is (message, error_name)) + if (dbus_message_has_name (message, error_name)) { error_found = TRUE; break; @@ -1545,7 +1545,7 @@ check_existent_service_activation (BusContext *context, if (dbus_message_get_is_error (message)) { - if (!dbus_message_sender_is (message, DBUS_SERVICE_DBUS)) + if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS)) { _dbus_warn ("Message has wrong sender %s\n", dbus_message_get_sender (message) ? @@ -1553,13 +1553,13 @@ check_existent_service_activation (BusContext *context, goto out; } - if (dbus_message_name_is (message, - DBUS_ERROR_NO_MEMORY)) + if (dbus_message_has_name (message, + DBUS_ERROR_NO_MEMORY)) { ; /* good, this is a valid response */ } - else if (dbus_message_name_is (message, - DBUS_ERROR_SPAWN_CHILD_EXITED)) + else if (dbus_message_has_name (message, + DBUS_ERROR_SPAWN_CHILD_EXITED)) { ; /* good, this is expected also */ } @@ -1592,7 +1592,7 @@ check_existent_service_activation (BusContext *context, goto out; } - got_service_deleted = dbus_message_name_is (message, DBUS_MESSAGE_SERVICE_DELETED); + got_service_deleted = dbus_message_has_name (message, DBUS_MESSAGE_SERVICE_DELETED); got_error = dbus_message_get_is_error (message); dbus_connection_return_message (connection, message); @@ -1748,7 +1748,7 @@ check_segfault_service_activation (BusContext *context, if (dbus_message_get_is_error (message)) { - if (!dbus_message_sender_is (message, DBUS_SERVICE_DBUS)) + if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS)) { _dbus_warn ("Message has wrong sender %s\n", dbus_message_get_sender (message) ? @@ -1756,12 +1756,12 @@ check_segfault_service_activation (BusContext *context, goto out; } - if (dbus_message_name_is (message, + if (dbus_message_has_name (message, DBUS_ERROR_NO_MEMORY)) { ; /* good, this is a valid response */ } - else if (dbus_message_name_is (message, + else if (dbus_message_has_name (message, DBUS_ERROR_SPAWN_CHILD_SIGNALED)) { ; /* good, this is expected also */ diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c index 4bb0514f..9843d288 100644 --- a/dbus/dbus-connection.c +++ b/dbus/dbus-connection.c @@ -2394,12 +2394,14 @@ dbus_connection_set_watch_functions (DBusConnection *connection, * allocation. With Qt, QTimer::start() and QTimer::stop() can be used * to enable and disable. The toggled function may be NULL if a main * loop re-queries dbus_timeout_get_enabled() every time anyway. + * Whenever a timeout is toggled, its interval may change. * * The DBusTimeout can be queried for the timer interval using - * dbus_timeout_get_interval(). dbus_timeout_handle() should - * be called repeatedly, each time the interval elapses, starting - * after it has elapsed once. The timeout stops firing when - * it is removed with the given remove_function. + * dbus_timeout_get_interval(). dbus_timeout_handle() should be called + * repeatedly, each time the interval elapses, starting after it has + * elapsed once. The timeout stops firing when it is removed with the + * given remove_function. The timer interval may change whenever the + * timeout is added, removed, or toggled. * * @param connection the connection. * @param add_function function to add a timeout. diff --git a/dbus/dbus-timeout.c b/dbus/dbus-timeout.c index a77363be..74210f9a 100644 --- a/dbus/dbus-timeout.c +++ b/dbus/dbus-timeout.c @@ -48,7 +48,7 @@ struct DBusTimeout }; /** - * Creates a new DBusTimeout. + * Creates a new DBusTimeout, enabled by default. * @param interval the timeout interval in milliseconds. * @param handler function to call when the timeout occurs. * @param data data to pass to the handler @@ -111,6 +111,40 @@ _dbus_timeout_unref (DBusTimeout *timeout) } } +/** + * Changes the timeout interval. Note that you have to disable and + * re-enable the timeout using the timeout toggle function + * (_dbus_connection_toggle_timeout() etc.) to notify the application + * of this change. + * + * @param timeout the timeout + * @param interval the new interval + */ +void +_dbus_timeout_set_interval (DBusTimeout *timeout, + int interval) +{ + timeout->interval = interval; +} + +/** + * Changes the timeout's enabled-ness. Note that you should use + * _dbus_connection_toggle_timeout() etc. instead, if + * the timeout is passed out to an application main loop. + * i.e. you can't use this function in the D-BUS library, it's + * only used in the message bus daemon implementation. + * + * @param timeout the timeout + * @param interval the new interval + */ +void +_dbus_timeout_set_enabled (DBusTimeout *timeout, + dbus_bool_t enabled) +{ + timeout->enabled = enabled != FALSE; +} + + /** * @typedef DBusTimeoutList * @@ -133,7 +167,7 @@ struct DBusTimeoutList DBusAddTimeoutFunction add_timeout_function; /**< Callback for adding a timeout. */ DBusRemoveTimeoutFunction remove_timeout_function; /**< Callback for removing a timeout. */ - DBusTimeoutToggledFunction timeout_toggled_function; /**< Callback when timeout is enabled/disabled */ + DBusTimeoutToggledFunction timeout_toggled_function; /**< Callback when timeout is enabled/disabled or changes interval */ void *timeout_data; /**< Data for timeout callbacks */ DBusFreeFunction timeout_free_data_function; /**< Free function for timeout callback data */ }; @@ -355,6 +389,11 @@ _dbus_timeout_list_toggle_timeout (DBusTimeoutList *timeout_list, * should be called each time this interval elapses, * starting after it elapses once. * + * The interval may change during the life of the + * timeout; if so, the timeout will be disabled and + * re-enabled (calling the "timeout toggled function") + * to notify you of the change. + * * @param timeout the DBusTimeout object. * @returns the interval in milliseconds. */ diff --git a/dbus/dbus-timeout.h b/dbus/dbus-timeout.h index 2f136ae0..c68f29fa 100644 --- a/dbus/dbus-timeout.h +++ b/dbus/dbus-timeout.h @@ -34,12 +34,16 @@ typedef struct DBusTimeoutList DBusTimeoutList; typedef dbus_bool_t (* DBusTimeoutHandler) (void *data); -DBusTimeout* _dbus_timeout_new (int interval, - DBusTimeoutHandler handler, - void *data, - DBusFreeFunction free_data_function); -void _dbus_timeout_ref (DBusTimeout *timeout); -void _dbus_timeout_unref (DBusTimeout *timeout); +DBusTimeout* _dbus_timeout_new (int interval, + DBusTimeoutHandler handler, + void *data, + DBusFreeFunction free_data_function); +void _dbus_timeout_ref (DBusTimeout *timeout); +void _dbus_timeout_unref (DBusTimeout *timeout); +void _dbus_timeout_set_interval (DBusTimeout *timeout, + int interval); +void _dbus_timeout_set_enabled (DBusTimeout *timeout, + dbus_bool_t enabled); DBusTimeoutList *_dbus_timeout_list_new (void); void _dbus_timeout_list_free (DBusTimeoutList *timeout_list); diff --git a/test/test-service.c b/test/test-service.c index 9784d3b7..c2757acc 100644 --- a/test/test-service.c +++ b/test/test-service.c @@ -77,10 +77,10 @@ filter_func (DBusMessageHandler *handler, DBusMessage *message, void *user_data) { - if (dbus_message_name_is (message, "org.freedesktop.DBus.TestSuiteEcho")) + if (dbus_message_has_name (message, "org.freedesktop.DBus.TestSuiteEcho")) return handle_echo (connection, message); - else if (dbus_message_name_is (message, "org.freedesktop.DBus.TestSuiteExit") || - dbus_message_name_is (message, DBUS_MESSAGE_LOCAL_DISCONNECT)) + else if (dbus_message_has_name (message, "org.freedesktop.DBus.TestSuiteExit") || + dbus_message_has_name (message, DBUS_MESSAGE_LOCAL_DISCONNECT)) { dbus_connection_disconnect (connection); quit (); -- cgit