diff options
-rw-r--r-- | ChangeLog | 14 | ||||
-rw-r--r-- | bus/bus.c | 56 | ||||
-rw-r--r-- | bus/bus.h | 51 | ||||
-rw-r--r-- | bus/connection.c | 317 | ||||
-rw-r--r-- | bus/connection.h | 10 | ||||
-rw-r--r-- | bus/dispatch.c | 5 | ||||
-rw-r--r-- | bus/driver.c | 15 | ||||
-rw-r--r-- | dbus/dbus-connection.h | 8 | ||||
-rw-r--r-- | dbus/dbus-list.c | 13 | ||||
-rw-r--r-- | dbus/dbus-list.h | 2 | ||||
-rw-r--r-- | dbus/dbus-sysdeps.c | 4 | ||||
-rw-r--r-- | doc/TODO | 12 |
12 files changed, 428 insertions, 79 deletions
@@ -1,3 +1,17 @@ +2003-04-19 Havoc Pennington <hp@pobox.com> + + * bus/driver.c (bus_driver_handle_hello): check limits and + return an error if they are exceeded. + + * bus/connection.c: maintain separate lists of active and inactive + connections, and a count of each. Maintain count of completed + connections per user. Implement code to check connection limits. + + * dbus/dbus-list.c (_dbus_list_unlink): export + + * bus/bus.c (bus_context_check_security_policy): enforce a maximum + number of bytes in the message queue for a connection + 2003-04-18 Havoc Pennington <hp@pobox.com> * dbus/dbus-auth.c (record_mechanisms): memleak fixes @@ -45,8 +45,11 @@ struct BusContext BusRegistry *registry; BusPolicy *policy; DBusUserDatabase *user_database; - int activation_timeout; /**< How long to wait for an activation to time out */ - int auth_timeout; /**< How long to wait for an authentication to time out */ + long max_incoming_bytes; /**< How many incoming messages for a connection */ + long max_outgoing_bytes; /**< How many outgoing bytes can be queued for a connection */ + long max_message_size; /**< Max size of a single message in bytes */ + int activation_timeout; /**< How long to wait for an activation to time out */ + int auth_timeout; /**< How long to wait for an authentication to time out */ int max_completed_connections; /**< Max number of authorized connections */ int max_incomplete_connections; /**< Max number of incomplete connections */ int max_connections_per_user; /**< Max number of connections auth'd as same user */ @@ -210,6 +213,12 @@ new_connection_callback (DBusServer *server, */ dbus_connection_disconnect (new_connection); } + + dbus_connection_set_max_received_size (new_connection, + context->max_incoming_bytes); + + dbus_connection_set_max_message_size (new_connection, + context->max_message_size); /* on OOM, we won't have ref'd the connection so it will die. */ } @@ -353,6 +362,11 @@ bus_context_new (const DBusString *config_file, */ if (!server_data_slot_ref ()) _dbus_assert_not_reached ("second ref of server data slot failed"); + + /* Make up some numbers! woot! */ + context->max_incoming_bytes = _DBUS_ONE_MEGABYTE * 63; + context->max_outgoing_bytes = _DBUS_ONE_MEGABYTE * 63; + context->max_message_size = _DBUS_ONE_MEGABYTE * 32; #ifdef DBUS_BUILD_TESTS context->activation_timeout = 6000; /* 6 seconds */ @@ -375,7 +389,7 @@ bus_context_new (const DBusString *config_file, * DOS all the other users. */ context->max_completed_connections = 1024; - + context->user_database = _dbus_user_database_new (); if (context->user_database == NULL) { @@ -818,6 +832,30 @@ bus_context_get_activation_timeout (BusContext *context) return context->activation_timeout; } +int +bus_context_get_auth_timeout (BusContext *context) +{ + return context->auth_timeout; +} + +int +bus_context_get_max_completed_connections (BusContext *context) +{ + return context->max_completed_connections; +} + +int +bus_context_get_max_incomplete_connections (BusContext *context) +{ + return context->max_incomplete_connections; +} + +int +bus_context_get_max_connections_per_user (BusContext *context) +{ + return context->max_connections_per_user; +} + dbus_bool_t bus_context_check_security_policy (BusContext *context, DBusConnection *sender, @@ -878,5 +916,17 @@ bus_context_check_security_policy (BusContext *context, return FALSE; } + /* See if limits on size have been exceeded */ + if (recipient && + dbus_connection_get_outgoing_size (recipient) > + context->max_outgoing_bytes) + { + const char *dest = dbus_message_get_service (message); + dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED, + "The destination service \"%s\" has a full message queue", + dest ? dest : DBUS_SERVICE_DBUS); + return FALSE; + } + return TRUE; } @@ -41,29 +41,34 @@ typedef struct BusRegistry BusRegistry; typedef struct BusService BusService; typedef struct BusTransaction BusTransaction; -BusContext* bus_context_new (const DBusString *config_file, - int print_addr_fd, - DBusError *error); -void bus_context_shutdown (BusContext *context); -void bus_context_ref (BusContext *context); -void bus_context_unref (BusContext *context); -const char* bus_context_get_type (BusContext *context); -const char* bus_context_get_address (BusContext *context); -BusRegistry* bus_context_get_registry (BusContext *context); -BusConnections* bus_context_get_connections (BusContext *context); -BusActivation* bus_context_get_activation (BusContext *context); -DBusLoop* bus_context_get_loop (BusContext *context); -DBusUserDatabase* bus_context_get_user_database (BusContext *context); -dbus_bool_t bus_context_allow_user (BusContext *context, - unsigned long uid); -BusClientPolicy* bus_context_create_client_policy (BusContext *context, - DBusConnection *connection); -int bus_context_get_activation_timeout (BusContext *context); -dbus_bool_t bus_context_check_security_policy (BusContext *context, - DBusConnection *sender, - DBusConnection *recipient, - DBusMessage *message, - DBusError *error); +BusContext* bus_context_new (const DBusString *config_file, + int print_addr_fd, + DBusError *error); +void bus_context_shutdown (BusContext *context); +void bus_context_ref (BusContext *context); +void bus_context_unref (BusContext *context); +const char* bus_context_get_type (BusContext *context); +const char* bus_context_get_address (BusContext *context); +BusRegistry* bus_context_get_registry (BusContext *context); +BusConnections* bus_context_get_connections (BusContext *context); +BusActivation* bus_context_get_activation (BusContext *context); +DBusLoop* bus_context_get_loop (BusContext *context); +DBusUserDatabase* bus_context_get_user_database (BusContext *context); +dbus_bool_t bus_context_allow_user (BusContext *context, + unsigned long uid); +BusClientPolicy* bus_context_create_client_policy (BusContext *context, + DBusConnection *connection); +int bus_context_get_activation_timeout (BusContext *context); +int bus_context_get_auth_timeout (BusContext *context); +int bus_context_get_max_completed_connections (BusContext *context); +int bus_context_get_max_incomplete_connections (BusContext *context); +int bus_context_get_max_connections_per_user (BusContext *context); +dbus_bool_t bus_context_check_security_policy (BusContext *context, + DBusConnection *sender, + DBusConnection *recipient, + DBusMessage *message, + DBusError *error); + #endif /* BUS_BUS_H */ diff --git a/bus/connection.c b/bus/connection.c index 71ab0108..14081e2e 100644 --- a/bus/connection.c +++ b/bus/connection.c @@ -26,14 +26,19 @@ #include "services.h" #include "utils.h" #include <dbus/dbus-list.h> +#include <dbus/dbus-hash.h> static void bus_connection_remove_transactions (DBusConnection *connection); struct BusConnections { int refcount; - DBusList *list; /**< List of all the connections */ + DBusList *completed; /**< List of all completed connections */ + int n_completed; /**< Length of completed list */ + DBusList *incomplete; /**< List of all not-yet-active connections */ + int n_incomplete; /**< Length of incomplete list */ BusContext *context; + DBusHashTable *completed_by_user; /**< Number of completed connections for each UID */ }; static int connection_data_slot = -1; @@ -42,6 +47,7 @@ static int connection_data_slot_refcount = 0; typedef struct { BusConnections *connections; + DBusList *link_in_connection_list; DBusConnection *connection; DBusList *services_owned; char *name; @@ -96,6 +102,65 @@ connection_get_loop (DBusConnection *connection) return bus_context_get_loop (d->connections->context); } + +static int +get_connections_for_uid (BusConnections *connections, + dbus_uid_t uid) +{ + void *val; + int current_count; + + /* val is NULL is 0 when it isn't in the hash yet */ + + val = _dbus_hash_table_lookup_ulong (connections->completed_by_user, + uid); + + current_count = _DBUS_POINTER_TO_INT (val); + + return current_count; +} + +static dbus_bool_t +adjust_connections_for_uid (BusConnections *connections, + dbus_uid_t uid, + int adjustment) +{ + int current_count; + + current_count = get_connections_for_uid (connections, uid); + + _dbus_verbose ("Adjusting connection count for UID " DBUS_UID_FORMAT + ": was %d adjustment %d making %d\n", + uid, current_count, adjustment, current_count + adjustment); + + _dbus_assert (current_count >= 0); + + current_count += adjustment; + + _dbus_assert (current_count >= 0); + + if (current_count == 0) + { + _dbus_hash_table_remove_ulong (connections->completed_by_user, uid); + return TRUE; + } + else + { + dbus_bool_t retval; + + retval = _dbus_hash_table_insert_ulong (connections->completed_by_user, + uid, _DBUS_INT_TO_POINTER (current_count)); + + /* only positive adjustment can fail as otherwise + * a hash entry should already exist + */ + _dbus_assert (adjustment > 0 || + (adjustment <= 0 && retval)); + + return retval; + } +} + void bus_connection_disconnected (DBusConnection *connection) { @@ -180,8 +245,34 @@ bus_connection_disconnected (DBusConnection *connection) bus_connection_remove_transactions (connection); - _dbus_list_remove (&d->connections->list, connection); + if (d->link_in_connection_list != NULL) + { + if (d->name != NULL) + { + unsigned long uid; + + _dbus_list_remove_link (&d->connections->completed, d->link_in_connection_list); + d->link_in_connection_list = NULL; + d->connections->n_completed -= 1; + if (dbus_connection_get_unix_user (connection, &uid)) + { + if (!adjust_connections_for_uid (d->connections, + uid, -1)) + _dbus_assert_not_reached ("adjusting downward should never fail"); + } + } + else + { + _dbus_list_remove_link (&d->connections->incomplete, d->link_in_connection_list); + d->link_in_connection_list = NULL; + d->connections->n_incomplete -= 1; + } + + _dbus_assert (d->connections->n_incomplete >= 0); + _dbus_assert (d->connections->n_completed >= 0); + } + /* frees "d" as side effect */ dbus_connection_set_data (connection, connection_data_slot, @@ -323,6 +414,15 @@ bus_connections_new (BusContext *context) connection_data_slot_unref (); return NULL; } + + 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; + } connections->refcount = 1; connections->context = context; @@ -344,19 +444,37 @@ bus_connections_unref (BusConnections *connections) connections->refcount -= 1; if (connections->refcount == 0) { - while (connections->list != NULL) + /* drop all incomplete */ + while (connections->incomplete != NULL) { DBusConnection *connection; - connection = connections->list->data; + connection = connections->incomplete->data; dbus_connection_ref (connection); dbus_connection_disconnect (connection); bus_connection_disconnected (connection); dbus_connection_unref (connection); } + + _dbus_assert (connections->n_incomplete == 0); - _dbus_list_clear (&connections->list); + /* drop all real connections */ + while (connections->completed != NULL) + { + DBusConnection *connection; + + connection = connections->completed->data; + + dbus_connection_ref (connection); + dbus_connection_disconnect (connection); + bus_connection_disconnected (connection); + dbus_connection_unref (connection); + } + + _dbus_assert (connections->n_completed == 0); + + _dbus_hash_table_unref (connections->completed_by_user); dbus_free (connections); @@ -405,8 +523,7 @@ bus_connections_setup_connection (BusConnections *connections, NULL, connection, NULL)) goto out; - - + dbus_connection_set_unix_user_function (connection, allow_user_function, NULL, NULL); @@ -415,16 +532,14 @@ bus_connections_setup_connection (BusConnections *connections, dispatch_status_function, bus_context_get_loop (connections->context), NULL); + + d->link_in_connection_list = _dbus_list_alloc_link (connection); + if (d->link_in_connection_list == NULL) + goto out; /* Setup the connection with the dispatcher */ if (!bus_dispatch_add_connection (connection)) goto out; - - if (!_dbus_list_append (&connections->list, connection)) - { - bus_dispatch_remove_connection (connection); - goto out; - } if (dbus_connection_get_dispatch_status (connection) != DBUS_DISPATCH_COMPLETE) { @@ -434,13 +549,36 @@ bus_connections_setup_connection (BusConnections *connections, goto out; } } + + _dbus_list_append_link (&connections->incomplete, d->link_in_connection_list); + connections->n_incomplete += 1; dbus_connection_ref (connection); + + /* Note that we might disconnect ourselves here, but it only takes + * effect on return to the main loop. + */ + if (connections->n_incomplete > + bus_context_get_max_incomplete_connections (connections->context)) + { + _dbus_verbose ("Number of incomplete connections exceeds max, dropping oldest one\n"); + + _dbus_assert (connections->incomplete != NULL); + /* Disconnect the oldest unauthenticated connection. FIXME + * would it be more secure to drop a *random* connection? This + * algorithm seems to mean that if someone can create new + * connections quickly enough, they can keep anyone else from + * completing authentication. But random may or may not really + * help with that, a more elaborate solution might be required. + */ + dbus_connection_disconnect (connections->incomplete->data); + } + retval = TRUE; out: if (!retval) - { + { if (!dbus_connection_set_watch_functions (connection, NULL, NULL, NULL, connection, @@ -463,6 +601,13 @@ bus_connections_setup_connection (BusConnections *connections, connection_data_slot, NULL, NULL)) _dbus_assert_not_reached ("failed to set connection data to null"); + + if (d->link_in_connection_list != NULL) + { + _dbus_assert (d->link_in_connection_list->next == NULL); + _dbus_assert (d->link_in_connection_list->prev == NULL); + _dbus_list_free_link (d->link_in_connection_list); + } } return retval; @@ -567,6 +712,67 @@ bus_connection_get_policy (DBusConnection *connection) return d->policy; } +static dbus_bool_t +foreach_active (BusConnections *connections, + BusConnectionForeachFunction function, + void *data) +{ + DBusList *link; + + link = _dbus_list_get_first_link (&connections->completed); + while (link != NULL) + { + DBusConnection *connection = link->data; + DBusList *next = _dbus_list_get_next_link (&connections->completed, link); + + if (!(* function) (connection, data)) + return FALSE; + + link = next; + } + + return TRUE; +} + +static dbus_bool_t +foreach_inactive (BusConnections *connections, + BusConnectionForeachFunction function, + void *data) +{ + DBusList *link; + + link = _dbus_list_get_first_link (&connections->incomplete); + while (link != NULL) + { + DBusConnection *connection = link->data; + DBusList *next = _dbus_list_get_next_link (&connections->incomplete, link); + + if (!(* function) (connection, data)) + return FALSE; + + link = next; + } + + return TRUE; +} + +/** + * Calls function on each active connection; if the function returns + * #FALSE, stops iterating. Active connections are authenticated + * and have sent a Hello message. + * + * @param connections the connections object + * @param function the function + * @param data data to pass to it as a second arg + */ +void +bus_connections_foreach_active (BusConnections *connections, + BusConnectionForeachFunction function, + void *data) +{ + foreach_active (connections, function, data); +} + /** * Calls function on each connection; if the function returns * #FALSE, stops iterating. @@ -578,21 +784,12 @@ bus_connection_get_policy (DBusConnection *connection) void bus_connections_foreach (BusConnections *connections, BusConnectionForeachFunction function, - void *data) + void *data) { - DBusList *link; - - link = _dbus_list_get_first_link (&connections->list); - while (link != NULL) - { - DBusConnection *connection = link->data; - DBusList *next = _dbus_list_get_next_link (&connections->list, link); + if (!foreach_active (connections, function, data)) + return; - if (!(* function) (connection, data)) - break; - - link = next; - } + foreach_inactive (connections, function, data); } BusContext* @@ -789,17 +986,40 @@ bus_connection_set_name (DBusConnection *connection, const DBusString *name) { BusConnectionData *d; + unsigned long uid; d = BUS_CONNECTION_DATA (connection); _dbus_assert (d != NULL); _dbus_assert (d->name == NULL); - + if (!_dbus_string_copy_data (name, &d->name)) return FALSE; _dbus_assert (d->name != NULL); _dbus_verbose ("Name %s assigned to %p\n", d->name, connection); + + if (dbus_connection_get_unix_user (connection, &uid)) + { + if (!adjust_connections_for_uid (d->connections, + uid, 1)) + { + dbus_free (d->name); + d->name = NULL; + return FALSE; + } + } + + /* Now the connection is active, move it between lists */ + _dbus_list_unlink (&d->connections->incomplete, + d->link_in_connection_list); + d->connections->n_incomplete -= 1; + _dbus_list_append_link (&d->connections->completed, + d->link_in_connection_list); + d->connections->n_completed += 1; + + _dbus_assert (d->connections->n_incomplete >= 0); + _dbus_assert (d->connections->n_completed > 0); return TRUE; } @@ -815,6 +1035,47 @@ bus_connection_get_name (DBusConnection *connection) return d->name; } +/** + * Check whether completing the passed-in connection would + * exceed limits, and if so set error and return #FALSE + */ +dbus_bool_t +bus_connections_check_limits (BusConnections *connections, + DBusConnection *requesting_completion, + DBusError *error) +{ + BusConnectionData *d; + unsigned long uid; + + d = BUS_CONNECTION_DATA (requesting_completion); + _dbus_assert (d != NULL); + + _dbus_assert (d->name == NULL); + + if (connections->n_completed >= + bus_context_get_max_completed_connections (connections->context)) + { + dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED, + "The maximum number of active connections has been reached"); + return FALSE; + } + + if (dbus_connection_get_unix_user (requesting_completion, &uid)) + { + if (get_connections_for_uid (connections, uid) >= + bus_context_get_max_connections_per_user (connections->context)) + { + dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED, + "The maximum number of active connections for UID %lu has been reached", + uid); + return FALSE; + } + } + + return TRUE; +} + + /* * Transactions * diff --git a/bus/connection.h b/bus/connection.h index c429007b..0d4d3a10 100644 --- a/bus/connection.h +++ b/bus/connection.h @@ -40,12 +40,18 @@ dbus_bool_t bus_connections_setup_connection (BusConnections * 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); +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); + dbus_bool_t bus_connection_is_active (DBusConnection *connection); diff --git a/bus/dispatch.c b/bus/dispatch.c index d1c19fd3..c1e67d6a 100644 --- a/bus/dispatch.c +++ b/bus/dispatch.c @@ -48,9 +48,6 @@ static dbus_bool_t send_one_message (DBusConnection *connection, void *data) { SendMessageData *d = data; - - if (!bus_connection_is_active (connection)) - return TRUE; if (!bus_context_check_security_policy (d->context, d->sender, @@ -93,7 +90,7 @@ bus_dispatch_broadcast_message (BusTransaction *transaction, d.transaction = transaction; d.error = &tmp_error; - bus_connections_foreach (connections, send_one_message, &d); + bus_connections_foreach_active (connections, send_one_message, &d); if (dbus_error_is_set (&tmp_error)) { diff --git a/bus/driver.c b/bus/driver.c index c52020b5..bc58f556 100644 --- a/bus/driver.c +++ b/bus/driver.c @@ -262,8 +262,23 @@ bus_driver_handle_hello (DBusConnection *connection, BusService *service; dbus_bool_t retval; BusRegistry *registry; + BusConnections *connections; _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + /* Note that when these limits are exceeded we don't disconnect the + * connection; we just sort of leave it hanging there until it times + * out or disconnects itself or is dropped due to the max number of + * incomplete connections. It's even OK if the connection wants to + * retry the hello message, we support that. + */ + connections = bus_connection_get_connections (connection); + if (!bus_connections_check_limits (connections, connection, + error)) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + return FALSE; + } if (!_dbus_string_init (&unique_name)) { diff --git a/dbus/dbus-connection.h b/dbus/dbus-connection.h index 6e8a9f15..c2206cd3 100644 --- a/dbus/dbus-connection.h +++ b/dbus/dbus-connection.h @@ -183,11 +183,11 @@ void* dbus_connection_get_data (DBusConnection *connection, void dbus_connection_set_change_sigpipe (dbus_bool_t will_modify_sigpipe); -void dbus_connection_set_max_message_size (DBusConnection *connection, - long size); -long dbus_connection_get_max_message_size (DBusConnection *connection); +void dbus_connection_set_max_message_size (DBusConnection *connection, + long size); +long dbus_connection_get_max_message_size (DBusConnection *connection); void dbus_connection_set_max_received_size (DBusConnection *connection, - long size); + long size); long dbus_connection_get_max_received_size (DBusConnection *connection); long dbus_connection_get_outgoing_size (DBusConnection *connection); diff --git a/dbus/dbus-list.c b/dbus/dbus-list.c index 5f4c67ca..235ed275 100644 --- a/dbus/dbus-list.c +++ b/dbus/dbus-list.c @@ -470,7 +470,15 @@ _dbus_list_remove_last (DBusList **list, return FALSE; } -static void +/** + * Removes the given link from the list, but doesn't + * free it. _dbus_list_remove_link() both removes the + * link and also frees it. + * + * @param list the list + * @param link the link in the list + */ +void _dbus_list_unlink (DBusList **list, DBusList *link) { @@ -487,6 +495,9 @@ _dbus_list_unlink (DBusList **list, if (*list == link) *list = link->next; } + + link->next = NULL; + link->prev = NULL; } /** diff --git a/dbus/dbus-list.h b/dbus/dbus-list.h index ad74dfd0..f3b37ef8 100644 --- a/dbus/dbus-list.h +++ b/dbus/dbus-list.h @@ -74,6 +74,8 @@ dbus_bool_t _dbus_list_copy (DBusList **list, int _dbus_list_get_length (DBusList **list); DBusList* _dbus_list_alloc_link (void *data); void _dbus_list_free_link (DBusList *link); +void _dbus_list_unlink (DBusList **list, + DBusList *link); void _dbus_list_append_link (DBusList **list, DBusList *link); void _dbus_list_prepend_link (DBusList **list, diff --git a/dbus/dbus-sysdeps.c b/dbus/dbus-sysdeps.c index 62aa0b4b..7673085f 100644 --- a/dbus/dbus-sysdeps.c +++ b/dbus/dbus-sysdeps.c @@ -470,8 +470,8 @@ _dbus_listen_unix_socket (const char *path, * But there doesn't seem to be a good way to do this. * * Just to be extra careful, I threw in the stat() - clearly - * the stat() can't *fix* any security issue, but it probably - * makes it harder to exploit. + * the stat() can't *fix* any security issue, but it at least + * avoids inadvertent/accidental data loss. */ { struct stat sb; @@ -21,10 +21,6 @@ - Activation needs some careful additional thinking-through. - - Recursive/composite/etc. types and associated API, see mailing list. - - - Configuration file (working on that now) - - Property list feature on message bus (list of properties associated with a connection). May also include message matching rules that involve the properties of the source or destination @@ -46,9 +42,6 @@ - We might consider returning a "no such operation" error in dbus-connection.c for unhandled messages. - - Abstract the user database, so you can use something other than the system password - database. - - The convenience functions in dbus-bus.h should perhaps have the signatures that they would have if they were autogenerated stubs. e.g. the acquire service function. We should also evaluate @@ -60,9 +53,6 @@ some basic spec'ing out of the GLib/Qt level stubs/skels stuff will be needed to understand the right approach. - - sync up DBusWatch and DBusTimeout so that handle_watch() is a method on DBusWatch - similar to the way timeouts work - - there are various bits of code to manage ref/unref of data slots, that should be merged into a generic facility @@ -85,7 +75,5 @@ - We have a limit on the number of messages a connection can send, but not on how many can be buffered for a given connection. - - make client serial and reply serial unsigned and add dbus_message_get_is_reply() - - other apps can send you a fake DBUS_MESSAGE_LOCAL_DISCONNECT; need to check for that and disallow it. |