From 29560adcc79a259a0be3511c056ee7453aa26c04 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Thu, 13 Mar 2003 00:56:43 +0000 Subject: [PATCH] 2003-03-12 Havoc Pennington Mega-patch that gets the message bus daemon initially handling out-of-memory. Work still needed. Also lots of random moving stuff to DBusError instead of ResultCode. * dbus/dbus-list.c (_dbus_list_length_is_one): new function * dbus/dbus-connection.c (dbus_connection_send_with_reply_and_block): use DBusError * dbus/dbus-bus.c: adapt to API changes, make it use DBusError not DBusResultCode * dbus/dbus-connection.c (dbus_connection_send): drop the result code here, as the only failure possible is OOM. * bus/connection.c (bus_connection_disconnect): rename bus_connection_disconnected as it's a notification only * bus/driver.c (bus_driver_handle_acquire_service): don't free "name" on get_args failure, should be done by get_args; don't disconnect client for bad args, just return an error. (bus_driver_handle_service_exists): ditto * bus/services.c (bus_services_list): NULL-terminate returned array * bus/driver.c (bus_driver_send_service_lost) (bus_driver_send_service_acquired): send messages from driver to a specific client to the client's unique name, not to the broadcast service. * dbus/dbus-message.c (decode_header_data): reject messages that contain no name field (_dbus_message_get_client_serial): rename to dbus_message_get_serial and make public (_dbus_message_set_serial): rename from set_client_serial (_dbus_message_set_reply_serial): make public (_dbus_message_get_reply_serial): make public * bus/connection.c (bus_connection_foreach): allow stopping iteration by returning FALSE from foreach function. * dbus/dbus-connection.c (dbus_connection_send_preallocated) (dbus_connection_free_preallocated_send) (dbus_connection_preallocate_send): new API for sending a message without possibility of malloc failure. (dbus_connection_send_message): rename to just dbus_connection_send (and same for whole function family) * dbus/dbus-errors.c (dbus_error_free): make this reinit the error * dbus/dbus-sysdeps.c (_dbus_exit): new function * bus/activation.c: handle/return errors * dbus/dbus-errors.h: add more DBUS_ERROR #define * dbus/dbus-sysdeps.c (_dbus_directory_open) (_dbus_file_get_contents) (_dbus_directory_get_next_file): use DBusError instead of DBusResultCode (_dbus_result_from_errno): move to this file --- ChangeLog | 62 ++ bus/activation.c | 231 +++++-- bus/activation.h | 5 +- bus/connection.c | 422 ++++++++++++- bus/connection.h | 26 +- bus/desktop-file.c | 180 ++++-- bus/dispatch.c | 281 +++++++-- bus/dispatch.h | 6 +- bus/driver.c | 680 ++++++++++++++------- bus/driver.h | 31 +- bus/main.c | 13 +- bus/services.c | 165 +++-- bus/services.h | 21 +- bus/utils.c | 2 + bus/utils.h | 5 +- dbus/dbus-address.c | 4 +- dbus/dbus-auth-script.c | 12 +- dbus/dbus-auth.c | 25 +- dbus/dbus-bus.c | 124 ++-- dbus/dbus-bus.h | 8 +- dbus/dbus-connection.c | 220 ++++--- dbus/dbus-connection.h | 34 +- dbus/dbus-errors.c | 44 +- dbus/dbus-errors.h | 16 + dbus/dbus-internals.c | 107 +--- dbus/dbus-internals.h | 5 + dbus/dbus-keyring.c | 12 +- dbus/dbus-list.c | 18 + dbus/dbus-list.h | 2 + dbus/dbus-message-builder.c | 11 +- dbus/dbus-message-internal.h | 17 +- dbus/dbus-message.c | 217 ++++--- dbus/dbus-message.h | 39 +- dbus/dbus-sha.c | 16 +- dbus/dbus-sysdeps.c | 321 ++++++++-- dbus/dbus-sysdeps.h | 30 +- glib/test-dbus-glib.c | 20 +- glib/test-thread-client.c | 9 +- test/bus-test.c | 56 +- test/data/valid-messages/dict-simple.message | 3 + test/data/valid-messages/dict.message | 5 +- test/data/valid-messages/lots-of-arguments.message | 3 + test/data/valid-messages/no-padding.message | 4 + test/data/valid-messages/simplest-manual.message | 3 + test/data/valid-messages/simplest.message | 3 + test/echo-client.c | 8 +- test/unbase64.c | 10 +- test/watch.c | 8 +- 48 files changed, 2605 insertions(+), 939 deletions(-) diff --git a/ChangeLog b/ChangeLog index 36f27b9..c7bc436 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,65 @@ +2003-03-12 Havoc Pennington + + Mega-patch that gets the message bus daemon initially handling + out-of-memory. Work still needed. Also lots of random + moving stuff to DBusError instead of ResultCode. + + * dbus/dbus-list.c (_dbus_list_length_is_one): new function + + * dbus/dbus-connection.c + (dbus_connection_send_with_reply_and_block): use DBusError + + * dbus/dbus-bus.c: adapt to API changes, make it use DBusError not + DBusResultCode + + * dbus/dbus-connection.c (dbus_connection_send): drop the result + code here, as the only failure possible is OOM. + + * bus/connection.c (bus_connection_disconnect): + rename bus_connection_disconnected as it's a notification only + + * bus/driver.c (bus_driver_handle_acquire_service): don't free + "name" on get_args failure, should be done by get_args; + don't disconnect client for bad args, just return an error. + (bus_driver_handle_service_exists): ditto + + * bus/services.c (bus_services_list): NULL-terminate returned array + + * bus/driver.c (bus_driver_send_service_lost) + (bus_driver_send_service_acquired): send messages from driver to a + specific client to the client's unique name, not to the broadcast + service. + + * dbus/dbus-message.c (decode_header_data): reject messages that + contain no name field + (_dbus_message_get_client_serial): rename to + dbus_message_get_serial and make public + (_dbus_message_set_serial): rename from set_client_serial + (_dbus_message_set_reply_serial): make public + (_dbus_message_get_reply_serial): make public + + * bus/connection.c (bus_connection_foreach): allow stopping + iteration by returning FALSE from foreach function. + + * dbus/dbus-connection.c (dbus_connection_send_preallocated) + (dbus_connection_free_preallocated_send) + (dbus_connection_preallocate_send): new API for sending a message + without possibility of malloc failure. + (dbus_connection_send_message): rename to just + dbus_connection_send (and same for whole function family) + + * dbus/dbus-errors.c (dbus_error_free): make this reinit the error + + * dbus/dbus-sysdeps.c (_dbus_exit): new function + + * bus/activation.c: handle/return errors + + * dbus/dbus-errors.h: add more DBUS_ERROR #define + + * dbus/dbus-sysdeps.c (_dbus_directory_open) (_dbus_file_get_contents) + (_dbus_directory_get_next_file): use DBusError instead of DBusResultCode + (_dbus_result_from_errno): move to this file + 2003-03-10 Anders Carlsson * dbus/dbus-marshal.c: diff --git a/bus/activation.c b/bus/activation.c index b5cec44..4e428bd 100644 --- a/bus/activation.c +++ b/bus/activation.c @@ -59,18 +59,24 @@ bus_activation_entry_free (BusActivationEntry *entry) } static dbus_bool_t -add_desktop_file_entry (BusDesktopFile *desktop_file) +add_desktop_file_entry (BusDesktopFile *desktop_file, + DBusError *error) { char *name, *exec; BusActivationEntry *entry; + + name = NULL; + exec = NULL; + entry = NULL; if (!bus_desktop_file_get_string (desktop_file, DBUS_SERVICE_SECTION, DBUS_SERVICE_NAME, &name)) { - _dbus_verbose ("No \""DBUS_SERVICE_NAME"\" key in .service file\n"); - return FALSE; + dbus_set_error (error, DBUS_ERROR_FAILED, + "No \""DBUS_SERVICE_NAME"\" key in .service file\n"); + goto failed; } if (!bus_desktop_file_get_string (desktop_file, @@ -78,57 +84,104 @@ add_desktop_file_entry (BusDesktopFile *desktop_file) DBUS_SERVICE_EXEC, &exec)) { - _dbus_verbose ("No \""DBUS_SERVICE_EXEC"\" key in .service file\n"); - - dbus_free (name); - return FALSE; + dbus_set_error (error, DBUS_ERROR_FAILED, + "No \""DBUS_SERVICE_EXEC"\" key in .service file\n"); + goto failed; } + /* FIXME we need a better-defined algorithm for which service file to + * pick than "whichever one is first in the directory listing" + */ if (_dbus_hash_table_lookup_string (activation_entries, name)) { - _dbus_verbose ("Service %s already exists in activation entry list\n", name); - dbus_free (name); - dbus_free (exec); - - return FALSE; + dbus_set_error (error, DBUS_ERROR_FAILED, + "Service %s already exists in activation entry list\n", name); + goto failed; + } + + entry = dbus_new0 (BusActivationEntry, 1); + if (entry == NULL) + { + BUS_SET_OOM (error); + goto failed; } - BUS_HANDLE_OOM (entry = dbus_malloc0 (sizeof (BusActivationEntry))); entry->name = name; entry->exec = exec; - BUS_HANDLE_OOM (_dbus_hash_table_insert_string (activation_entries, entry->name, entry)); + if (!_dbus_hash_table_insert_string (activation_entries, entry->name, entry)) + { + BUS_SET_OOM (error); + goto failed; + } _dbus_verbose ("Added \"%s\" to list of services\n", entry->name); return TRUE; + + failed: + dbus_free (name); + dbus_free (exec); + dbus_free (entry); + + return FALSE; } -static void -load_directory (const char *directory) +/* warning: this doesn't fully "undo" itself on failure, i.e. doesn't strip + * hash entries it already added. + */ +static dbus_bool_t +load_directory (const char *directory, + DBusError *error) { DBusDirIter *iter; DBusString dir, filename; - DBusResultCode result; - + DBusString full_path; + BusDesktopFile *desktop_file; + DBusError tmp_error; + _dbus_string_init_const (&dir, directory); + + iter = NULL; + desktop_file = NULL; - iter = _dbus_directory_open (&dir, &result); - if (iter == NULL) + if (!_dbus_string_init (&filename, _DBUS_INT_MAX)) { - _dbus_verbose ("Failed to open directory %s: &s\n", directory, - result); - return; + BUS_SET_OOM (error); + return FALSE; } - BUS_HANDLE_OOM (_dbus_string_init (&filename, _DBUS_INT_MAX)); + if (!_dbus_string_init (&full_path, _DBUS_INT_MAX)) + { + BUS_SET_OOM (error); + _dbus_string_free (&filename); + return FALSE; + } + + /* from this point it's safe to "goto failed" */ + + iter = _dbus_directory_open (&dir, error); + if (iter == NULL) + { + _dbus_verbose ("Failed to open directory %s: %s\n", + directory, error ? error->message : "unknown"); + goto failed; + } /* Now read the files */ - while (_dbus_directory_get_next_file (iter, &filename, &result)) + dbus_error_init (&tmp_error); + while (_dbus_directory_get_next_file (iter, &filename, &tmp_error)) { - DBusString full_path; - BusDesktopFile *desktop_file; - DBusError error; + _dbus_assert (!dbus_error_is_set (&tmp_error)); + + _dbus_string_set_length (&full_path, 0); + + if (!_dbus_string_append (&full_path, directory) || + !_dbus_concat_dir_and_file (&full_path, &filename)) + { + BUS_SET_OOM (error); + goto failed; + } if (!_dbus_string_ends_with_c_str (&filename, ".service")) { @@ -136,71 +189,133 @@ load_directory (const char *directory) _dbus_string_get_const_data (&filename, &filename_c); _dbus_verbose ("Skipping non-.service file %s\n", filename_c); - continue; + continue; } - BUS_HANDLE_OOM (_dbus_string_init (&full_path, _DBUS_INT_MAX)); - BUS_HANDLE_OOM (_dbus_string_append (&full_path, directory)); - - BUS_HANDLE_OOM (_dbus_concat_dir_and_file (&full_path, &filename)); + desktop_file = bus_desktop_file_load (&full_path, &tmp_error); - desktop_file = bus_desktop_file_load (&full_path, &error); - - if (!desktop_file) + if (desktop_file == NULL) { const char *full_path_c; _dbus_string_get_const_data (&full_path, &full_path_c); _dbus_verbose ("Could not load %s: %s\n", full_path_c, - error.message); - dbus_error_free (&error); - _dbus_string_free (&full_path); + tmp_error.message); + + if (dbus_error_has_name (&tmp_error, DBUS_ERROR_NO_MEMORY)) + { + dbus_move_error (&tmp_error, error); + goto failed; + } + + dbus_error_free (&tmp_error); continue; } - if (!add_desktop_file_entry (desktop_file)) + if (!add_desktop_file_entry (desktop_file, &tmp_error)) { const char *full_path_c; + bus_desktop_file_free (desktop_file); + desktop_file = NULL; + _dbus_string_get_const_data (&full_path, &full_path_c); - _dbus_verbose ("Could not add %s to activation entry list.\n", full_path_c); + _dbus_verbose ("Could not add %s to activation entry list: %s\n", + full_path_c, tmp_error.message); + + if (dbus_error_has_name (&tmp_error, DBUS_ERROR_NO_MEMORY)) + { + dbus_move_error (&tmp_error, error); + goto failed; + } + + dbus_error_free (&tmp_error); + continue; } + else + { + bus_desktop_file_free (desktop_file); + desktop_file = NULL; + continue; + } + } - bus_desktop_file_free (desktop_file); - _dbus_string_free (&full_path); + if (dbus_error_is_set (&tmp_error)) + { + dbus_move_error (&tmp_error, error); + goto failed; } + + return TRUE; + + failed: + _DBUS_ASSERT_ERROR_IS_SET (error); + + if (iter != NULL) + _dbus_directory_close (iter); + if (desktop_file) + bus_desktop_file_free (desktop_file); + _dbus_string_free (&filename); + _dbus_string_free (&full_path); + + return FALSE; } - -void -bus_activation_init (const char *address, - const char **directories) +dbus_bool_t +bus_activation_init (const char *address, + const char **directories, + DBusError *error) { int i; + _dbus_assert (server_address == NULL); + _dbus_assert (activation_entries == NULL); + /* FIXME: We should split up the server addresses. */ - BUS_HANDLE_OOM (server_address = _dbus_strdup (address)); + server_address = _dbus_strdup (address); + if (server_address == NULL) + { + BUS_SET_OOM (error); + goto failed; + } - BUS_HANDLE_OOM (activation_entries = _dbus_hash_table_new (DBUS_HASH_STRING, NULL, - (DBusFreeFunction)bus_activation_entry_free)); - - i = 0; + activation_entries = _dbus_hash_table_new (DBUS_HASH_STRING, NULL, + (DBusFreeFunction)bus_activation_entry_free); + if (activation_entries == NULL) + { + BUS_SET_OOM (error); + goto failed; + } /* Load service files */ + i = 0; while (directories[i] != NULL) { - load_directory (directories[i]); - i++; + if (!load_directory (directories[i], error)) + goto failed; + ++i; } + + return TRUE; + + failed: + dbus_free (server_address); + if (activation_entries) + _dbus_hash_table_unref (activation_entries); + + return FALSE; } static void child_setup (void *data) { - /* FIXME: Check return value in case of OOM */ - _dbus_setenv ("DBUS_ADDRESS", server_address); + /* If no memory, we simply have the child exit, so it won't try + * to connect to the wrong thing. + */ + if (!_dbus_setenv ("DBUS_ADDRESS", server_address)) + _dbus_exit (1); } dbus_bool_t @@ -220,6 +335,10 @@ bus_activation_activate_service (const char *service_name, return FALSE; } + /* FIXME we need to support a full command line, not just a single + * argv[0] + */ + /* Now try to spawn the process */ argv[0] = entry->exec; argv[1] = NULL; diff --git a/bus/activation.h b/bus/activation.h index 5f29871..e7a9cdf 100644 --- a/bus/activation.h +++ b/bus/activation.h @@ -26,8 +26,9 @@ #include -void bus_activation_init (const char *address, - const char **paths); +dbus_bool_t bus_activation_init (const char *address, + const char **paths, + DBusError *error); dbus_bool_t bus_activation_activate_service (const char *service_name, DBusError *error); diff --git a/bus/connection.c b/bus/connection.c index 40bbc32..ff671c5 100644 --- a/bus/connection.c +++ b/bus/connection.c @@ -24,34 +24,79 @@ #include "dispatch.h" #include "loop.h" #include "services.h" +#include "utils.h" #include +static void bus_connection_remove_transactions (DBusConnection *connection); + static int connection_data_slot; static DBusList *connections = NULL; typedef struct { + DBusConnection *connection; DBusList *services_owned; - char *name; + DBusList *transaction_messages; /**< Stuff we need to send as part of a transaction */ + DBusMessage *oom_message; + DBusPreallocatedSend *oom_preallocated; } BusConnectionData; #define BUS_CONNECTION_DATA(connection) (dbus_connection_get_data ((connection), connection_data_slot)) void -bus_connection_disconnect (DBusConnection *connection) +bus_connection_disconnected (DBusConnection *connection) { BusConnectionData *d; BusService *service; - + _dbus_warn ("Disconnected\n"); d = BUS_CONNECTION_DATA (connection); _dbus_assert (d != NULL); - /* Drop any service ownership */ - while ((service = _dbus_list_get_last (&d->services_owned))) - bus_service_remove_owner (service, connection); + /* Drop any service ownership. FIXME Unfortunately, this requires + * memory allocation and there doesn't seem to be a good way to + * 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). + */ + { + BusTransaction *transaction; + DBusError error; + + dbus_error_init (&error); + + transaction = NULL; + while (transaction == NULL) + { + transaction = bus_transaction_new (); + bus_wait_for_memory (); + } + + while ((service = _dbus_list_get_last (&d->services_owned))) + { + retry: + if (!bus_service_remove_owner (service, connection, + transaction, &error)) + { + if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY)) + { + dbus_error_free (&error); + bus_wait_for_memory (); + goto retry; + } + else + _dbus_assert_not_reached ("Removing service owner failed for non-memory-related reason"); + } + } + + bus_transaction_execute_and_free (transaction); + } bus_dispatch_remove_connection (connection); @@ -60,12 +105,14 @@ bus_connection_disconnect (DBusConnection *connection) NULL, NULL, connection, NULL); + + bus_connection_remove_transactions (connection); dbus_connection_set_data (connection, connection_data_slot, NULL, NULL); - _dbus_list_remove (&connections, connection); + _dbus_list_remove (&connections, connection); dbus_connection_unref (connection); } @@ -106,7 +153,14 @@ free_connection_data (void *data) /* services_owned should be NULL since we should be disconnected */ _dbus_assert (d->services_owned == NULL); + /* similarly */ + _dbus_assert (d->transaction_messages == NULL); + if (d->oom_preallocated) + dbus_connection_free_preallocated_send (d->connection, d->oom_preallocated); + if (d->oom_message) + dbus_message_unref (d->oom_message); + dbus_free (d->name); dbus_free (d); @@ -132,6 +186,8 @@ bus_connection_setup (DBusConnection *connection) if (d == NULL) return FALSE; + + d->connection = connection; if (!dbus_connection_set_data (connection, connection_data_slot, @@ -163,6 +219,88 @@ bus_connection_setup (DBusConnection *connection) return TRUE; } +/** + * Checks whether the connection is registered with the message bus. + * + * @param connection the connection + * @returns #TRUE if we're an active message bus participant + */ +dbus_bool_t +bus_connection_is_active (DBusConnection *connection) +{ + BusConnectionData *d; + + d = BUS_CONNECTION_DATA (connection); + + return d != NULL && d->name != NULL; +} + +dbus_bool_t +bus_connection_preallocate_oom_error (DBusConnection *connection) +{ + DBusMessage *message; + DBusPreallocatedSend *preallocated; + BusConnectionData *d; + + d = BUS_CONNECTION_DATA (connection); + + _dbus_assert (d != NULL); + + if (d->oom_preallocated != NULL) + return TRUE; + + preallocated = dbus_connection_preallocate_send (connection); + if (preallocated == NULL) + return FALSE; + + message = dbus_message_new (DBUS_SERVICE_DBUS, + DBUS_ERROR_NO_MEMORY); + if (message == NULL) + { + dbus_connection_free_preallocated_send (connection, preallocated); + return FALSE; + } + + /* set reply serial to placeholder value just so space is already allocated + * for it. + */ + if (!dbus_message_set_reply_serial (message, 14)) + { + dbus_connection_free_preallocated_send (connection, preallocated); + dbus_message_unref (message); + return FALSE; + } + + d->oom_message = message; + d->oom_preallocated = preallocated; + + return TRUE; +} + +void +bus_connection_send_oom_error (DBusConnection *connection, + DBusMessage *in_reply_to) +{ + BusConnectionData *d; + + d = BUS_CONNECTION_DATA (connection); + + _dbus_assert (d != NULL); + _dbus_assert (d->oom_message != NULL); + + /* should always succeed since we set it to a placeholder earlier */ + if (!dbus_message_set_reply_serial (d->oom_message, + dbus_message_get_serial (in_reply_to))) + _dbus_assert_not_reached ("Failed to set reply serial for preallocated oom message"); + + dbus_connection_send_preallocated (connection, d->oom_preallocated, + d->oom_message, NULL); + + dbus_message_unref (d->oom_message); + d->oom_message = NULL; + d->oom_preallocated = NULL; +} + dbus_bool_t bus_connection_add_owned_service (DBusConnection *connection, BusService *service) @@ -223,9 +361,277 @@ bus_connection_get_name (DBusConnection *connection) return d->name; } +/** + * Calls function on each connection; if the function returns + * #FALSE, stops iterating. + * + * @param function the function + * @param data data to pass to it as a second arg + */ void bus_connection_foreach (BusConnectionForeachFunction function, void *data) { - _dbus_list_foreach (&connections, (DBusForeachFunction)function, data); + DBusList *link; + + link = _dbus_list_get_first_link (&connections); + while (link != NULL) + { + DBusConnection *connection = link->data; + DBusList *next = _dbus_list_get_next_link (&connections, link); + + if (!(* function) (connection, data)) + break; + + link = next; + } +} + +typedef struct +{ + BusTransaction *transaction; + DBusMessage *message; + DBusPreallocatedSend *preallocated; +} MessageToSend; + +struct BusTransaction +{ + DBusList *connections; + +}; + +static void +message_to_send_free (DBusConnection *connection, + MessageToSend *to_send) +{ + if (to_send->message) + dbus_message_unref (to_send->message); + + if (to_send->preallocated) + dbus_connection_free_preallocated_send (connection, to_send->preallocated); + + dbus_free (to_send); +} + +BusTransaction* +bus_transaction_new (void) +{ + BusTransaction *transaction; + + transaction = dbus_new0 (BusTransaction, 1); + if (transaction == NULL) + return NULL; + + return transaction; +} + +dbus_bool_t +bus_transaction_send_message (BusTransaction *transaction, + DBusConnection *connection, + DBusMessage *message) +{ + MessageToSend *to_send; + BusConnectionData *d; + DBusList *link; + + if (!dbus_connection_get_is_connected (connection)) + return TRUE; /* silently ignore disconnected connections */ + + d = BUS_CONNECTION_DATA (connection); + _dbus_assert (d != NULL); + + to_send = dbus_new (MessageToSend, 1); + if (to_send == NULL) + { + return FALSE; + } + + to_send->preallocated = dbus_connection_preallocate_send (connection); + if (to_send->preallocated == NULL) + { + dbus_free (to_send); + return FALSE; + } + + dbus_message_ref (message); + to_send->message = message; + to_send->transaction = transaction; + + if (!_dbus_list_prepend (&d->transaction_messages, to_send)) + { + message_to_send_free (connection, to_send); + return FALSE; + } + + /* See if we already had this connection in the list + * for this transaction. If we have a pending message, + * then we should already be in transaction->connections + */ + link = _dbus_list_get_first_link (&d->transaction_messages); + _dbus_assert (link->data == to_send); + link = _dbus_list_get_next_link (&d->transaction_messages, link); + while (link != NULL) + { + MessageToSend *m = link->data; + DBusList *next = _dbus_list_get_next_link (&d->transaction_messages, link); + + if (m->transaction == transaction) + break; + + link = next; + } + + if (link == NULL) + { + if (!_dbus_list_prepend (&transaction->connections, connection)) + { + _dbus_list_remove (&d->transaction_messages, to_send); + message_to_send_free (connection, to_send); + return FALSE; + } + } + + return TRUE; +} + +static void +connection_cancel_transaction (DBusConnection *connection, + BusTransaction *transaction) +{ + DBusList *link; + BusConnectionData *d; + + d = BUS_CONNECTION_DATA (connection); + _dbus_assert (d != NULL); + + link = _dbus_list_get_first_link (&d->transaction_messages); + while (link != NULL) + { + MessageToSend *m = link->data; + DBusList *next = _dbus_list_get_next_link (&d->transaction_messages, link); + + if (m->transaction == transaction) + { + _dbus_list_remove_link (&d->transaction_messages, + link); + + message_to_send_free (connection, m); + } + + link = next; + } +} + +void +bus_transaction_cancel_and_free (BusTransaction *transaction) +{ + DBusConnection *connection; + + while ((connection = _dbus_list_pop_first (&transaction->connections))) + connection_cancel_transaction (connection, transaction); + + _dbus_assert (transaction->connections == NULL); + + dbus_free (transaction); +} + +static void +connection_execute_transaction (DBusConnection *connection, + BusTransaction *transaction) +{ + DBusList *link; + BusConnectionData *d; + + d = BUS_CONNECTION_DATA (connection); + _dbus_assert (d != NULL); + + /* Send the queue in order (FIFO) */ + link = _dbus_list_get_last_link (&d->transaction_messages); + while (link != NULL) + { + MessageToSend *m = link->data; + DBusList *prev = _dbus_list_get_prev_link (&d->transaction_messages, link); + + if (m->transaction == transaction) + { + _dbus_list_remove_link (&d->transaction_messages, + link); + + dbus_connection_send_preallocated (connection, + m->preallocated, + m->message, + NULL); + + m->preallocated = NULL; /* so we don't double-free it */ + + message_to_send_free (connection, m); + } + + link = prev; + } +} + +void +bus_transaction_execute_and_free (BusTransaction *transaction) +{ + /* For each connection in transaction->connections + * send the messages + */ + DBusConnection *connection; + + while ((connection = _dbus_list_pop_first (&transaction->connections))) + connection_execute_transaction (connection, transaction); + + _dbus_assert (transaction->connections == NULL); + + dbus_free (transaction); +} + +static void +bus_connection_remove_transactions (DBusConnection *connection) +{ + MessageToSend *to_send; + BusConnectionData *d; + + d = BUS_CONNECTION_DATA (connection); + _dbus_assert (d != NULL); + + while ((to_send = _dbus_list_get_first (&d->transaction_messages))) + { + /* only has an effect for the first MessageToSend listing this transaction */ + _dbus_list_remove (&to_send->transaction->connections, + connection); + + _dbus_list_remove (&d->transaction_messages, to_send); + message_to_send_free (connection, to_send); + } +} + +/** + * Converts the DBusError to a message reply + */ +dbus_bool_t +bus_transaction_send_error_reply (BusTransaction *transaction, + DBusConnection *connection, + const DBusError *error, + DBusMessage *in_reply_to) +{ + DBusMessage *reply; + + _dbus_assert (error != NULL); + _DBUS_ASSERT_ERROR_IS_SET (error); + + reply = dbus_message_new_error_reply (in_reply_to, + error->name, + error->message); + if (reply == NULL) + return FALSE; + + if (!bus_transaction_send_message (transaction, connection, reply)) + { + dbus_message_unref (reply); + return FALSE; + } + + return TRUE; } diff --git a/bus/connection.h b/bus/connection.h index 04ab1f0..a7a448a 100644 --- a/bus/connection.h +++ b/bus/connection.h @@ -27,13 +27,19 @@ #include #include "services.h" -typedef void (* BusConnectionForeachFunction) (DBusConnection *connection, - void *data); +typedef dbus_bool_t (* BusConnectionForeachFunction) (DBusConnection *connection, + void *data); dbus_bool_t bus_connection_init (void); dbus_bool_t bus_connection_setup (DBusConnection *connection); +dbus_bool_t bus_connection_is_active (DBusConnection *connection); + +dbus_bool_t bus_connection_preallocate_oom_error (DBusConnection *connection); +void bus_connection_send_oom_error (DBusConnection *connection, + DBusMessage *in_reply_to); + /* called by services.c */ dbus_bool_t bus_connection_add_owned_service (DBusConnection *connection, BusService *service); @@ -47,8 +53,20 @@ const char *bus_connection_get_name (DBusConnection *connection); void bus_connection_foreach (BusConnectionForeachFunction function, void *data); -/* called by dispatch.c */ -void bus_connection_disconnect (DBusConnection *connection); +/* called by dispatch.c when the connection is dropped */ +void bus_connection_disconnected (DBusConnection *connection); + +/* transaction API so we can send or not send a block of messages as a whole */ +BusTransaction* bus_transaction_new (void); +dbus_bool_t bus_transaction_send_message (BusTransaction *transaction, + DBusConnection *connection, + DBusMessage *message); +dbus_bool_t bus_transaction_send_error_reply (BusTransaction *transaction, + DBusConnection *connection, + const DBusError *error, + DBusMessage *in_reply_to); +void bus_transaction_cancel_and_free (BusTransaction *transaction); +void bus_transaction_execute_and_free (BusTransaction *transaction); #endif /* BUS_CONNECTION_H */ diff --git a/bus/desktop-file.c b/bus/desktop-file.c index 0ab6afc..65a0d76 100644 --- a/bus/desktop-file.c +++ b/bus/desktop-file.c @@ -125,7 +125,7 @@ bus_desktop_file_free (BusDesktopFile *desktop_file) dbus_free (desktop_file); } -static void +static dbus_bool_t grow_lines_in_section (BusDesktopFileSection *section) { BusDesktopFileLine *lines; @@ -137,14 +137,19 @@ grow_lines_in_section (BusDesktopFileSection *section) else new_n_lines = section->n_allocated_lines*2; - BUS_HANDLE_OOM (lines = dbus_realloc (section->lines, - sizeof (BusDesktopFileLine) * new_n_lines)); - section->lines = lines; + lines = dbus_realloc (section->lines, + sizeof (BusDesktopFileLine) * new_n_lines); + + if (lines == NULL) + return FALSE; + section->lines = lines; section->n_allocated_lines = new_n_lines; + + return TRUE; } -static void +static dbus_bool_t grow_sections (BusDesktopFile *desktop_file) { int new_n_sections; @@ -155,21 +160,36 @@ grow_sections (BusDesktopFile *desktop_file) else new_n_sections = desktop_file->n_allocated_sections*2; - BUS_HANDLE_OOM (sections = dbus_realloc (desktop_file->sections, - sizeof (BusDesktopFileSection) * new_n_sections)); + sections = dbus_realloc (desktop_file->sections, + sizeof (BusDesktopFileSection) * new_n_sections); + if (sections == NULL) + return FALSE; + desktop_file->sections = sections; desktop_file->n_allocated_sections = new_n_sections; + + return TRUE; } static char * -unescape_string (const DBusString *str, int pos, int end_pos) +unescape_string (BusDesktopFileParser *parser, + const DBusString *str, + int pos, + int end_pos, + DBusError *error) { char *retval, *q; /* len + 1 is enough, because unescaping never makes the - * string longer */ - BUS_HANDLE_OOM (retval = dbus_malloc (end_pos - pos + 1)); + * string longer + */ + retval = dbus_malloc (end_pos - pos + 1); + if (retval == NULL) + { + BUS_SET_OOM (error); + return NULL; + } q = retval; @@ -179,6 +199,8 @@ unescape_string (const DBusString *str, int pos, int end_pos) { /* Found an embedded null */ dbus_free (retval); + report_error (parser, "Text to be unescaped contains embedded nul", + BUS_DESKTOP_PARSE_ERROR_INVALID_ESCAPES, error); return NULL; } @@ -190,6 +212,8 @@ unescape_string (const DBusString *str, int pos, int end_pos) { /* Escape at end of string */ dbus_free (retval); + report_error (parser, "Text to be unescaped ended in \\", + BUS_DESKTOP_PARSE_ERROR_INVALID_ESCAPES, error); return NULL; } @@ -213,7 +237,9 @@ unescape_string (const DBusString *str, int pos, int end_pos) default: /* Invalid escape code */ dbus_free (retval); - return NULL; + report_error (parser, "Text to be unescaped had invalid escape sequence", + BUS_DESKTOP_PARSE_ERROR_INVALID_ESCAPES, error); + return NULL; } pos++; } @@ -235,20 +261,34 @@ new_section (BusDesktopFile *desktop_file, const char *name) { int n; + char *name_copy; if (desktop_file->n_allocated_sections == desktop_file->n_sections) - grow_sections (desktop_file); - - n = desktop_file->n_sections++; + { + if (!grow_sections (desktop_file)) + return NULL; + } - BUS_HANDLE_OOM (desktop_file->sections[n].section_name = _dbus_strdup (name)); + name_copy = _dbus_strdup (name); + if (name_copy == NULL) + return NULL; + + n = desktop_file->n_sections + 1; + desktop_file->sections[n].section_name = name_copy; desktop_file->sections[n].n_lines = 0; desktop_file->sections[n].lines = NULL; desktop_file->sections[n].n_allocated_lines = 0; - grow_lines_in_section (&desktop_file->sections[n]); + if (!grow_lines_in_section (&desktop_file->sections[n])) + { + dbus_free (desktop_file->sections[n].section_name); + desktop_file->sections[n].section_name = NULL; + return NULL; + } + desktop_file->n_sections = n; + return &desktop_file->sections[n]; } @@ -277,7 +317,10 @@ new_line (BusDesktopFileParser *parser) section = &parser->desktop_file->sections[parser->current_section]; if (section->n_allocated_lines == section->n_lines) - grow_lines_in_section (section); + { + if (!grow_lines_in_section (section)) + return NULL; + } line = §ion->lines[section->n_lines++]; @@ -358,11 +401,12 @@ parse_section_start (BusDesktopFileParser *parser, DBusError *error) return FALSE; } - section_name = unescape_string (&parser->data, parser->pos + 1, line_end - 1); + section_name = unescape_string (parser, + &parser->data, parser->pos + 1, line_end - 1, + error); if (section_name == NULL) { - report_error (parser, "Invalid escaping in section name", BUS_DESKTOP_PARSE_ERROR_INVALID_ESCAPES, error); parser_free (parser); return FALSE; } @@ -450,20 +494,39 @@ parse_key_value (BusDesktopFileParser *parser, DBusError *error) value_start = p; - value = unescape_string (&parser->data, value_start, line_end); + value = unescape_string (parser, &parser->data, value_start, line_end, error); if (value == NULL) { - report_error (parser, "Invalid escaping in value", BUS_DESKTOP_PARSE_ERROR_INVALID_ESCAPES, error); parser_free (parser); return FALSE; } line = new_line (parser); - - BUS_HANDLE_OOM (_dbus_string_init (&key, key_end - key_start)); - BUS_HANDLE_OOM (_dbus_string_copy_len (&parser->data, key_start, key_end - key_start, - &key, 0)); - BUS_HANDLE_OOM (_dbus_string_steal_data (&key, &tmp)); + if (line == NULL) + { + parser_free (parser); + return FALSE; + } + + if (!_dbus_string_init (&key, key_end - key_start)) + { + parser_free (parser); + return FALSE; + } + + if (!_dbus_string_copy_len (&parser->data, key_start, key_end - key_start, + &key, 0)) + { + parser_free (parser); + return FALSE; + } + + if (!_dbus_string_steal_data (&key, &tmp)) + { + parser_free (parser); + return FALSE; + } + _dbus_string_free (&key); line->key = tmp; @@ -491,11 +554,11 @@ report_error (BusDesktopFileParser *parser, section_name = parser->desktop_file->sections[parser->current_section].section_name; if (section_name) - BUS_HANDLE_OOM (dbus_set_error (error, error_name, - "Error in section %s at line %d: %s\n", section_name, parser->line_num, message)); + dbus_set_error (error, error_name, + "Error in section %s at line %d: %s\n", section_name, parser->line_num, message); else - BUS_HANDLE_OOM (dbus_set_error (error, error_name, - "Error at line %d: %s\n", parser->line_num, message)); + dbus_set_error (error, error_name, + "Error at line %d: %s\n", parser->line_num, message); } #if 0 @@ -519,39 +582,52 @@ dump_desktop_file (BusDesktopFile *file) } #endif -BusDesktopFile * +BusDesktopFile* bus_desktop_file_load (DBusString *filename, DBusError *error) { DBusString str; - DBusResultCode result_code; BusDesktopFileParser parser; + DBusStat sb; - /* FIXME: Check file size so we don't try to load a ridicously large file. */ + /* Clearly there's a race here, but it's just to make it unlikely + * that we do something silly, we still handle doing it below. + */ + if (!_dbus_stat (filename, &sb, error)) + return NULL; - BUS_HANDLE_OOM (_dbus_string_init (&str, _DBUS_INT_MAX)); + if (sb.size > _DBUS_ONE_KILOBYTE * 128) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "Desktop file size (%ld bytes) is too large", (long) sb.size); + return NULL; + } - BUS_HANDLE_OOM ((result_code = _dbus_file_get_contents (&str, filename)) != - DBUS_RESULT_NO_MEMORY); + if (!_dbus_string_init (&str, _DBUS_INT_MAX)) + return NULL; - if (result_code != DBUS_RESULT_SUCCESS) + if (!_dbus_file_get_contents (&str, filename, error)) { _dbus_string_free (&str); - - /* FIXME: Set error */ return NULL; } if (!_dbus_string_validate_utf8 (&str, 0, _dbus_string_get_length (&str))) { _dbus_string_free (&str); - - /* FIXME: Set error */ + dbus_set_error (error, DBUS_ERROR_FAILED, + "invalid UTF-8"); + return NULL; + } + + parser.desktop_file = dbus_new0 (BusDesktopFile, 1); + if (parser.desktop_file == NULL) + { + _dbus_string_free (&str); + BUS_SET_OOM (error); return NULL; } - BUS_HANDLE_OOM (parser.desktop_file = dbus_malloc0 (sizeof (BusDesktopFile))); - parser.data = str; parser.line_num = 1; parser.pos = 0; @@ -563,7 +639,10 @@ bus_desktop_file_load (DBusString *filename, if (_dbus_string_get_byte (&parser.data, parser.pos) == '[') { if (!parse_section_start (&parser, error)) - return NULL; + { + _dbus_string_free (&parser.data); + return NULL; + } } else if (is_blank_line (&parser) || _dbus_string_get_byte (&parser.data, parser.pos) == '#') @@ -571,7 +650,10 @@ bus_desktop_file_load (DBusString *filename, else { if (!parse_key_value (&parser, error)) - return NULL; + { + _dbus_string_free (&parser.data); + return NULL; + } } } @@ -661,7 +743,13 @@ bus_desktop_file_get_string (BusDesktopFile *desktop_file, if (!bus_desktop_file_get_raw (desktop_file, section, keyname, &raw)) return FALSE; - BUS_HANDLE_OOM (*val = _dbus_strdup (raw)); + *val = _dbus_strdup (raw); + + /* FIXME we don't distinguish "key not found" from "out of memory" here, + * which is broken. + */ + if (*val == NULL) + return FALSE; return TRUE; } diff --git a/bus/dispatch.c b/bus/dispatch.c index 76e10a9..d9fe81a 100644 --- a/bus/dispatch.c +++ b/bus/dispatch.c @@ -30,23 +30,110 @@ static int message_handler_slot; -static void +typedef struct +{ + DBusMessage *message; + BusTransaction *transaction; + DBusError *error; +} SendMessageData; + +static dbus_bool_t send_one_message (DBusConnection *connection, void *data) { - /* Only send messages to registered connections */ - if (bus_connection_get_name (connection) == NULL) - return; + SendMessageData *d = data; - BUS_HANDLE_OOM (dbus_connection_send_message (connection, data, NULL, NULL)); + if (!bus_connection_is_active (connection)) + return TRUE; + + if (!bus_transaction_send_message (d->transaction, + connection, + d->message)) + { + BUS_SET_OOM (d->error); + return FALSE; + } + + return TRUE; } -void -bus_dispatch_broadcast_message (DBusMessage *message) +dbus_bool_t +bus_dispatch_broadcast_message (BusTransaction *transaction, + DBusMessage *message, + DBusError *error) { - _dbus_assert (dbus_message_get_sender (message) != NULL); - - bus_connection_foreach (send_one_message, message); + DBusError tmp_error; + SendMessageData d; + _dbus_assert (dbus_message_get_sender (message) != NULL); + + dbus_error_init (&tmp_error); + d.message = message; + d.transaction = transaction; + d.error = &tmp_error; + bus_connection_foreach (send_one_message, &d); + + if (dbus_error_is_set (&tmp_error)) + { + dbus_move_error (&tmp_error, error); + return FALSE; + } + else + return TRUE; +} + +static dbus_bool_t +send_service_nonexistent_error (BusTransaction *transaction, + DBusConnection *connection, + const char *service_name, + DBusMessage *in_reply_to, + DBusError *error) +{ + DBusMessage *error_reply; + DBusString error_message; + const char *error_str; + + /* Trying to send a message to a non-existant service, + * bounce back an error message. + */ + + if (!_dbus_string_init (&error_message, _DBUS_INT_MAX)) + { + BUS_SET_OOM (error); + return FALSE; + } + + if (!_dbus_string_append (&error_message, "Service \"") || + !_dbus_string_append (&error_message, service_name) || + !_dbus_string_append (&error_message, "does not exist")) + { + _dbus_string_free (&error_message); + BUS_SET_OOM (error); + return FALSE; + } + + _dbus_string_get_const_data (&error_message, &error_str); + error_reply = dbus_message_new_error_reply (in_reply_to, + DBUS_ERROR_SERVICE_DOES_NOT_EXIST, + error_str); + + _dbus_string_free (&error_message); + + if (error_reply == NULL) + { + BUS_SET_OOM (error); + return FALSE; + } + + if (!bus_transaction_send_message (transaction, connection, error_reply)) + { + dbus_message_unref (error_reply); + BUS_SET_OOM (error); + return FALSE; + } + + dbus_message_unref (error_reply); + + return TRUE; } static DBusHandlerResult @@ -56,76 +143,164 @@ bus_dispatch_message_handler (DBusMessageHandler *handler, void *user_data) { const char *sender, *service_name, *message_name; + DBusError error; + BusTransaction *transaction; + + transaction = NULL; + dbus_error_init (&error); - /* Assign a sender to the message */ - sender = bus_connection_get_name (connection); - BUS_HANDLE_OOM (dbus_message_set_sender (message, sender)); + /* If we can't even allocate an OOM error, we just go to sleep + * until we can. + */ + while (!bus_connection_preallocate_oom_error (connection)) + bus_wait_for_memory (); + + /* Ref connection in case we disconnect it at some point in here */ + dbus_connection_ref (connection); service_name = dbus_message_get_service (message); message_name = dbus_message_get_name (message); + + _dbus_assert (message_name != NULL); /* DBusMessageLoader is supposed to check this */ + + /* If service_name is NULL, this is a message to the bus daemon, not intended + * to actually go "on the bus"; e.g. a peer-to-peer ping. Handle these + * immediately, especially disconnection messages. + */ + if (service_name == NULL) + { + if (strcmp (message_name, DBUS_MESSAGE_LOCAL_DISCONNECT) == 0) + bus_connection_disconnected (connection); + + /* DBusConnection also handles some of these automatically, we leave + * it to do so. + */ + goto out; + } + + _dbus_assert (service_name != NULL); /* this message is intended for bus routing */ - /* TODO: Crashes if service_name == NULL */ + /* Create our transaction */ + transaction = bus_transaction_new (); + if (transaction == NULL) + { + BUS_SET_OOM (&error); + goto out; + } - /* See if the message is to the driver */ - if (message_name && strcmp (message_name, DBUS_MESSAGE_LOCAL_DISCONNECT) == 0) + /* Assign a sender to the message */ + if (bus_connection_is_active (connection)) { - bus_connection_disconnect (connection); + sender = bus_connection_get_name (connection); + _dbus_assert (sender != NULL); + + if (!dbus_message_set_sender (message, sender)) + { + BUS_SET_OOM (&error); + goto out; + } } - else if (strcmp (service_name, DBUS_SERVICE_DBUS) == 0) + + if (strcmp (service_name, DBUS_SERVICE_DBUS) == 0) /* to bus driver */ { - bus_driver_handle_message (connection, message); + if (!bus_driver_handle_message (connection, transaction, message, &error)) + goto out; } - else if (sender == NULL) + else if (!bus_connection_is_active (connection)) /* clients must talk to bus driver first */ { _dbus_verbose ("Received message from non-registered client. Disconnecting.\n"); dbus_connection_disconnect (connection); } - else if (strcmp (service_name, DBUS_SERVICE_BROADCAST) == 0) + /* FIXME what if we un-special-case this service and just have a flag + * on services that all service owners will get messages to it, not just + * the primary owner. + */ + else if (strcmp (service_name, DBUS_SERVICE_BROADCAST) == 0) /* spam! */ { - bus_dispatch_broadcast_message (message); + if (!bus_dispatch_broadcast_message (transaction, message, &error)) + goto out; } - else + else /* route to named service */ { DBusString service_string; BusService *service; _dbus_string_init_const (&service_string, service_name); - service = bus_service_lookup (&service_string, FALSE); - - if (!service) - { - DBusMessage *error_reply; - DBusString error_message; - const char *error_str; - - /* Trying to send a message to a non-existant service, - bounce back an error message. */ - - BUS_HANDLE_OOM (_dbus_string_init (&error_message, _DBUS_INT_MAX)); - - BUS_HANDLE_OOM (_dbus_string_append (&error_message, "Service \"")); - BUS_HANDLE_OOM (_dbus_string_append (&error_message, service_name)); - BUS_HANDLE_OOM (_dbus_string_append (&error_message, "does not exist")); + service = bus_service_lookup (&service_string); - _dbus_string_get_const_data (&error_message, &error_str); - BUS_HANDLE_OOM (error_reply = dbus_message_new_error_reply (message, DBUS_ERROR_SERVICE_DOES_NOT_EXIST, - error_str)); - _dbus_string_free (&error_message); + if (service == NULL) + { + if (!send_service_nonexistent_error (transaction, connection, + service_name, + message, &error)) + goto out; + } + else + { + _dbus_assert (bus_service_get_primary_owner (service) != NULL); + + /* Dispatch the message */ + if (!bus_transaction_send_message (transaction, + bus_service_get_primary_owner (service), + message)) + { + BUS_SET_OOM (&error); + goto out; + } + } + } + + out: + if (dbus_error_is_set (&error)) + { + if (!dbus_connection_get_is_connected (connection)) + { + /* If we disconnected it, we won't bother to send it any error + * messages. + */ + } + else if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY)) + { + bus_connection_send_oom_error (connection, message); - /* Dispatch the message */ - BUS_HANDLE_OOM (dbus_connection_send_message (connection, error_reply, NULL, NULL)); - dbus_message_unref (error_reply); - } + /* cancel transaction due to OOM */ + if (transaction != NULL) + { + bus_transaction_cancel_and_free (transaction); + transaction = NULL; + } + } else - { - _dbus_assert (bus_service_get_primary_owner (service) != NULL); + { + /* Try to send the real error, if no mem to do that, send + * the OOM error + */ + _dbus_assert (transaction != NULL); + + if (!bus_transaction_send_error_reply (transaction, connection, + &error, message)) + { + bus_connection_send_oom_error (connection, message); + + /* cancel transaction due to OOM */ + if (transaction != NULL) + { + bus_transaction_cancel_and_free (transaction); + transaction = NULL; + } + } + } - /* Dispatch the message */ - BUS_HANDLE_OOM (dbus_connection_send_message (bus_service_get_primary_owner (service), - message, NULL, NULL)); - } + dbus_error_free (&error); } + if (transaction != NULL) + { + bus_transaction_execute_and_free (transaction); + } + + dbus_connection_unref (connection); + return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS; } diff --git a/bus/dispatch.h b/bus/dispatch.h index 2fe3479..c24170d 100644 --- a/bus/dispatch.h +++ b/bus/dispatch.h @@ -25,10 +25,12 @@ #define BUS_DISPATCH_H #include +#include "connection.h" dbus_bool_t bus_dispatch_add_connection (DBusConnection *connection); void bus_dispatch_remove_connection (DBusConnection *connection); -void bus_dispatch_broadcast_message (DBusMessage *message); - +dbus_bool_t bus_dispatch_broadcast_message (BusTransaction *transaction, + DBusMessage *message, + DBusError *error); #endif /* BUS_DISPATCH_H */ diff --git a/bus/driver.c b/bus/driver.c index 80478e4..4698559 100644 --- a/bus/driver.c +++ b/bus/driver.c @@ -31,79 +31,171 @@ #include #include -static void bus_driver_send_welcome_message (DBusConnection *connection, - DBusMessage *hello_message); - -void -bus_driver_send_service_deleted (const char *service_name) +static dbus_bool_t bus_driver_send_welcome_message (DBusConnection *connection, + DBusMessage *hello_message, + BusTransaction *transaction, + DBusError *error); + +dbus_bool_t +bus_driver_send_service_deleted (const char *service_name, + BusTransaction *transaction, + DBusError *error) { DBusMessage *message; - + dbus_bool_t retval; + _dbus_verbose ("sending service deleted: %s\n", service_name); - BUS_HANDLE_OOM (message = dbus_message_new (DBUS_SERVICE_BROADCAST, - DBUS_MESSAGE_SERVICE_DELETED)); + message = dbus_message_new (DBUS_SERVICE_BROADCAST, + DBUS_MESSAGE_SERVICE_DELETED); + if (message == NULL) + { + BUS_SET_OOM (error); + return FALSE; + } - BUS_HANDLE_OOM (dbus_message_set_sender (message, DBUS_SERVICE_DBUS)); + if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS) || + !dbus_message_append_args (message, + DBUS_TYPE_STRING, service_name, + 0)) + { + dbus_message_unref (message); + BUS_SET_OOM (error); + return FALSE; + } - BUS_HANDLE_OOM (dbus_message_append_args (message, - DBUS_TYPE_STRING, service_name, - 0)); - bus_dispatch_broadcast_message (message); - dbus_message_unref (message); + retval = bus_dispatch_broadcast_message (transaction, message, error); + dbus_message_unref (message); + + return retval; } -void -bus_driver_send_service_created (const char *service_name) +dbus_bool_t +bus_driver_send_service_created (const char *service_name, + BusTransaction *transaction, + DBusError *error) { DBusMessage *message; - - BUS_HANDLE_OOM (message = dbus_message_new (DBUS_SERVICE_BROADCAST, - DBUS_MESSAGE_SERVICE_CREATED)); + dbus_bool_t retval; + + message = dbus_message_new (DBUS_SERVICE_BROADCAST, + DBUS_MESSAGE_SERVICE_CREATED); + if (message == NULL) + { + BUS_SET_OOM (error); + return FALSE; + } - BUS_HANDLE_OOM (dbus_message_set_sender (message, DBUS_SERVICE_DBUS)); + if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS)) + { + dbus_message_unref (message); + BUS_SET_OOM (error); + return FALSE; + } - BUS_HANDLE_OOM (dbus_message_append_args (message, - DBUS_TYPE_STRING, service_name, - 0)); - bus_dispatch_broadcast_message (message); + if (!dbus_message_append_args (message, + DBUS_TYPE_STRING, service_name, + 0)) + { + dbus_message_unref (message); + BUS_SET_OOM (error); + return FALSE; + } + + retval = bus_dispatch_broadcast_message (transaction, message, error); dbus_message_unref (message); + + return retval; } -void +dbus_bool_t bus_driver_send_service_lost (DBusConnection *connection, - const char *service_name) + const char *service_name, + BusTransaction *transaction, + DBusError *error) { DBusMessage *message; - BUS_HANDLE_OOM (message = dbus_message_new (DBUS_SERVICE_BROADCAST, - DBUS_MESSAGE_SERVICE_LOST)); + message = dbus_message_new (bus_connection_get_name (connection), + DBUS_MESSAGE_SERVICE_LOST); + if (message == NULL) + { + BUS_SET_OOM (error); + return FALSE; + } - BUS_HANDLE_OOM (dbus_message_set_sender (message, DBUS_SERVICE_DBUS)); - BUS_HANDLE_OOM (dbus_message_append_args (message, - DBUS_TYPE_STRING, service_name, - 0)); - BUS_HANDLE_OOM (dbus_connection_send_message (connection, message, NULL, NULL)); + if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS)) + { + dbus_message_unref (message); + BUS_SET_OOM (error); + return FALSE; + } - dbus_message_unref (message); + if (!dbus_message_append_args (message, + DBUS_TYPE_STRING, service_name, + 0)) + { + dbus_message_unref (message); + BUS_SET_OOM (error); + return FALSE; + } + + if (!bus_transaction_send_message (transaction, connection, message)) + { + dbus_message_unref (message); + BUS_SET_OOM (error); + return FALSE; + } + else + { + dbus_message_unref (message); + return TRUE; + } } -void +dbus_bool_t bus_driver_send_service_acquired (DBusConnection *connection, - const char *service_name) + const char *service_name, + BusTransaction *transaction, + DBusError *error) { DBusMessage *message; - BUS_HANDLE_OOM (message = dbus_message_new (DBUS_SERVICE_BROADCAST, - DBUS_MESSAGE_SERVICE_ACQUIRED)); + message = dbus_message_new (bus_connection_get_name (connection), + DBUS_MESSAGE_SERVICE_ACQUIRED); + if (message == NULL) + { + BUS_SET_OOM (error); + return FALSE; + } - BUS_HANDLE_OOM (dbus_message_set_sender (message, DBUS_SERVICE_DBUS)); - BUS_HANDLE_OOM (dbus_message_append_args (message, - DBUS_TYPE_STRING, service_name, - 0)); - BUS_HANDLE_OOM (dbus_connection_send_message (connection, message, NULL, NULL)); + if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS)) + { + dbus_message_unref (message); + BUS_SET_OOM (error); + return FALSE; + } - dbus_message_unref (message); + if (!dbus_message_append_args (message, + DBUS_TYPE_STRING, service_name, + 0)) + { + dbus_message_unref (message); + BUS_SET_OOM (error); + return FALSE; + } + + if (!bus_transaction_send_message (transaction, connection, message)) + { + dbus_message_unref (message); + BUS_SET_OOM (error); + return FALSE; + } + else + { + dbus_message_unref (message); + return TRUE; + } } static dbus_bool_t @@ -154,7 +246,7 @@ create_unique_client_name (DBusString *str) next_minor_number += 1; /* Check if a client with the name exists */ - if (bus_service_lookup (str, FALSE) == NULL) + if (bus_service_lookup (str) == NULL) break; /* drop the number again, try the next one. */ @@ -164,35 +256,65 @@ create_unique_client_name (DBusString *str) return TRUE; } -static void +static dbus_bool_t bus_driver_handle_hello (DBusConnection *connection, - DBusMessage *message) + BusTransaction *transaction, + DBusMessage *message, + DBusError *error) { DBusString unique_name; BusService *service; + dbus_bool_t retval; + + if (!_dbus_string_init (&unique_name, _DBUS_INT_MAX)) + { + BUS_SET_OOM (error); + return FALSE; + } - BUS_HANDLE_OOM (_dbus_string_init (&unique_name, _DBUS_INT_MAX)); - BUS_HANDLE_OOM (create_unique_client_name (&unique_name)); + retval = FALSE; + + if (!create_unique_client_name (&unique_name)) + { + BUS_SET_OOM (error); + goto out_0; + } - BUS_HANDLE_OOM (bus_connection_set_name (connection, &unique_name)); - BUS_HANDLE_OOM (dbus_message_set_sender (message, - bus_connection_get_name (connection))); + if (!bus_connection_set_name (connection, &unique_name)) + { + BUS_SET_OOM (error); + goto out_0; + } + + if (!dbus_message_set_sender (message, + bus_connection_get_name (connection))) + { + BUS_SET_OOM (error); + goto out_0; + } - BUS_HANDLE_OOM (bus_driver_send_welcome_message (connection, message)); + if (!bus_driver_send_welcome_message (connection, message, transaction, error)) + goto out_0; /* Create the service */ - BUS_HANDLE_OOM (service = bus_service_lookup (&unique_name, TRUE)); - bus_service_set_prohibit_replacement (service, TRUE); + service = bus_service_ensure (&unique_name, connection, transaction, error); + if (service == NULL) + goto out_0; - /* Add the connection as the owner */ - BUS_HANDLE_OOM (bus_service_add_owner (service, connection)); + bus_service_set_prohibit_replacement (service, TRUE); + retval = TRUE; + + out_0: _dbus_string_free (&unique_name); + return retval; } -static void +static dbus_bool_t bus_driver_send_welcome_message (DBusConnection *connection, - DBusMessage *hello_message) + DBusMessage *hello_message, + BusTransaction *transaction, + DBusError *error) { DBusMessage *welcome; const char *name; @@ -200,209 +322,330 @@ bus_driver_send_welcome_message (DBusConnection *connection, name = bus_connection_get_name (connection); _dbus_assert (name != NULL); - BUS_HANDLE_OOM (welcome = dbus_message_new_reply (hello_message)); - - BUS_HANDLE_OOM (dbus_message_set_sender (welcome, DBUS_SERVICE_DBUS)); - - BUS_HANDLE_OOM (dbus_message_append_args (welcome, - DBUS_TYPE_STRING, name, - NULL)); + welcome = dbus_message_new_reply (hello_message); + if (welcome == NULL) + { + BUS_SET_OOM (error); + return FALSE; + } - BUS_HANDLE_OOM (dbus_connection_send_message (connection, welcome, NULL, NULL)); + if (!dbus_message_set_sender (welcome, DBUS_SERVICE_DBUS)) + { + dbus_message_unref (welcome); + BUS_SET_OOM (error); + return FALSE; + } - dbus_message_unref (welcome); + if (!dbus_message_append_args (welcome, + DBUS_TYPE_STRING, name, + NULL)) + { + dbus_message_unref (welcome); + BUS_SET_OOM (error); + return FALSE; + } + + if (!bus_transaction_send_message (transaction, connection, welcome)) + { + dbus_message_unref (welcome); + BUS_SET_OOM (error); + return FALSE; + } + else + { + dbus_message_unref (welcome); + return TRUE; + } } -static void +static dbus_bool_t bus_driver_handle_list_services (DBusConnection *connection, - DBusMessage *message) + BusTransaction *transaction, + DBusMessage *message, + DBusError *error) { DBusMessage *reply; - int len, i; + int len; char **services; - BUS_HANDLE_OOM (reply = dbus_message_new_reply (message)); - - BUS_HANDLE_OOM (services = bus_services_list (&len)); - - BUS_HANDLE_OOM (dbus_message_append_args (reply, - DBUS_TYPE_STRING_ARRAY, services, len, - 0)); - - BUS_HANDLE_OOM (dbus_connection_send_message (connection, reply, NULL, NULL)); + reply = dbus_message_new_reply (message); + if (reply == NULL) + { + BUS_SET_OOM (error); + return FALSE; + } - dbus_message_unref (reply); + services = bus_services_list (&len); + if (services == NULL) + { + dbus_message_unref (reply); + BUS_SET_OOM (error); + return FALSE; + } + + if (!dbus_message_append_args (reply, + DBUS_TYPE_STRING_ARRAY, services, len, + 0)) + { + dbus_free_string_array (services); + dbus_message_unref (reply); + BUS_SET_OOM (error); + return FALSE; + } - if (services != NULL) + dbus_free_string_array (services); + + if (!bus_transaction_send_message (transaction, connection, reply)) { - for (i = 0; i < len; i++) - dbus_free (services[i]); - dbus_free (services); + dbus_message_unref (reply); + BUS_SET_OOM (error); + return FALSE; + } + else + { + dbus_message_unref (reply); + return TRUE; } } -static void +static dbus_bool_t bus_driver_handle_acquire_service (DBusConnection *connection, - DBusMessage *message) + BusTransaction *transaction, + DBusMessage *message, + DBusError *error) { DBusMessage *reply; - DBusResultCode result; DBusString service_name; BusService *service; char *name; int service_reply; int flags; + dbus_bool_t retval; + DBusConnection *old_owner; + DBusConnection *current_owner; - BUS_HANDLE_OOM ((result = dbus_message_get_args (message, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_UINT32, &flags, - 0)) != DBUS_RESULT_NO_MEMORY); + if (!dbus_message_get_args (message, + error, + DBUS_TYPE_STRING, &name, + DBUS_TYPE_UINT32, &flags, + 0)) + return FALSE; - if (result != DBUS_RESULT_SUCCESS) - { - dbus_free (name); - dbus_connection_disconnect (connection); - return; - } + _dbus_verbose ("Trying to own service %s with flags 0x%x\n", name, flags); - _dbus_verbose ("Trying to own service %s with flags %d\n", name, flags); + retval = FALSE; + reply = NULL; _dbus_string_init_const (&service_name, name); - service = bus_service_lookup (&service_name, TRUE); + + service = bus_service_lookup (&service_name); - BUS_HANDLE_OOM ((reply = dbus_message_new_reply (message))); + if (service != NULL) + old_owner = bus_service_get_primary_owner (service); + else + old_owner = NULL; - /* - * Check if the service already has an owner - */ - if (bus_service_get_primary_owner (service) != NULL) - { - if (bus_service_has_owner (service, connection)) - service_reply = DBUS_SERVICE_REPLY_ALREADY_OWNER; - else if (!(flags & DBUS_SERVICE_FLAG_REPLACE_EXISTING)) - service_reply = DBUS_SERVICE_REPLY_SERVICE_EXISTS; - else - { - if (bus_service_get_prohibit_replacement (service)) - { - - /* Queue the connection */ - BUS_HANDLE_OOM (bus_service_add_owner (service, connection)); - - service_reply = DBUS_SERVICE_REPLY_IN_QUEUE; - } - else - { - DBusConnection *owner; - - /* We can replace the primary owner */ - owner = bus_service_get_primary_owner (service); - - /* We enqueue the new owner and remove the first one because - * that will cause ServiceAcquired and ServiceLost messages to - * be sent. - */ - BUS_HANDLE_OOM (bus_service_add_owner (service, connection)); - bus_service_remove_owner (service, owner); - _dbus_assert (connection == bus_service_get_primary_owner (service)); - service_reply = DBUS_SERVICE_REPLY_PRIMARY_OWNER; - } - } + reply = dbus_message_new_reply (message); + if (reply == NULL) + { + BUS_SET_OOM (error); + goto out; } - else + + if (service == NULL) { + service = bus_service_ensure (&service_name, connection, transaction, error); + if (service == NULL) + goto out; + } + + current_owner = bus_service_get_primary_owner (service); + + if (old_owner == NULL) + { + _dbus_assert (current_owner == connection); + bus_service_set_prohibit_replacement (service, - (flags & DBUS_SERVICE_FLAG_PROHIBIT_REPLACEMENT)); + (flags & DBUS_SERVICE_FLAG_PROHIBIT_REPLACEMENT)); + + service_reply = DBUS_SERVICE_REPLY_PRIMARY_OWNER; + } + else if (old_owner == connection) + service_reply = DBUS_SERVICE_REPLY_ALREADY_OWNER; + else if (!((flags & DBUS_SERVICE_FLAG_REPLACE_EXISTING))) + service_reply = DBUS_SERVICE_REPLY_SERVICE_EXISTS; + else if (bus_service_get_prohibit_replacement (service)) + { + /* Queue the connection */ + if (!bus_service_add_owner (service, connection, + transaction, error)) + goto out; - /* Broadcast service created message */ - bus_driver_send_service_created (bus_service_get_name (service)); + service_reply = DBUS_SERVICE_REPLY_IN_QUEUE; + } + else + { + /* Replace the current owner */ + + /* We enqueue the new owner and remove the first one because + * that will cause ServiceAcquired and ServiceLost messages to + * be sent. + */ - BUS_HANDLE_OOM (bus_service_add_owner (service, connection)); - + /* FIXME this is broken, if the remove_owner fails + * we don't undo the add_owner + * (easiest fix is probably to move all this to + * services.c and have a single routine for it) + */ + + if (!bus_service_add_owner (service, connection, + transaction, error)) + goto out; + + if (!bus_service_remove_owner (service, old_owner, + transaction, error)) + goto out; + + _dbus_assert (connection == bus_service_get_primary_owner (service)); service_reply = DBUS_SERVICE_REPLY_PRIMARY_OWNER; } - BUS_HANDLE_OOM (dbus_message_append_args (reply, DBUS_TYPE_UINT32, service_reply, 0)); + if (!dbus_message_append_args (reply, DBUS_TYPE_UINT32, service_reply, 0)) + { + BUS_SET_OOM (error); + goto out; + } - /* Send service reply */ - BUS_HANDLE_OOM (dbus_connection_send_message (connection, reply, NULL, NULL)); + if (!bus_transaction_send_message (transaction, connection, reply)) + { + BUS_SET_OOM (error); + goto out; + } + + retval = TRUE; + + out: dbus_free (name); - dbus_message_unref (reply); -} + if (reply) + dbus_message_unref (reply); + return retval; +} -static void +static dbus_bool_t bus_driver_handle_service_exists (DBusConnection *connection, - DBusMessage *message) + BusTransaction *transaction, + DBusMessage *message, + DBusError *error) { DBusMessage *reply; - DBusResultCode result; DBusString service_name; BusService *service; char *name; + dbus_bool_t retval; - BUS_HANDLE_OOM ((result = dbus_message_get_args (message, - DBUS_TYPE_STRING, &name, - 0)) != DBUS_RESULT_NO_MEMORY); - if (result != DBUS_RESULT_SUCCESS) - { - dbus_free (name); - dbus_connection_disconnect (connection); - return; - } + if (!dbus_message_get_args (message, error, + DBUS_TYPE_STRING, &name, + 0)) + return FALSE; + retval = FALSE; + _dbus_string_init_const (&service_name, name); - service = bus_service_lookup (&service_name, FALSE); + service = bus_service_lookup (&service_name); - BUS_HANDLE_OOM ((reply = dbus_message_new_reply (message))); - BUS_HANDLE_OOM (dbus_message_set_sender (reply, DBUS_SERVICE_DBUS)); - - BUS_HANDLE_OOM (dbus_message_append_args (reply, - DBUS_TYPE_UINT32, service != NULL, - 0)); - BUS_HANDLE_OOM (dbus_connection_send_message (connection, reply, NULL, NULL)); - dbus_message_unref (reply); + reply = dbus_message_new_reply (message); + if (reply == NULL) + { + BUS_SET_OOM (error); + goto out; + } + + if (!dbus_message_set_sender (reply, DBUS_SERVICE_DBUS)) + { + BUS_SET_OOM (error); + goto out; + } + + if (!dbus_message_append_args (reply, + DBUS_TYPE_UINT32, service != NULL, + 0)) + { + BUS_SET_OOM (error); + goto out; + } + + if (!bus_transaction_send_message (transaction, connection, reply)) + { + BUS_SET_OOM (error); + goto out; + } + + retval = TRUE; + + out: + if (reply) + dbus_message_unref (reply); dbus_free (name); + + return retval; } -static void +static dbus_bool_t bus_driver_handle_activate_service (DBusConnection *connection, - DBusMessage *message) + BusTransaction *transaction, + DBusMessage *message, + DBusError *error) { - DBusResultCode result; dbus_uint32_t flags; char *name; - DBusError error; + dbus_bool_t retval; - BUS_HANDLE_OOM ((result = dbus_message_get_args (message, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_UINT32, &flags, - 0)) != DBUS_RESULT_NO_MEMORY); - if (result != DBUS_RESULT_SUCCESS) - { - dbus_free (name); - dbus_connection_disconnect (connection); - return; - } + if (!dbus_message_get_args (message, error, + DBUS_TYPE_STRING, &name, + DBUS_TYPE_UINT32, &flags, + 0)) + return FALSE; - if (!bus_activation_activate_service (name, &error)) - { - DBusMessage *error_reply; - - BUS_HANDLE_OOM (error_reply = dbus_message_new_error_reply (message, - error.name, error.message)); - dbus_error_free (&error); + retval = FALSE; - BUS_HANDLE_OOM (dbus_connection_send_message (connection, error_reply, NULL, NULL)); - dbus_message_unref (error_reply); - } + if (!bus_activation_activate_service (name, error)) + goto out; + + retval = TRUE; + + out: + dbus_free (name); + return retval; } -void +/* For speed it might be useful to sort this in order of + * frequency of use (but doesn't matter with only a few items + * anyhow) + */ +struct +{ + const char *name; + dbus_bool_t (* handler) (DBusConnection *connection, + BusTransaction *transaction, + DBusMessage *message, + DBusError *error); +} message_handlers[] = { + { DBUS_MESSAGE_ACQUIRE_SERVICE, bus_driver_handle_acquire_service }, + { DBUS_MESSAGE_ACTIVATE_SERVICE, bus_driver_handle_activate_service }, + { DBUS_MESSAGE_HELLO, bus_driver_handle_hello }, + { DBUS_MESSAGE_SERVICE_EXISTS, bus_driver_handle_service_exists }, + { DBUS_MESSAGE_LIST_SERVICES, bus_driver_handle_list_services } +}; + +dbus_bool_t bus_driver_handle_message (DBusConnection *connection, - DBusMessage *message) + BusTransaction *transaction, + DBusMessage *message, + DBusError *error) { const char *name, *sender; - + int i; + _dbus_verbose ("Driver got a message: %s\n", dbus_message_get_name (message)); @@ -411,26 +654,39 @@ bus_driver_handle_message (DBusConnection *connection, if (sender == NULL && (strcmp (name, DBUS_MESSAGE_HELLO) != 0)) { - _dbus_verbose ("Trying to send a message without being registered. Disconnecting.\n"); + dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED, + "Client tried to send a message other than %s without being registered", + DBUS_MESSAGE_HELLO); + dbus_connection_disconnect (connection); - return; - } - - /* Now check names. */ - if (strcmp (name, DBUS_MESSAGE_HELLO) == 0) - bus_driver_handle_hello (connection, message); - else if (strcmp (name, DBUS_MESSAGE_LIST_SERVICES) == 0) - bus_driver_handle_list_services (connection, message); - else if (strcmp (name, DBUS_MESSAGE_ACQUIRE_SERVICE) == 0) - bus_driver_handle_acquire_service (connection, message); - else if (strcmp (name, DBUS_MESSAGE_SERVICE_EXISTS) == 0) - bus_driver_handle_service_exists (connection, message); - else if (strcmp (name, DBUS_MESSAGE_ACTIVATE_SERVICE) == 0) - bus_driver_handle_activate_service (connection, message); + return FALSE; + } + + i = 0; + while (i < _DBUS_N_ELEMENTS (message_handlers)) + { + if (strcmp (message_handlers[i].name, name) == 0) + { + if ((* message_handlers[i].handler) (connection, transaction, message, error)) + return TRUE; + else + return FALSE; + } + + ++i; + } + + dbus_set_error (error, DBUS_ERROR_UNKNOWN_MESSAGE, + "%s does not understand message %s", + DBUS_SERVICE_DBUS, name); + + return FALSE; } void bus_driver_remove_connection (DBusConnection *connection) { - /* Does nothing for now */ + /* FIXME Does nothing for now, should unregister the connection + * with the bus driver. + */ } diff --git a/bus/driver.h b/bus/driver.h index 3019fe4..ac80c15 100644 --- a/bus/driver.h +++ b/bus/driver.h @@ -25,17 +25,26 @@ #define BUS_DRIVER_H #include +#include "connection.h" -void bus_driver_remove_connection (DBusConnection *connection); -void bus_driver_handle_message (DBusConnection *connection, - DBusMessage *message); -void bus_driver_send_service_deleted (const char *service_name); -void bus_driver_send_service_lost (DBusConnection *connection, - const char *service_name); -void bus_driver_send_service_acquired (DBusConnection *connection, - const char *service_name); -void bus_driver_send_service_created (const char *service_name); - - +void bus_driver_remove_connection (DBusConnection *connection); +dbus_bool_t bus_driver_handle_message (DBusConnection *connection, + BusTransaction *transaction, + DBusMessage *message, + DBusError *error); +dbus_bool_t bus_driver_send_service_deleted (const char *service_name, + BusTransaction *transaction, + DBusError *error); +dbus_bool_t bus_driver_send_service_lost (DBusConnection *connection, + const char *service_name, + BusTransaction *transaction, + DBusError *error); +dbus_bool_t bus_driver_send_service_acquired (DBusConnection *connection, + const char *service_name, + BusTransaction *transaction, + DBusError *error); +dbus_bool_t bus_driver_send_service_created (const char *service_name, + BusTransaction *transaction, + DBusError *error); #endif /* BUS_DRIVER_H */ diff --git a/bus/main.c b/bus/main.c index fdb6462..56345c7 100644 --- a/bus/main.c +++ b/bus/main.c @@ -97,9 +97,18 @@ main (int argc, char **argv) } else { - char *paths[] = { argv[2], NULL }; + const char *paths[] = { argv[2], NULL }; + DBusError error; - bus_activation_init (argv[1], paths); + dbus_error_init (&error); + if (!bus_activation_init (argv[1], paths, + &error)) + { + _dbus_warn ("Could not initialize service activation: %s\n", + error.message); + dbus_error_free (&error); + return 1; + } } setup_server (server); diff --git a/bus/services.c b/bus/services.c index 497978d..22302af 100644 --- a/bus/services.c +++ b/bus/services.c @@ -21,31 +21,29 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ -#include "driver.h" -#include "services.h" -#include "connection.h" #include #include #include +#include "driver.h" +#include "services.h" +#include "connection.h" +#include "utils.h" + struct BusService { char *name; DBusList *owners; - - unsigned int prohibit_replacement:1; + + unsigned int prohibit_replacement : 1; }; static DBusHashTable *service_hash = NULL; static DBusMemPool *service_pool = NULL; -BusService* -bus_service_lookup (const DBusString *service_name, - dbus_bool_t create_if_not_found) +static dbus_bool_t +init_hash (void) { - const char *c_name; - BusService *service; - if (service_hash == NULL) { service_hash = _dbus_hash_table_new (DBUS_HASH_STRING, @@ -65,93 +63,182 @@ bus_service_lookup (const DBusString *service_name, _dbus_mem_pool_free (service_pool); service_pool = NULL; } - return NULL; + return FALSE; } } + return TRUE; +} + +BusService* +bus_service_lookup (const DBusString *service_name) +{ + const char *c_name; + BusService *service; + + if (!init_hash ()) + return NULL; _dbus_string_get_const_data (service_name, &c_name); service = _dbus_hash_table_lookup_string (service_hash, c_name); - if (service != NULL) - return service; - if (!create_if_not_found) + return service; +} + +BusService* +bus_service_ensure (const DBusString *service_name, + DBusConnection *owner_if_created, + BusTransaction *transaction, + DBusError *error) +{ + const char *c_name; + BusService *service; + + _dbus_assert (owner_if_created != NULL); + _dbus_assert (transaction != NULL); + + if (!init_hash ()) return NULL; + _dbus_string_get_const_data (service_name, &c_name); + + service = _dbus_hash_table_lookup_string (service_hash, + c_name); + if (service != NULL) + return service; + service = _dbus_mem_pool_alloc (service_pool); if (service == NULL) - return NULL; + { + BUS_SET_OOM (error); + return NULL; + } service->name = _dbus_strdup (c_name); if (service->name == NULL) { _dbus_mem_pool_dealloc (service_pool, service); + BUS_SET_OOM (error); return NULL; } + if (!bus_driver_send_service_created (service->name, transaction, error)) + { + dbus_free (service->name); + _dbus_mem_pool_dealloc (service_pool, service); + return NULL; + } + + if (!bus_service_add_owner (service, owner_if_created, + transaction, error)) + { + dbus_free (service->name); + _dbus_mem_pool_dealloc (service_pool, service); + return NULL; + } + if (!_dbus_hash_table_insert_string (service_hash, service->name, service)) { + _dbus_list_clear (&service->owners); dbus_free (service->name); _dbus_mem_pool_dealloc (service_pool, service); + BUS_SET_OOM (error); return NULL; } - - bus_driver_send_service_created (service->name); return service; } dbus_bool_t bus_service_add_owner (BusService *service, - DBusConnection *owner) + DBusConnection *owner, + BusTransaction *transaction, + DBusError *error) { + /* Send service acquired message first, OOM will result + * in cancelling the transaction + */ + if (service->owners == NULL) + { + if (!bus_driver_send_service_acquired (owner, service->name, transaction, error)) + return FALSE; + } + if (!_dbus_list_append (&service->owners, owner)) - return FALSE; + { + BUS_SET_OOM (error); + return FALSE; + } if (!bus_connection_add_owned_service (owner, service)) { _dbus_list_remove_last (&service->owners, owner); + BUS_SET_OOM (error); return FALSE; } - - /* Send service acquired message */ - if (bus_service_get_primary_owner (service) == owner) - bus_driver_send_service_acquired (owner, service->name); return TRUE; } -void +dbus_bool_t bus_service_remove_owner (BusService *service, - DBusConnection *owner) + DBusConnection *owner, + BusTransaction *transaction, + DBusError *error) { + /* We send out notifications before we do any work we + * might have to undo if the notification-sending failed + */ + /* Send service lost message */ if (bus_service_get_primary_owner (service) == owner) - bus_driver_send_service_lost (owner, service->name); + { + if (!bus_driver_send_service_lost (owner, service->name, + transaction, error)) + return FALSE; + } + + if (_dbus_list_length_is_one (&service->owners)) + { + /* We are the only owner - send service deleted */ + if (!bus_driver_send_service_deleted (service->name, + transaction, error)) + return FALSE; + } + else + { + DBusList *link; + link = _dbus_list_get_first (&service->owners); + link = _dbus_list_get_next_link (&service->owners, link); + + if (link != NULL) + { + /* This will be our new owner */ + if (!bus_driver_send_service_acquired (link->data, + service->name, + transaction, + error)) + return FALSE; + } + } _dbus_list_remove_last (&service->owners, owner); bus_connection_remove_owned_service (owner, service); if (service->owners == NULL) { - /* Delete service */ - bus_driver_send_service_deleted (service->name); - + /* Delete service (already sent message that it was deleted above) */ _dbus_hash_table_remove_string (service_hash, service->name); dbus_free (service->name); _dbus_mem_pool_dealloc (service_pool, service); } - else - { - /* Send service acquired to the new owner */ - bus_driver_send_service_acquired (bus_service_get_primary_owner (service), - service->name); - } + + return TRUE; } DBusConnection* @@ -192,7 +279,7 @@ bus_services_list (int *array_len) DBusHashIter iter; len = _dbus_hash_table_get_n_entries (service_hash); - retval = dbus_new (char *, len); + retval = dbus_new (char *, len + 1); if (retval == NULL) return NULL; @@ -210,6 +297,8 @@ bus_services_list (int *array_len) i++; } + retval[i] = NULL; + if (array_len) *array_len = len; @@ -227,8 +316,6 @@ void bus_service_set_prohibit_replacement (BusService *service, dbus_bool_t prohibit_replacement) { - _dbus_assert (service->owners == NULL); - service->prohibit_replacement = prohibit_replacement != FALSE; } diff --git a/bus/services.h b/bus/services.h index 3f6b31a..9758358 100644 --- a/bus/services.h +++ b/bus/services.h @@ -26,6 +26,10 @@ #include #include +#include "connection.h" + +/* forward decl that probably shouldn't be in this file */ +typedef struct BusTransaction BusTransaction; /* Each service can have multiple owners; one owner is the "real * owner" and the others are queued up. For example, if I have @@ -38,12 +42,19 @@ typedef struct BusService BusService; typedef void (* BusServiceForeachFunction) (BusService *service, void *data); -BusService* bus_service_lookup (const DBusString *service_name, - dbus_bool_t create_if_not_found); +BusService* bus_service_lookup (const DBusString *service_name); +BusService* bus_service_ensure (const DBusString *service_name, + DBusConnection *owner_if_created, + BusTransaction *transaction, + DBusError *error); dbus_bool_t bus_service_add_owner (BusService *service, - DBusConnection *owner); -void bus_service_remove_owner (BusService *service, - DBusConnection *owner); + DBusConnection *owner, + BusTransaction *transaction, + DBusError *error); +dbus_bool_t bus_service_remove_owner (BusService *service, + DBusConnection *owner, + BusTransaction *transaction, + DBusError *error); dbus_bool_t bus_service_has_owner (BusService *service, DBusConnection *owner); DBusConnection* bus_service_get_primary_owner (BusService *service); diff --git a/bus/utils.c b/bus/utils.c index 8663b1e..8b964cc 100644 --- a/bus/utils.c +++ b/bus/utils.c @@ -25,6 +25,8 @@ #include "utils.h" #include +const char bus_no_memory_message[] = "Memory allocation failure in message bus"; + void bus_wait_for_memory (void) { diff --git a/bus/utils.h b/bus/utils.h index 5cbe284..41eb555 100644 --- a/bus/utils.h +++ b/bus/utils.h @@ -25,8 +25,9 @@ #ifndef BUS_UTILS_H #define BUS_UTILS_H -#define BUS_HANDLE_OOM(stat) (stat) - void bus_wait_for_memory (void); +extern const char bus_no_memory_message[]; +#define BUS_SET_OOM(error) dbus_set_error ((error), DBUS_ERROR_NO_MEMORY, bus_no_memory_message) + #endif /* BUS_ACTIVATION_H */ diff --git a/dbus/dbus-address.c b/dbus/dbus-address.c index fb8952b..25179ce 100644 --- a/dbus/dbus-address.c +++ b/dbus/dbus-address.c @@ -27,9 +27,9 @@ #include "dbus-list.h" /** - * @defgroup DBusAddress address parsing + * @defgroup DBusAddress Address parsing * @ingroup DBus - * @brief Parsing addresses to DBus servers. + * @brief Parsing addresses of D-BUS servers. * * @{ */ diff --git a/dbus/dbus-auth-script.c b/dbus/dbus-auth-script.c index 732b451..336d63e 100644 --- a/dbus/dbus-auth-script.c +++ b/dbus/dbus-auth-script.c @@ -184,7 +184,7 @@ dbus_bool_t _dbus_auth_script_run (const DBusString *filename) { DBusString file; - DBusResultCode result; + DBusError error; DBusString line; dbus_bool_t retval; int line_no; @@ -213,14 +213,14 @@ _dbus_auth_script_run (const DBusString *filename) _dbus_string_free (&line); return FALSE; } - - if ((result = _dbus_file_get_contents (&file, filename)) != DBUS_RESULT_SUCCESS) - { + + dbus_error_init (&error); + if (!_dbus_file_get_contents (&file, filename, &error)) { const char *s; _dbus_string_get_const_data (filename, &s); _dbus_warn ("Getting contents of %s failed: %s\n", - s, dbus_result_to_string (result)); - + s, error.message); + dbus_error_free (&error); goto out; } diff --git a/dbus/dbus-auth.c b/dbus/dbus-auth.c index 516a51a..8dfdc76 100644 --- a/dbus/dbus-auth.c +++ b/dbus/dbus-auth.c @@ -514,7 +514,7 @@ sha1_handle_first_client_response (DBusAuth *auth, } else { - _dbus_assert (dbus_error_is_set (&error)); + _DBUS_ASSERT_ERROR_IS_SET (&error); _dbus_verbose ("Error loading keyring: %s\n", error.message); if (send_rejected (auth)) @@ -535,7 +535,7 @@ sha1_handle_first_client_response (DBusAuth *auth, auth->cookie_id = _dbus_keyring_get_best_key (auth->keyring, &error); if (auth->cookie_id < 0) { - _dbus_assert (dbus_error_is_set (&error)); + _DBUS_ASSERT_ERROR_IS_SET (&error); _dbus_verbose ("Could not get a cookie ID to send to client: %s\n", error.message); if (send_rejected (auth)) @@ -844,7 +844,8 @@ handle_client_data_cookie_sha1_mech (DBusAuth *auth, } else { - _dbus_assert (dbus_error_is_set (&error)); + _DBUS_ASSERT_ERROR_IS_SET (&error); + _dbus_verbose ("Error loading keyring: %s\n", error.message); @@ -2238,7 +2239,7 @@ process_test_subdir (const DBusString *test_base_dir, DBusString filename; DBusDirIter *dir; dbus_bool_t retval; - DBusResultCode result; + DBusError error; retval = FALSE; dir = NULL; @@ -2258,22 +2259,23 @@ process_test_subdir (const DBusString *test_base_dir, _dbus_string_free (&filename); if (!_dbus_string_init (&filename, _DBUS_INT_MAX)) _dbus_assert_not_reached ("didn't allocate filename string\n"); - - dir = _dbus_directory_open (&test_directory, &result); + + dbus_error_init (&error); + dir = _dbus_directory_open (&test_directory, &error); if (dir == NULL) { const char *s; _dbus_string_get_const_data (&test_directory, &s); _dbus_warn ("Could not open %s: %s\n", s, - dbus_result_to_string (result)); + error.message); + dbus_error_free (&error); goto failed; } printf ("Testing:\n"); - result = DBUS_RESULT_SUCCESS; next: - while (_dbus_directory_get_next_file (dir, &filename, &result)) + while (_dbus_directory_get_next_file (dir, &filename, &error)) { DBusString full_path; @@ -2311,12 +2313,13 @@ process_test_subdir (const DBusString *test_base_dir, _dbus_string_free (&full_path); } - if (result != DBUS_RESULT_SUCCESS) + if (dbus_error_is_set (&error)) { const char *s; _dbus_string_get_const_data (&test_directory, &s); _dbus_warn ("Could not get next file in %s: %s\n", - s, dbus_result_to_string (result)); + s, error.message); + dbus_error_free (&error); goto failed; } diff --git a/dbus/dbus-bus.c b/dbus/dbus-bus.c index 99ef5ad..cc612a7 100644 --- a/dbus/dbus-bus.c +++ b/dbus/dbus-bus.c @@ -2,6 +2,7 @@ /* dbus-bus.c Convenience functions for communicating with the bus. * * Copyright (C) 2003 CodeFactory AB + * Copyright (C) 2003 Red Hat, Inc. * * Licensed under the Academic Free License version 1.2 * @@ -23,29 +24,32 @@ #include "dbus-bus.h" #include "dbus-protocol.h" +#include "dbus-internals.h" /** - * @defgroup DBusBus Convenience functinos for communicating with the bus. + * @defgroup DBusBus Message bus APIs * @ingroup DBus - * @brief Convenience functinos for communicating with the bus. + * @brief Functions for communicating with the message bus * * @{ */ /** - * Registers a connection with the bus. This is needed to send messages - * to other clients. + * Registers a connection with the bus. This must be the first + * thing an application does when connecting to the message bus. * - * @param connection The connection - * @param result address where a result code can be returned. - * @returns the service name of which the client is known as. + * @todo if we get an error reply, it has to be converted into + * DBusError and returned + * + * @param connection the connection + * @param error place to store errors + * @returns the client's unique service name, #NULL on error */ -char * +char* dbus_bus_register_client (DBusConnection *connection, - DBusResultCode *result) + DBusError *error) { DBusMessage *message, *reply; - DBusResultCode code; char *name; message = dbus_message_new (DBUS_SERVICE_DBUS, @@ -53,56 +57,61 @@ dbus_bus_register_client (DBusConnection *connection, if (!message) { - dbus_set_result (result, DBUS_RESULT_NO_MEMORY); + _DBUS_SET_OOM (error); return NULL; } - reply = dbus_connection_send_message_with_reply_and_block (connection, message, -1, result); + reply = dbus_connection_send_with_reply_and_block (connection, message, -1, error); dbus_message_unref (message); - if (!reply) - return NULL; - - code = dbus_message_get_args (reply, - DBUS_TYPE_STRING, &name, - 0); - if (code != DBUS_RESULT_SUCCESS) + if (reply == NULL) { - dbus_set_result (result, code); + _DBUS_ASSERT_ERROR_IS_SET (error); return NULL; } - dbus_set_result (result, DBUS_RESULT_SUCCESS); - + if (!dbus_message_get_args (reply, error, + DBUS_TYPE_STRING, &name, + 0)) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + return NULL; + } + return name; } /** * Asks the bus to try to acquire a certain service. * + * @todo these docs are not complete, need to document the + * return value and flags + * + * @todo if we get an error reply, it has to be converted into + * DBusError and returned + * * @param connection the connection * @param service_name the service name * @param flags flags - * @param result address where a result code can be returned. - * @returns a result code. + * @param error location to store the error + * @returns a result code, -1 if error is set */ int dbus_bus_acquire_service (DBusConnection *connection, const char *service_name, unsigned int flags, - DBusResultCode *result) + DBusError *error) { DBusMessage *message, *reply; int service_result; - DBusResultCode code; message = dbus_message_new (DBUS_SERVICE_DBUS, DBUS_MESSAGE_ACQUIRE_SERVICE); - if (!message) + if (message == NULL) { - dbus_set_result (result, DBUS_RESULT_NO_MEMORY); + _DBUS_SET_OOM (error); return -1; } @@ -112,26 +121,28 @@ dbus_bus_acquire_service (DBusConnection *connection, 0)) { dbus_message_unref (message); - dbus_set_result (result, DBUS_RESULT_NO_MEMORY); + _DBUS_SET_OOM (error); return -1; } - reply = dbus_connection_send_message_with_reply_and_block (connection, message, -1, result); + reply = dbus_connection_send_with_reply_and_block (connection, message, -1, + error); + dbus_message_unref (message); - if (!reply) - return -1; - - code = dbus_message_get_args (reply, - DBUS_TYPE_UINT32, &service_result, - 0); - if (code != DBUS_RESULT_SUCCESS) + if (reply == NULL) { - dbus_set_result (result, code); + _DBUS_ASSERT_ERROR_IS_SET (error); return -1; } - dbus_set_result (result, DBUS_RESULT_SUCCESS); + if (!dbus_message_get_args (reply, error, + DBUS_TYPE_UINT32, &service_result, + 0)) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + return -1; + } return service_result; } @@ -139,25 +150,26 @@ dbus_bus_acquire_service (DBusConnection *connection, /** * Checks whether a certain service exists. * + * @todo the SERVICE_EXISTS message should use BOOLEAN not UINT32 + * * @param connection the connection * @param service_name the service name - * @param result address where a result code can be returned. - * @returns #TRUE if the service exists, #FALSE otherwise. + * @param error location to store any errors + * @returns #TRUE if the service exists, #FALSE if not or on error */ dbus_bool_t dbus_bus_service_exists (DBusConnection *connection, const char *service_name, - DBusResultCode *result) + DBusError *error) { DBusMessage *message, *reply; unsigned int exists; - DBusResultCode code; message = dbus_message_new (DBUS_SERVICE_DBUS, DBUS_MESSAGE_SERVICE_EXISTS); - if (!message) + if (message == NULL) { - dbus_set_result (result, DBUS_RESULT_NO_MEMORY); + _DBUS_SET_OOM (error); return FALSE; } @@ -166,27 +178,27 @@ dbus_bus_service_exists (DBusConnection *connection, 0)) { dbus_message_unref (message); - dbus_set_result (result, DBUS_RESULT_NO_MEMORY); + _DBUS_SET_OOM (error); return FALSE; } - reply = dbus_connection_send_message_with_reply_and_block (connection, message, -1, result); + reply = dbus_connection_send_with_reply_and_block (connection, message, -1, error); dbus_message_unref (message); - if (!reply) - return FALSE; + if (reply == NULL) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + return FALSE; + } - code = dbus_message_get_args (reply, - DBUS_TYPE_UINT32, &exists, - 0); - if (code != DBUS_RESULT_SUCCESS) + if (!dbus_message_get_args (reply, error, + DBUS_TYPE_UINT32, &exists, + 0)) { - dbus_set_result (result, code); + _DBUS_ASSERT_ERROR_IS_SET (error); return FALSE; } - dbus_set_result (result, DBUS_RESULT_SUCCESS); - return (exists != FALSE); } diff --git a/dbus/dbus-bus.h b/dbus/dbus-bus.h index 0bd8dec..d1c2bfd 100644 --- a/dbus/dbus-bus.h +++ b/dbus/dbus-bus.h @@ -29,15 +29,15 @@ #include -char * dbus_bus_register_client (DBusConnection *connection, - DBusResultCode *result); +char* dbus_bus_register_client (DBusConnection *connection, + DBusError *error); int dbus_bus_acquire_service (DBusConnection *connection, const char *service_name, unsigned int flags, - DBusResultCode *result); + DBusError *error); dbus_bool_t dbus_bus_service_exists (DBusConnection *connection, const char *service_name, - DBusResultCode *result); + DBusError *error); #endif /* DBUS_BUS_H */ diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c index 3611b87..bfc27e2 100644 --- a/dbus/dbus-connection.c +++ b/dbus/dbus-connection.c @@ -187,7 +187,7 @@ _dbus_connection_queue_received_message (DBusConnection *connection, return FALSE; /* If this is a reply we're waiting on, remove timeout for it */ - reply_serial = _dbus_message_get_reply_serial (message); + reply_serial = dbus_message_get_reply_serial (message); if (reply_serial != -1) { reply_handler_data = _dbus_hash_table_lookup_int (connection->pending_replies, @@ -205,9 +205,11 @@ _dbus_connection_queue_received_message (DBusConnection *connection, connection->n_incoming += 1; _dbus_connection_wakeup_mainloop (connection); - - _dbus_verbose ("Incoming message %p added to queue, %d incoming\n", - message, connection->n_incoming); + + _dbus_assert (dbus_message_get_name (message) != NULL); + _dbus_verbose ("Incoming message %p (%s) added to queue, %d incoming\n", + message, dbus_message_get_name (message), + connection->n_incoming); return TRUE; } @@ -963,54 +965,88 @@ dbus_connection_get_is_authenticated (DBusConnection *connection) } /** - * Adds a message to the outgoing message queue. Does not block to - * write the message to the network; that happens asynchronously. to - * force the message to be written, call dbus_connection_flush(). + * Preallocates resources needed to send a message, allowing the message + * to be sent without the possibility of memory allocation failure. + * Allows apps to create a future guarantee that they can send + * a message regardless of memory shortages. * - * If the function fails, it returns #FALSE and returns the - * reason for failure via the result parameter. - * The result parameter can be #NULL if you aren't interested - * in the reason for the failure. - * - * @param connection the connection. - * @param message the message to write. - * @param client_serial return location for client serial. - * @param result address where result code can be placed. - * @returns #TRUE on success. + * @param connection the connection we're preallocating for. + * @returns the preallocated resources, or #NULL */ -dbus_bool_t -dbus_connection_send_message (DBusConnection *connection, - DBusMessage *message, - dbus_int32_t *client_serial, - DBusResultCode *result) +DBusPreallocatedSend* +dbus_connection_preallocate_send (DBusConnection *connection) +{ + /* we store "connection" in the link just to enforce via + * assertion that preallocated links are only used + * with the connection they were created for. + */ + return (DBusPreallocatedSend*) _dbus_list_alloc_link (connection); +} +/** + * Frees preallocated message-sending resources from + * dbus_connection_preallocate_send(). Should only + * be called if the preallocated resources are not used + * to send a message. + * + * @param connection the connection + * @param preallocated the resources + */ +void +dbus_connection_free_preallocated_send (DBusConnection *connection, + DBusPreallocatedSend *preallocated) { - dbus_int32_t serial; + DBusList *link = (DBusList*) preallocated; + _dbus_assert (link->data == connection); + _dbus_list_free_link (link); +} +/** + * Sends a message using preallocated resources. This function cannot fail. + * It works identically to dbus_connection_send() in other respects. + * Preallocated resources comes from dbus_connection_preallocate_send(). + * This function "consumes" the preallocated resources, they need not + * be freed separately. + * + * @param connection the connection + * @param preallocated the preallocated resources + * @param message the message to send + * @param client_serial return location for client serial assigned to the message + */ +void +dbus_connection_send_preallocated (DBusConnection *connection, + DBusPreallocatedSend *preallocated, + DBusMessage *message, + dbus_int32_t *client_serial) +{ + DBusList *link = (DBusList*) preallocated; + dbus_int32_t serial; + + _dbus_assert (link->data == connection); + _dbus_assert (dbus_message_get_name (message) != NULL); + dbus_mutex_lock (connection->mutex); - if (!_dbus_list_prepend (&connection->outgoing_messages, - message)) - { - dbus_set_result (result, DBUS_RESULT_NO_MEMORY); - dbus_mutex_unlock (connection->mutex); - return FALSE; - } + link->data = message; + _dbus_list_prepend_link (&connection->outgoing_messages, + link); dbus_message_ref (message); connection->n_outgoing += 1; - _dbus_verbose ("Message %p added to outgoing queue, %d pending to send\n", - message, connection->n_outgoing); + _dbus_verbose ("Message %p (%s) added to outgoing queue, %d pending to send\n", + message, + dbus_message_get_name (message), + connection->n_outgoing); - if (_dbus_message_get_client_serial (message) == -1) + if (dbus_message_get_serial (message) == -1) { serial = _dbus_connection_get_next_client_serial (connection); - _dbus_message_set_client_serial (message, serial); + _dbus_message_set_serial (message, serial); } if (client_serial) - *client_serial = _dbus_message_get_client_serial (message); + *client_serial = dbus_message_get_serial (message); _dbus_message_lock (message); @@ -1021,8 +1057,43 @@ dbus_connection_send_message (DBusConnection *connection, _dbus_connection_wakeup_mainloop (connection); dbus_mutex_unlock (connection->mutex); - - return TRUE; +} + +/** + * Adds a message to the outgoing message queue. Does not block to + * write the message to the network; that happens asynchronously. To + * force the message to be written, call dbus_connection_flush(). + * Because this only queues the message, the only reason it can + * fail is lack of memory. Even if the connection is disconnected, + * no error will be returned. + * + * If the function fails, it returns #FALSE and returns the + * reason for failure via the result parameter. + * The result parameter can be #NULL if you aren't interested + * in the reason for the failure. + * + * @param connection the connection. + * @param message the message to write. + * @param client_serial return location for client serial. + * @returns #TRUE on success. + */ +dbus_bool_t +dbus_connection_send (DBusConnection *connection, + DBusMessage *message, + dbus_int32_t *client_serial) +{ + DBusPreallocatedSend *preallocated; + + preallocated = dbus_connection_preallocate_send (connection); + if (preallocated == NULL) + { + return FALSE; + } + else + { + dbus_connection_send_preallocated (connection, preallocated, message, client_serial); + return TRUE; + } } static void @@ -1100,25 +1171,19 @@ reply_handler_data_free (ReplyHandlerData *data) * you want a very short or very long timeout. There is no way to * avoid a timeout entirely, other than passing INT_MAX for the * timeout to postpone it indefinitely. - * - * @todo I think we should rename this function family - * dbus_connection_send(), send_with_reply(), etc. (i.e. - * drop the "message" part), the names are too long. * * @param connection the connection * @param message the message to send * @param reply_handler message handler expecting the reply, or #NULL * @param timeout_milliseconds timeout in milliseconds or -1 for default - * @param result return location for result code * @returns #TRUE if the message is successfully queued, #FALSE if no memory. * */ dbus_bool_t -dbus_connection_send_message_with_reply (DBusConnection *connection, - DBusMessage *message, - DBusMessageHandler *reply_handler, - int timeout_milliseconds, - DBusResultCode *result) +dbus_connection_send_with_reply (DBusConnection *connection, + DBusMessage *message, + DBusMessageHandler *reply_handler, + int timeout_milliseconds) { DBusTimeout *timeout; ReplyHandlerData *data; @@ -1132,10 +1197,7 @@ dbus_connection_send_message_with_reply (DBusConnection *connection, data = dbus_new0 (ReplyHandlerData, 1); if (!data) - { - dbus_set_result (result, DBUS_RESULT_NO_MEMORY); - return FALSE; - } + return FALSE; timeout = _dbus_timeout_new (timeout_milliseconds, reply_handler_timeout, data, NULL); @@ -1143,7 +1205,6 @@ dbus_connection_send_message_with_reply (DBusConnection *connection, if (!timeout) { reply_handler_data_free (data); - dbus_set_result (result, DBUS_RESULT_NO_MEMORY); return FALSE; } @@ -1155,8 +1216,6 @@ dbus_connection_send_message_with_reply (DBusConnection *connection, reply_handler_data_free (data); _dbus_timeout_unref (timeout); dbus_mutex_unlock (connection->mutex); - - dbus_set_result (result, DBUS_RESULT_NO_MEMORY); return FALSE; } @@ -1171,17 +1230,15 @@ dbus_connection_send_message_with_reply (DBusConnection *connection, { dbus_mutex_unlock (connection->mutex); reply_handler_data_free (data); - - dbus_set_result (result, DBUS_RESULT_NO_MEMORY); return FALSE; } data->connection_added = TRUE; /* Assign a serial to the message */ - if (_dbus_message_get_client_serial (message) == -1) + if (dbus_message_get_serial (message) == -1) { serial = _dbus_connection_get_next_client_serial (connection); - _dbus_message_set_client_serial (message, serial); + _dbus_message_set_serial (message, serial); } data->handler = reply_handler; @@ -1195,8 +1252,6 @@ dbus_connection_send_message_with_reply (DBusConnection *connection, { dbus_mutex_unlock (connection->mutex); reply_handler_data_free (data); - - dbus_set_result (result, DBUS_RESULT_NO_MEMORY); return FALSE; } @@ -1206,8 +1261,6 @@ dbus_connection_send_message_with_reply (DBusConnection *connection, dbus_mutex_unlock (connection->mutex); dbus_message_unref (reply); reply_handler_data_free (data); - - dbus_set_result (result, DBUS_RESULT_NO_MEMORY); return FALSE; } @@ -1216,23 +1269,20 @@ dbus_connection_send_message_with_reply (DBusConnection *connection, /* Insert the serial in the pending replies hash. */ if (!_dbus_hash_table_insert_int (connection->pending_replies, serial, data)) { - dbus_set_result (result, DBUS_RESULT_NO_MEMORY); dbus_mutex_unlock (connection->mutex); - reply_handler_data_free (data); - + reply_handler_data_free (data); return FALSE; } dbus_mutex_unlock (connection->mutex); - if (!dbus_connection_send_message (connection, message, NULL, result)) + if (!dbus_connection_send (connection, message, NULL)) { /* This will free the handler data too */ _dbus_hash_table_remove_int (connection->pending_replies, serial); return FALSE; } - dbus_set_result (result, DBUS_RESULT_SUCCESS); return TRUE; } @@ -1242,9 +1292,9 @@ dbus_connection_send_message_with_reply (DBusConnection *connection, * has been reached. This function is used to do non-reentrant "method calls." * If a reply is received, it is returned, and removed from the incoming * message queue. If it is not received, #NULL is returned and the - * result is set to #DBUS_RESULT_NO_REPLY. If something else goes + * error is set to #DBUS_ERROR_NO_REPLY. If something else goes * wrong, result is set to whatever is appropriate, such as - * #DBUS_RESULT_NO_MEMORY. + * #DBUS_ERROR_NO_MEMORY or #DBUS_ERROR_DISCONNECTED. * * @todo could use performance improvements (it keeps scanning * the whole message queue for example) and has thread issues, @@ -1253,15 +1303,15 @@ dbus_connection_send_message_with_reply (DBusConnection *connection, * @param connection the connection * @param message the message to send * @param timeout_milliseconds timeout in milliseconds or -1 for default - * @param result return location for result code + * @param error return location for error message * @returns the message that is the reply or #NULL with an error code if the * function fails. */ DBusMessage * -dbus_connection_send_message_with_reply_and_block (DBusConnection *connection, - DBusMessage *message, - int timeout_milliseconds, - DBusResultCode *result) +dbus_connection_send_with_reply_and_block (DBusConnection *connection, + DBusMessage *message, + int timeout_milliseconds, + DBusError *error) { dbus_int32_t client_serial; DBusList *link; @@ -1279,8 +1329,11 @@ dbus_connection_send_message_with_reply_and_block (DBusConnection *connectio if (timeout_milliseconds > _DBUS_ONE_HOUR_IN_MILLISECONDS * 6) timeout_milliseconds = _DBUS_ONE_HOUR_IN_MILLISECONDS * 6; - if (!dbus_connection_send_message (connection, message, &client_serial, result)) - return NULL; + if (!dbus_connection_send (connection, message, &client_serial)) + { + _DBUS_SET_OOM (error); + return NULL; + } message = NULL; @@ -1318,13 +1371,10 @@ dbus_connection_send_message_with_reply_and_block (DBusConnection *connectio { DBusMessage *reply = link->data; - if (_dbus_message_get_reply_serial (reply) == client_serial) + if (dbus_message_get_reply_serial (reply) == client_serial) { _dbus_list_remove_link (&connection->incoming_messages, link); dbus_message_ref (reply); - - if (result) - *result = DBUS_RESULT_SUCCESS; dbus_mutex_unlock (connection->mutex); return reply; @@ -1345,14 +1395,14 @@ dbus_connection_send_message_with_reply_and_block (DBusConnection *connectio (end_tv_usec - tv_usec) / 1000; _dbus_verbose ("%d milliseconds remain\n", timeout_milliseconds); _dbus_assert (timeout_milliseconds > 0); - + goto block_again; /* not expired yet */ } - + if (dbus_connection_get_is_connected (connection)) - dbus_set_result (result, DBUS_RESULT_NO_REPLY); + dbus_set_error (error, DBUS_ERROR_NO_REPLY, "Message did not receive a reply"); else - dbus_set_result (result, DBUS_RESULT_DISCONNECTED); + dbus_set_error (error, DBUS_ERROR_DISCONNECTED, "Disconnected prior to receiving a reply"); dbus_mutex_unlock (connection->mutex); @@ -1631,7 +1681,7 @@ dbus_connection_dispatch_message (DBusConnection *connection) result = DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS; - reply_serial = _dbus_message_get_reply_serial (message); + reply_serial = dbus_message_get_reply_serial (message); reply_handler_data = _dbus_hash_table_lookup_int (connection->pending_replies, reply_serial); diff --git a/dbus/dbus-connection.h b/dbus/dbus-connection.h index fd631c6..6b48013 100644 --- a/dbus/dbus-connection.h +++ b/dbus/dbus-connection.h @@ -37,6 +37,7 @@ typedef struct DBusConnection DBusConnection; typedef struct DBusWatch DBusWatch; typedef struct DBusTimeout DBusTimeout; typedef struct DBusMessageHandler DBusMessageHandler; +typedef struct DBusPreallocatedSend DBusPreallocatedSend; typedef enum { @@ -85,19 +86,18 @@ DBusMessage* dbus_connection_pop_message (DBusConnection *connecti dbus_bool_t dbus_connection_dispatch_message (DBusConnection *connection); -dbus_bool_t dbus_connection_send_message (DBusConnection *connection, - DBusMessage *message, - dbus_int32_t *client_serial, - DBusResultCode *result); -dbus_bool_t dbus_connection_send_message_with_reply (DBusConnection *connection, - DBusMessage *message, - DBusMessageHandler *reply_handler, - int timeout_milliseconds, - DBusResultCode *result); -DBusMessage *dbus_connection_send_message_with_reply_and_block (DBusConnection *connection, - DBusMessage *message, - int timeout_milliseconds, - DBusResultCode *result); +dbus_bool_t dbus_connection_send (DBusConnection *connection, + DBusMessage *message, + dbus_int32_t *client_serial); +dbus_bool_t dbus_connection_send_with_reply (DBusConnection *connection, + DBusMessage *message, + DBusMessageHandler *reply_handler, + int timeout_milliseconds); +DBusMessage *dbus_connection_send_with_reply_and_block (DBusConnection *connection, + DBusMessage *message, + int timeout_milliseconds, + DBusError *error); + void dbus_connection_set_watch_functions (DBusConnection *connection, @@ -169,6 +169,14 @@ void dbus_connection_set_max_live_messages_size (DBusConnection *connection, long size); long dbus_connection_get_max_live_messages_size (DBusConnection *connection); +DBusPreallocatedSend* dbus_connection_preallocate_send (DBusConnection *connection); +void dbus_connection_free_preallocated_send (DBusConnection *connection, + DBusPreallocatedSend *preallocated); +void dbus_connection_send_preallocated (DBusConnection *connection, + DBusPreallocatedSend *preallocated, + DBusMessage *message, + dbus_int32_t *client_serial); + DBUS_END_DECLS; diff --git a/dbus/dbus-errors.c b/dbus/dbus-errors.c index e57d353..da49e2e 100644 --- a/dbus/dbus-errors.c +++ b/dbus/dbus-errors.c @@ -44,9 +44,6 @@ * @endcode * * @todo add docs with DBusError - * - * @todo add dbus_error_is_set() to check - * whether an error is set. * * @{ */ @@ -138,11 +135,9 @@ dbus_result_to_string (DBusResultCode code) } /** - * Initializes a DBusError structure. - * - * @todo calling dbus_error_init() in here is no good, - * for the same reason a GError* has to be set to NULL - * before you pass it in. + * Initializes a DBusError structure. Does not allocate + * any memory; the error only needs to be freed + * if it is set at some point. * * @param error the DBusError. */ @@ -164,7 +159,8 @@ dbus_error_init (DBusError *error) } /** - * Frees an error created by dbus_error_init(). + * Frees an error that's been set (or just initialized), + * then reinitializes the error as in dbus_error_init(). * * @param error memory where the error is stored. */ @@ -177,6 +173,8 @@ dbus_error_free (DBusError *error) if (!real->const_message) dbus_free (real->message); + + dbus_error_init (error); } /** @@ -211,6 +209,32 @@ dbus_set_error_const (DBusError *error, } /** + * Moves an error src into dest, freeing src and + * overwriting dest. Both src and dest must be initialized. + * src is reinitialized to an empty error. dest may not + * contain an existing error. If the destination is + * #NULL, just frees and reinits the source error. + * + * @param src the source error + * @param dest the destination error or #NULL + */ +void +dbus_move_error (DBusError *src, + DBusError *dest) +{ + _dbus_assert (!dbus_error_is_set (dest)); + + if (dest) + { + dbus_error_free (dest); + *dest = *src; + dbus_error_init (src); + } + else + dbus_error_free (src); +} + +/** * Checks whether the error is set and has the given * name. * @param error the error @@ -246,7 +270,7 @@ dbus_error_has_name (const DBusError *error, dbus_bool_t dbus_error_is_set (const DBusError *error) { - _dbus_assert (error != NULL); + _dbus_assert (error != NULL); _dbus_assert ((error->name != NULL && error->message != NULL) || (error->name == NULL && error->message == NULL)); return error->name != NULL; diff --git a/dbus/dbus-errors.h b/dbus/dbus-errors.h index e6b8846..63edbdb 100644 --- a/dbus/dbus-errors.h +++ b/dbus/dbus-errors.h @@ -56,6 +56,20 @@ struct DBusError #define DBUS_ERROR_NO_MEMORY "org.freedesktop.DBus.Error.NoMemory" #define DBUS_ERROR_SERVICE_DOES_NOT_EXIST "org.freedesktop.DBus.Error.ServiceDoesNotExist" #define DBUS_ERROR_NO_REPLY "org.freedesktop.DBus.Error.NoReply" +#define DBUS_ERROR_IO_ERROR "org.freedesktop.DBus.Error.IOError" +#define DBUS_ERROR_BAD_ADDRESS "org.freedesktop.DBus.Error.BadAddress" +#define DBUS_ERROR_NOT_SUPPORTED "org.freedesktop.DBus.Error.NotSupported" +#define DBUS_ERROR_LIMITS_EXCEEDED "org.freedesktop.DBus.Error.LimitsExceeded" +#define DBUS_ERROR_ACCESS_DENIED "org.freedesktop.DBus.Error.AccessDenied" +#define DBUS_ERROR_AUTH_FAILED "org.freedesktop.DBus.Error.AuthFailed" +#define DBUS_ERROR_NO_SERVER "org.freedesktop.DBus.Error.NoServer" +#define DBUS_ERROR_TIMEOUT "org.freedesktop.DBus.Error.Timeout" +#define DBUS_ERROR_NO_NETWORK "org.freedesktop.DBus.Error.NoNetwork" +#define DBUS_ERROR_ADDRESS_IN_USE "org.freedesktop.DBus.Error.AddressInUse" +#define DBUS_ERROR_DISCONNECTED "org.freedesktop.DBus.Error.Disconnected" +#define DBUS_ERROR_INVALID_ARGS "org.freedesktop.DBus.Error.InvalidArgs" +#define DBUS_ERROR_FILE_NOT_FOUND "org.freedesktop.DBus.Error.FileNotFound" +#define DBUS_ERROR_UNKNOWN_MESSAGE "org.freedesktop.DBus.Error.UnknownMessage" typedef enum { @@ -90,6 +104,8 @@ void dbus_set_error (DBusError *error, void dbus_set_error_const (DBusError *error, const char *name, const char *message); +void dbus_move_error (DBusError *src, + DBusError *dest); dbus_bool_t dbus_error_has_name (const DBusError *error, const char *name); dbus_bool_t dbus_error_is_set (const DBusError *error); diff --git a/dbus/dbus-internals.c b/dbus/dbus-internals.c index 8dedb56..acd6d72 100644 --- a/dbus/dbus-internals.c +++ b/dbus/dbus-internals.c @@ -1,7 +1,7 @@ /* -*- mode: C; c-file-style: "gnu" -*- */ /* dbus-internals.c random utility stuff (internal to D-BUS implementation) * - * Copyright (C) 2002 Red Hat, Inc. + * Copyright (C) 2002, 2003 Red Hat, Inc. * * Licensed under the Academic Free License version 1.2 * @@ -128,6 +128,13 @@ */ /** + * Fixed "out of memory" error message, just to avoid + * making up a different string every time and wasting + * space. + */ +const char _dbus_no_memory_message[] = "Not enough memory"; + +/** * Prints a warning message to stderr. * * @param format printf-style format string. @@ -181,104 +188,6 @@ _dbus_verbose_real (const char *format, } /** - * Converts a UNIX errno into a DBusResultCode. - * - * @todo should cover more errnos, specifically those - * from open(). - * - * @param error_number the errno. - * @returns the result code. - */ -DBusResultCode -_dbus_result_from_errno (int error_number) -{ - switch (error_number) - { - case 0: - return DBUS_RESULT_SUCCESS; - -#ifdef EPROTONOSUPPORT - case EPROTONOSUPPORT: - return DBUS_RESULT_NOT_SUPPORTED; -#endif -#ifdef EAFNOSUPPORT - case EAFNOSUPPORT: - return DBUS_RESULT_NOT_SUPPORTED; -#endif -#ifdef ENFILE - case ENFILE: - return DBUS_RESULT_LIMITS_EXCEEDED; /* kernel out of memory */ -#endif -#ifdef EMFILE - case EMFILE: - return DBUS_RESULT_LIMITS_EXCEEDED; -#endif -#ifdef EACCES - case EACCES: - return DBUS_RESULT_ACCESS_DENIED; -#endif -#ifdef EPERM - case EPERM: - return DBUS_RESULT_ACCESS_DENIED; -#endif -#ifdef ENOBUFS - case ENOBUFS: - return DBUS_RESULT_NO_MEMORY; -#endif -#ifdef ENOMEM - case ENOMEM: - return DBUS_RESULT_NO_MEMORY; -#endif -#ifdef EINVAL - case EINVAL: - return DBUS_RESULT_FAILED; -#endif -#ifdef EBADF - case EBADF: - return DBUS_RESULT_FAILED; -#endif -#ifdef EFAULT - case EFAULT: - return DBUS_RESULT_FAILED; -#endif -#ifdef ENOTSOCK - case ENOTSOCK: - return DBUS_RESULT_FAILED; -#endif -#ifdef EISCONN - case EISCONN: - return DBUS_RESULT_FAILED; -#endif -#ifdef ECONNREFUSED - case ECONNREFUSED: - return DBUS_RESULT_NO_SERVER; -#endif -#ifdef ETIMEDOUT - case ETIMEDOUT: - return DBUS_RESULT_TIMEOUT; -#endif -#ifdef ENETUNREACH - case ENETUNREACH: - return DBUS_RESULT_NO_NETWORK; -#endif -#ifdef EADDRINUSE - case EADDRINUSE: - return DBUS_RESULT_ADDRESS_IN_USE; -#endif -#ifdef EEXIST - case EEXIST: - return DBUS_RESULT_FILE_NOT_FOUND; -#endif -#ifdef ENOENT - case ENOENT: - return DBUS_RESULT_FILE_NOT_FOUND; -#endif - } - - return DBUS_RESULT_FAILED; -} - -/** * Duplicates a string. Result must be freed with * dbus_free(). Returns #NULL if memory allocation fails. * If the string to be duplicated is #NULL, returns #NULL. diff --git a/dbus/dbus-internals.h b/dbus/dbus-internals.h index 19a5cdc..2576982 100644 --- a/dbus/dbus-internals.h +++ b/dbus/dbus-internals.h @@ -94,6 +94,8 @@ do { #define _DBUS_STRUCT_OFFSET(struct_type, member) \ ((long) ((unsigned char*) &((struct_type*) 0)->member)) +#define _DBUS_ASSERT_ERROR_IS_SET(error) _dbus_assert ((error) == NULL || dbus_error_is_set ((error))) + /* This alignment thing is from ORBit2 */ /* Align a value upward to a boundary, expressed as a number of bytes. * E.g. align to an 8-byte boundary with argument of 8. @@ -146,6 +148,9 @@ void _dbus_verbose_bytes_of_string (const DBusString *str, const char* _dbus_type_to_string (int type); +extern const char _dbus_no_memory_message[]; +#define _DBUS_SET_OOM(error) dbus_set_error ((error), DBUS_ERROR_NO_MEMORY, _dbus_no_memory_message) + #ifdef DBUS_BUILD_TESTS /* Memory debugging */ void _dbus_set_fail_alloc_counter (int until_next_fail); diff --git a/dbus/dbus-keyring.c b/dbus/dbus-keyring.c index c5c6a0b..db432be 100644 --- a/dbus/dbus-keyring.c +++ b/dbus/dbus-keyring.c @@ -399,6 +399,7 @@ _dbus_keyring_reload (DBusKeyring *keyring, int n_keys; int i; long now; + DBusError tmp_error; if (!_dbus_string_init (&contents, _DBUS_INT_MAX)) { @@ -434,14 +435,15 @@ _dbus_keyring_reload (DBusKeyring *keyring, have_lock = TRUE; } - result = _dbus_file_get_contents (&contents, - &keyring->filename); - - if (result != DBUS_RESULT_SUCCESS) + dbus_error_init (&tmp_error); + if (!_dbus_file_get_contents (&contents, + &keyring->filename, + &tmp_error)) { _dbus_verbose ("Failed to load keyring file: %s\n", - dbus_result_to_string (result)); + tmp_error.message); /* continue with empty keyring file, so we recreate it */ + dbus_error_free (&tmp_error); } if (!_dbus_string_validate_ascii (&contents, 0, diff --git a/dbus/dbus-list.c b/dbus/dbus-list.c index 7b30692..d0ca8df 100644 --- a/dbus/dbus-list.c +++ b/dbus/dbus-list.c @@ -678,6 +678,19 @@ _dbus_list_foreach (DBusList **list, } } +/** + * Check whether length is exactly one. + * + * @param list the list + * @returns #TRUE if length is exactly one + */ +dbus_bool_t +_dbus_list_length_is_one (DBusList **list) +{ + return (*list != NULL && + (*list)->next == *list); +} + /** @} */ #ifdef DBUS_BUILD_TESTS @@ -713,6 +726,11 @@ verify_list (DBusList **list) while (link != *list); _dbus_assert (length == _dbus_list_get_length (list)); + + if (length == 1) + _dbus_assert (_dbus_list_length_is_one (list)); + else + _dbus_assert (!_dbus_list_length_is_one (list)); } static dbus_bool_t diff --git a/dbus/dbus-list.h b/dbus/dbus-list.h index 2c55c6b..3f23f2e 100644 --- a/dbus/dbus-list.h +++ b/dbus/dbus-list.h @@ -73,6 +73,8 @@ void _dbus_list_append_link (DBusList **list, void _dbus_list_prepend_link (DBusList **list, DBusList *link); +dbus_bool_t _dbus_list_length_is_one (DBusList **list); + void _dbus_list_foreach (DBusList **list, DBusForeachFunction function, void *data); diff --git a/dbus/dbus-message-builder.c b/dbus/dbus-message-builder.c index 54b5de7..e34e1b5 100644 --- a/dbus/dbus-message-builder.c +++ b/dbus/dbus-message-builder.c @@ -314,7 +314,7 @@ _dbus_message_data_load (DBusString *dest, const DBusString *filename) { DBusString file; - DBusResultCode result; + DBusError error; DBusString line; dbus_bool_t retval; int line_no; @@ -340,14 +340,15 @@ _dbus_message_data_load (DBusString *dest, _dbus_string_get_const_data (filename, &s); _dbus_verbose ("Loading %s\n", s); } - - if ((result = _dbus_file_get_contents (&file, filename)) != DBUS_RESULT_SUCCESS) + + dbus_error_init (&error); + if (!_dbus_file_get_contents (&file, filename, &error)) { const char *s; _dbus_string_get_const_data (filename, &s); _dbus_warn ("Getting contents of %s failed: %s\n", - s, dbus_result_to_string (result)); - + s, error.message); + dbus_error_free (&error); goto out; } diff --git a/dbus/dbus-message-internal.h b/dbus/dbus-message-internal.h index 44ce62a..86796da 100644 --- a/dbus/dbus-message-internal.h +++ b/dbus/dbus-message-internal.h @@ -34,17 +34,12 @@ void _dbus_message_get_network_data (DBusMessage *message, const DBusString **header, const DBusString **body); -void _dbus_message_lock (DBusMessage *message); -void _dbus_message_unlock (DBusMessage *message); -void _dbus_message_set_client_serial (DBusMessage *message, - dbus_int32_t client_serial); -dbus_int32_t _dbus_message_get_client_serial (DBusMessage *message); -dbus_bool_t _dbus_message_set_reply_serial (DBusMessage *message, - dbus_int32_t reply_serial); -dbus_int32_t _dbus_message_get_reply_serial (DBusMessage *message); -void _dbus_message_add_size_counter (DBusMessage *message, - DBusCounter *counter); - +void _dbus_message_lock (DBusMessage *message); +void _dbus_message_unlock (DBusMessage *message); +void _dbus_message_set_serial (DBusMessage *message, + dbus_int32_t serial); +void _dbus_message_add_size_counter (DBusMessage *message, + DBusCounter *counter); DBusMessageLoader* _dbus_message_loader_new (void); void _dbus_message_loader_ref (DBusMessageLoader *loader); diff --git a/dbus/dbus-message.c b/dbus/dbus-message.c index a25480c..6a3c661 100644 --- a/dbus/dbus-message.c +++ b/dbus/dbus-message.c @@ -532,28 +532,22 @@ set_string_field (DBusMessage *message, } /** - * Sets the client serial of a message. + * Sets the serial number of a message. * This can only be done once on a message. - * - * @todo client_serial should be called simply - * "serial"; it's in outgoing messages for both - * the client and the server, it's only client-specific - * in the message bus case. It's more like origin_serial - * or something. * * @param message the message - * @param client_serial the client serial + * @param serial the serial */ void -_dbus_message_set_client_serial (DBusMessage *message, - dbus_int32_t client_serial) +_dbus_message_set_serial (DBusMessage *message, + dbus_int32_t serial) { _dbus_assert (!message->locked); - _dbus_assert (_dbus_message_get_client_serial (message) < 0); + _dbus_assert (dbus_message_get_serial (message) < 0); set_int_field (message, FIELD_CLIENT_SERIAL, - client_serial); - message->client_serial = client_serial; + serial); + message->client_serial = serial; } /** @@ -565,7 +559,7 @@ _dbus_message_set_client_serial (DBusMessage *message, * @returns #FALSE if not enough memory */ dbus_bool_t -_dbus_message_set_reply_serial (DBusMessage *message, +dbus_message_set_reply_serial (DBusMessage *message, dbus_int32_t reply_serial) { _dbus_assert (!message->locked); @@ -581,19 +575,15 @@ _dbus_message_set_reply_serial (DBusMessage *message, } /** - * Returns the client serial of a message or - * -1 if none has been specified. - * - * @todo see note in _dbus_message_set_client_serial() - * about how client_serial is a misnomer - * - * @todo this function should be public, after renaming it. + * Returns the serial of a message or -1 if none has been specified. + * The message's serial number is provided by the application sending + * the message and is used to identify replies to this message. * * @param message the message * @returns the client serial */ dbus_int32_t -_dbus_message_get_client_serial (DBusMessage *message) +dbus_message_get_serial (DBusMessage *message) { return message->client_serial; } @@ -606,7 +596,7 @@ _dbus_message_get_client_serial (DBusMessage *message) * @returns the reply serial */ dbus_int32_t -_dbus_message_get_reply_serial (DBusMessage *message) +dbus_message_get_reply_serial (DBusMessage *message) { return message->reply_serial; } @@ -845,8 +835,8 @@ dbus_message_new_reply (DBusMessage *original_message) if (message == NULL) return NULL; - if (!_dbus_message_set_reply_serial (message, - _dbus_message_get_client_serial (original_message))) + if (!dbus_message_set_reply_serial (message, + dbus_message_get_serial (original_message))) { dbus_message_unref (message); return NULL; @@ -881,8 +871,8 @@ dbus_message_new_error_reply (DBusMessage *original_message, if (message == NULL) return NULL; - if (!_dbus_message_set_reply_serial (message, - _dbus_message_get_client_serial (original_message))) + if (!dbus_message_set_reply_serial (message, + dbus_message_get_serial (original_message))) { dbus_message_unref (message); return NULL; @@ -1542,12 +1532,14 @@ dbus_message_append_dict (DBusMessage *message, * stored. The list is terminated with 0. * * @param message the message + * @param error error to be filled in on failure * @param first_arg_type the first argument type * @param ... location for first argument value, then list of type-location pairs - * @returns result code + * @returns #FALSE if the error was set */ -DBusResultCode +dbus_bool_t dbus_message_get_args (DBusMessage *message, + DBusError *error, int first_arg_type, ...) { @@ -1555,7 +1547,7 @@ dbus_message_get_args (DBusMessage *message, va_list var_args; va_start (var_args, first_arg_type); - retval = dbus_message_get_args_valist (message, first_arg_type, var_args); + retval = dbus_message_get_args_valist (message, error, first_arg_type, var_args); va_end (var_args); return retval; @@ -1575,22 +1567,31 @@ dbus_message_get_args (DBusMessage *message, * * @see dbus_message_get_args * @param message the message + * @param error error to be filled in * @param first_arg_type type of the first argument * @param var_args return location for first argument, followed by list of type/location pairs - * @returns result code + * @returns #FALSE if error was set */ -DBusResultCode +dbus_bool_t dbus_message_get_args_valist (DBusMessage *message, + DBusError *error, int first_arg_type, va_list var_args) { int spec_type, msg_type, i; DBusMessageIter *iter; - + dbus_bool_t retval; + iter = dbus_message_get_args_iter (message); if (iter == NULL) - return DBUS_RESULT_NO_MEMORY; + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, + "No memory to get message arguments"); + return FALSE; + } + + retval = FALSE; spec_type = first_arg_type; i = 0; @@ -1601,13 +1602,13 @@ dbus_message_get_args_valist (DBusMessage *message, if (msg_type != spec_type) { - _dbus_verbose ("Argument %d is specified to be of type \"%s\", but " - "is actually of type \"%s\"\n", i, - _dbus_type_to_string (spec_type), - _dbus_type_to_string (msg_type)); - dbus_message_iter_unref (iter); + dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, + "Argument %d is specified to be of type \"%s\", but " + "is actually of type \"%s\"\n", i, + _dbus_type_to_string (spec_type), + _dbus_type_to_string (msg_type)); - return DBUS_RESULT_INVALID_ARGS; + goto out; } switch (spec_type) @@ -1661,7 +1662,11 @@ dbus_message_get_args_valist (DBusMessage *message, *ptr = dbus_message_iter_get_string (iter); if (!*ptr) - return DBUS_RESULT_NO_MEMORY; + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, + "No memory for argument %d", i); + goto out; + } break; } @@ -1675,8 +1680,11 @@ dbus_message_get_args_valist (DBusMessage *message, len = va_arg (var_args, int *); if (!dbus_message_iter_get_boolean_array (iter, ptr, len)) - return DBUS_RESULT_NO_MEMORY; - + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, + "No memory for argument %d", i); + goto out; + } break; } @@ -1689,7 +1697,11 @@ dbus_message_get_args_valist (DBusMessage *message, len = va_arg (var_args, int *); if (!dbus_message_iter_get_int32_array (iter, ptr, len)) - return DBUS_RESULT_NO_MEMORY; + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, + "No memory for argument %d", i); + goto out; + } break; } @@ -1703,7 +1715,11 @@ dbus_message_get_args_valist (DBusMessage *message, len = va_arg (var_args, int *); if (!dbus_message_iter_get_uint32_array (iter, ptr, len)) - return DBUS_RESULT_NO_MEMORY; + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, + "No memory for argument %d", i); + goto out; + } break; } @@ -1717,8 +1733,11 @@ dbus_message_get_args_valist (DBusMessage *message, len = va_arg (var_args, int *); if (!dbus_message_iter_get_double_array (iter, ptr, len)) - return DBUS_RESULT_NO_MEMORY; - + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, + "No memory for argument %d", i); + goto out; + } break; } @@ -1731,8 +1750,11 @@ dbus_message_get_args_valist (DBusMessage *message, len = va_arg (var_args, int *); if (!dbus_message_iter_get_byte_array (iter, ptr, len)) - return DBUS_RESULT_NO_MEMORY; - + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, + "No memory for argument %d", i); + goto out; + } break; } case DBUS_TYPE_STRING_ARRAY: @@ -1744,7 +1766,11 @@ dbus_message_get_args_valist (DBusMessage *message, len = va_arg (var_args, int *); if (!dbus_message_iter_get_string_array (iter, ptr, len)) - return DBUS_RESULT_NO_MEMORY; + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, + "No memory for argument %d", i); + goto out; + } break; } case DBUS_TYPE_DICT: @@ -1754,7 +1780,11 @@ dbus_message_get_args_valist (DBusMessage *message, dict = va_arg (var_args, DBusDict **); if (!dbus_message_iter_get_dict (iter, dict)) - return DBUS_RESULT_NO_MEMORY; + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, + "No memory for argument %d", i); + goto out; + } break; } default: @@ -1763,17 +1793,20 @@ dbus_message_get_args_valist (DBusMessage *message, spec_type = va_arg (var_args, int); if (spec_type != 0 && !dbus_message_iter_next (iter)) - { - _dbus_verbose ("More fields than exist in the message were specified or field is corrupt\n"); + { + dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, + "Message has only %d arguments, but more were expected", i); + goto out; + } - dbus_message_iter_unref (iter); - return DBUS_RESULT_INVALID_ARGS; - } i++; } - + + retval = TRUE; + + out: dbus_message_iter_unref (iter); - return DBUS_RESULT_SUCCESS; + return retval; } /** @@ -2318,6 +2351,10 @@ dbus_message_name_is (DBusMessage *message, * DBusTransport implementation. The DBusTransport then hands off * the loaded messages to a DBusConnection, making the messages * visible to the application. + * + * @todo write tests for break-loader that a) randomly delete header + * fields and b) set string fields to zero-length and other funky + * values. * */ @@ -2624,6 +2661,13 @@ decode_header_data (const DBusString *data, } } + if (fields[FIELD_NAME].offset < 0) + { + _dbus_verbose ("No %s field provided\n", + DBUS_HEADER_FIELD_NAME); + return FALSE; + } + if (message_padding) *message_padding = header_len - pos; @@ -2970,13 +3014,13 @@ check_message_handling (DBusMessage *message) retval = FALSE; iter = NULL; - client_serial = _dbus_message_get_client_serial (message); + client_serial = dbus_message_get_serial (message); - /* can't use set_client_serial due to the assertions at the start of it */ + /* can't use set_serial due to the assertions at the start of it */ set_int_field (message, FIELD_CLIENT_SERIAL, client_serial); - - if (client_serial != _dbus_message_get_client_serial (message)) + + if (client_serial != dbus_message_get_serial (message)) { _dbus_warn ("get/set cycle for client_serial did not succeed\n"); goto failed; @@ -3215,14 +3259,15 @@ dbus_internal_do_not_use_load_message_file (const DBusString *filename, if (is_raw) { - DBusResultCode result; + DBusError error; - result = _dbus_file_get_contents (data, filename); - if (result != DBUS_RESULT_SUCCESS) + dbus_error_init (&error); + if (!_dbus_file_get_contents (data, filename, &error)) { const char *s; _dbus_string_get_const_data (filename, &s); - _dbus_warn ("Could not load message file %s\n", s); + _dbus_warn ("Could not load message file %s: %s\n", s, error.message); + dbus_error_free (&error); goto failed; } } @@ -3397,7 +3442,7 @@ process_test_subdir (const DBusString *test_base_dir, DBusString filename; DBusDirIter *dir; dbus_bool_t retval; - DBusResultCode result; + DBusError error; retval = FALSE; dir = NULL; @@ -3417,22 +3462,23 @@ process_test_subdir (const DBusString *test_base_dir, _dbus_string_free (&filename); if (!_dbus_string_init (&filename, _DBUS_INT_MAX)) _dbus_assert_not_reached ("didn't allocate filename string\n"); - - dir = _dbus_directory_open (&test_directory, &result); + + dbus_error_init (&error); + dir = _dbus_directory_open (&test_directory, &error); if (dir == NULL) { const char *s; _dbus_string_get_const_data (&test_directory, &s); _dbus_warn ("Could not open %s: %s\n", s, - dbus_result_to_string (result)); + error.message); + dbus_error_free (&error); goto failed; } printf ("Testing:\n"); - result = DBUS_RESULT_SUCCESS; next: - while (_dbus_directory_get_next_file (dir, &filename, &result)) + while (_dbus_directory_get_next_file (dir, &filename, &error)) { DBusString full_path; dbus_bool_t is_raw; @@ -3480,12 +3526,13 @@ process_test_subdir (const DBusString *test_base_dir, _dbus_string_free (&full_path); } - if (result != DBUS_RESULT_SUCCESS) + if (dbus_error_is_set (&error)) { const char *s; _dbus_string_get_const_data (&test_directory, &s); _dbus_warn ("Could not get next file in %s: %s\n", - s, dbus_result_to_string (result)); + s, error.message); + dbus_error_free (&error); goto failed; } @@ -3563,7 +3610,7 @@ _dbus_message_test (const char *test_data_dir) /* Test the vararg functions */ message = dbus_message_new ("org.freedesktop.DBus.Test", "testMessage"); - _dbus_message_set_client_serial (message, 1); + _dbus_message_set_serial (message, 1); dbus_message_append_args (message, DBUS_TYPE_INT32, -0x12345678, DBUS_TYPE_STRING, "Test string", @@ -3574,13 +3621,13 @@ _dbus_message_test (const char *test_data_dir) _dbus_string_get_length (&message->header)); _dbus_verbose_bytes_of_string (&message->body, 0, _dbus_string_get_length (&message->body)); - - if (dbus_message_get_args (message, - DBUS_TYPE_INT32, &our_int, - DBUS_TYPE_STRING, &our_str, - DBUS_TYPE_DOUBLE, &our_double, - DBUS_TYPE_BOOLEAN, &our_bool, - 0) != DBUS_RESULT_SUCCESS) + + if (!dbus_message_get_args (message, NULL, + DBUS_TYPE_INT32, &our_int, + DBUS_TYPE_STRING, &our_str, + DBUS_TYPE_DOUBLE, &our_double, + DBUS_TYPE_BOOLEAN, &our_bool, + 0)) _dbus_assert_not_reached ("Could not get arguments"); if (our_int != -0x12345678) @@ -3599,8 +3646,8 @@ _dbus_message_test (const char *test_data_dir) dbus_message_unref (message); message = dbus_message_new ("org.freedesktop.DBus.Test", "testMessage"); - _dbus_message_set_client_serial (message, 1); - _dbus_message_set_reply_serial (message, 0x12345678); + _dbus_message_set_serial (message, 1); + dbus_message_set_reply_serial (message, 0x12345678); dbus_message_append_string (message, "Test string"); dbus_message_append_int32 (message, -0x12345678); @@ -3645,7 +3692,7 @@ _dbus_message_test (const char *test_data_dir) if (!message) _dbus_assert_not_reached ("received a NULL message"); - if (_dbus_message_get_reply_serial (message) != 0x12345678) + if (dbus_message_get_reply_serial (message) != 0x12345678) _dbus_assert_not_reached ("reply serial fields differ"); message_iter_test (message); diff --git a/dbus/dbus-message.h b/dbus/dbus-message.h index 4ea6306..d30a0a3 100644 --- a/dbus/dbus-message.h +++ b/dbus/dbus-message.h @@ -48,17 +48,21 @@ DBusMessage *dbus_message_new_from_message (const DBusMessage *message); void dbus_message_ref (DBusMessage *message); void dbus_message_unref (DBusMessage *message); -const char* dbus_message_get_name (DBusMessage *message); -const char* dbus_message_get_service (DBusMessage *message); -dbus_bool_t dbus_message_set_sender (DBusMessage *message, - const char *sender); -const char* dbus_message_get_sender (DBusMessage *message); -void dbus_message_set_is_error (DBusMessage *message, - dbus_bool_t is_error_reply); -dbus_bool_t dbus_message_get_is_error (DBusMessage *message); +const char* dbus_message_get_name (DBusMessage *message); +const char* dbus_message_get_service (DBusMessage *message); +dbus_bool_t dbus_message_set_sender (DBusMessage *message, + const char *sender); +const char* dbus_message_get_sender (DBusMessage *message); +void dbus_message_set_is_error (DBusMessage *message, + dbus_bool_t is_error_reply); +dbus_bool_t dbus_message_get_is_error (DBusMessage *message); +dbus_bool_t dbus_message_name_is (DBusMessage *message, + const char *name); +dbus_int32_t dbus_message_get_serial (DBusMessage *message); +dbus_bool_t dbus_message_set_reply_serial (DBusMessage *message, + dbus_int32_t reply_serial); +dbus_int32_t dbus_message_get_reply_serial (DBusMessage *message); -dbus_bool_t dbus_message_name_is (DBusMessage *message, - const char *name); dbus_bool_t dbus_message_append_args (DBusMessage *message, int first_arg_type, @@ -99,13 +103,14 @@ dbus_bool_t dbus_message_append_dict (DBusMessage *message, DBusDict *dict); DBusMessageIter *dbus_message_get_args_iter (DBusMessage *message); -DBusResultCode dbus_message_get_args (DBusMessage *message, - int first_arg_type, - ...); -DBusResultCode dbus_message_get_args_valist (DBusMessage *message, - int first_arg_type, - va_list var_args); - +dbus_bool_t dbus_message_get_args (DBusMessage *message, + DBusError *error, + int first_arg_type, + ...); +dbus_bool_t dbus_message_get_args_valist (DBusMessage *message, + DBusError *error, + int first_arg_type, + va_list var_args); void dbus_message_iter_ref (DBusMessageIter *iter); diff --git a/dbus/dbus-sha.c b/dbus/dbus-sha.c index 2f73e36..8f04712 100644 --- a/dbus/dbus-sha.c +++ b/dbus/dbus-sha.c @@ -752,6 +752,7 @@ process_test_data (const char *test_data_dir) int line_no; dbus_bool_t retval; int success_count; + DBusError error; retval = FALSE; @@ -784,21 +785,24 @@ process_test_data (const char *test_data_dir) if (!_dbus_concat_dir_and_file (&results_file, &tmp)) _dbus_assert_not_reached ("no memory"); - if (_dbus_file_get_contents (&tests, &tests_file) != DBUS_RESULT_SUCCESS) + dbus_error_init (&error); + if (!_dbus_file_get_contents (&tests, &tests_file, &error)) { const char *s; _dbus_string_get_const_data (&tests_file, &s); - fprintf (stderr, "could not load test data file %s\n", - s); + fprintf (stderr, "could not load test data file %s: %s\n", + s, error.message); + dbus_error_free (&error); goto out; } - if (_dbus_file_get_contents (&results, &results_file) != DBUS_RESULT_SUCCESS) + if (!_dbus_file_get_contents (&results, &results_file, &error)) { const char *s; _dbus_string_get_const_data (&results_file, &s); - fprintf (stderr, "could not load results data file %s\n", - s); + fprintf (stderr, "could not load results data file %s: %s\n", + s, error.message); + dbus_error_free (&error); goto out; } diff --git a/dbus/dbus-sysdeps.c b/dbus/dbus-sysdeps.c index d096ce3..5d0be32 100644 --- a/dbus/dbus-sysdeps.c +++ b/dbus/dbus-sysdeps.c @@ -1,7 +1,7 @@ /* -*- mode: C; c-file-style: "gnu" -*- */ /* dbus-sysdeps.c Wrappers around system/libc features (internal to D-BUS implementation) * - * Copyright (C) 2002 Red Hat, Inc. + * Copyright (C) 2002, 2003 Red Hat, Inc. * * Licensed under the Academic Free License version 1.2 * @@ -1604,11 +1604,13 @@ _dbus_get_current_time (long *tv_sec, * * @param str the string to append to * @param filename filename to load - * @returns result + * @param error place to set an error + * @returns #FALSE if error was set */ -DBusResultCode +dbus_bool_t _dbus_file_get_contents (DBusString *str, - const DBusString *filename) + const DBusString *filename, + DBusError *error) { int fd; struct stat sb; @@ -1621,28 +1623,32 @@ _dbus_file_get_contents (DBusString *str, /* O_BINARY useful on Cygwin */ fd = open (filename_c, O_RDONLY | O_BINARY); if (fd < 0) - return _dbus_result_from_errno (errno); + { + dbus_set_error (error, _dbus_error_from_errno (errno), + "%s", _dbus_strerror (errno)); + return FALSE; + } if (fstat (fd, &sb) < 0) { - DBusResultCode result; - - result = _dbus_result_from_errno (errno); /* prior to close() */ + dbus_set_error (error, _dbus_error_from_errno (errno), + "%s", _dbus_strerror (errno)); _dbus_verbose ("fstat() failed: %s", _dbus_strerror (errno)); close (fd); - return result; + return FALSE; } if (sb.st_size > _DBUS_ONE_MEGABYTE) { - _dbus_verbose ("File size %lu is too large.\n", + dbus_set_error (error, DBUS_ERROR_FAILED, + "File size %lu is too large.\n", (unsigned long) sb.st_size); close (fd); - return DBUS_RESULT_FAILED; + return FALSE; } total = 0; @@ -1657,34 +1663,35 @@ _dbus_file_get_contents (DBusString *str, sb.st_size - total); if (bytes_read <= 0) { - DBusResultCode result; - - result = _dbus_result_from_errno (errno); /* prior to close() */ + dbus_set_error (error, _dbus_error_from_errno (errno), + "%s", _dbus_strerror (errno)); _dbus_verbose ("read() failed: %s", _dbus_strerror (errno)); close (fd); _dbus_string_set_length (str, orig_len); - return result; + return FALSE; } else total += bytes_read; } close (fd); - return DBUS_RESULT_SUCCESS; + return TRUE; } else if (sb.st_size != 0) { _dbus_verbose ("Can only open regular files at the moment.\n"); + dbus_set_error (error, DBUS_ERROR_FAILED, + "Not a regular file"); close (fd); - return DBUS_RESULT_FAILED; + return FALSE; } else { close (fd); - return DBUS_RESULT_SUCCESS; + return TRUE; } } @@ -1972,12 +1979,12 @@ struct DBusDirIter * Open a directory to iterate over. * * @param filename the directory name - * @param result return location for error code if #NULL returned + * @param error exception return object or #NULL * @returns new iterator, or #NULL on error */ DBusDirIter* _dbus_directory_open (const DBusString *filename, - DBusResultCode *result) + DBusError *error) { DIR *d; DBusDirIter *iter; @@ -1988,15 +1995,16 @@ _dbus_directory_open (const DBusString *filename, d = opendir (filename_c); if (d == NULL) { - dbus_set_result (result, _dbus_result_from_errno (errno)); + dbus_set_error (error, _dbus_error_from_errno (errno), + "%s", _dbus_strerror (errno)); return NULL; } - iter = dbus_new0 (DBusDirIter, 1); if (iter == NULL) { closedir (d); - dbus_set_result (result, DBUS_RESULT_NO_MEMORY); + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, + "Could not allocate memory for directory iterator"); return NULL; } @@ -2006,39 +2014,38 @@ _dbus_directory_open (const DBusString *filename, } /** - * Get next file in the directory. Will not return "." or ".." - * on UNIX. If an error occurs, the contents of "filename" - * are undefined. #DBUS_RESULT_SUCCESS is always returned - * in result if no error occurs. + * Get next file in the directory. Will not return "." or ".." on + * UNIX. If an error occurs, the contents of "filename" are + * undefined. The error is never set if the function succeeds. * * @todo for thread safety, I think we have to use * readdir_r(). (GLib has the same issue, should file a bug.) * * @param iter the iterator * @param filename string to be set to the next file in the dir - * @param result return location for error, or #DBUS_RESULT_SUCCESS + * @param error return location for error * @returns #TRUE if filename was filled in with a new filename */ dbus_bool_t _dbus_directory_get_next_file (DBusDirIter *iter, DBusString *filename, - DBusResultCode *result) + DBusError *error) { /* we always have to put something in result, since return * value means whether there's a filename and doesn't * reliably indicate whether an error was set. */ struct dirent *ent; - - dbus_set_result (result, DBUS_RESULT_SUCCESS); again: errno = 0; ent = readdir (iter->d); if (ent == NULL) { - dbus_set_result (result, - _dbus_result_from_errno (errno)); + if (errno != 0) + dbus_set_error (error, + _dbus_error_from_errno (errno), + "%s", _dbus_strerror (errno)); return FALSE; } else if (ent->d_name[0] == '.' && @@ -2050,7 +2057,8 @@ _dbus_directory_get_next_file (DBusDirIter *iter, _dbus_string_set_length (filename, 0); if (!_dbus_string_append (filename, ent->d_name)) { - dbus_set_result (result, DBUS_RESULT_NO_MEMORY); + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, + "No memory to read directory entry"); return FALSE; } else @@ -2501,4 +2509,249 @@ _dbus_fd_set_close_on_exec (int fd) fcntl (fd, F_SETFD, val); } + +/** + * Converts a UNIX errno into a DBusResultCode. + * + * @todo should cover more errnos, specifically those + * from open(). + * + * @param error_number the errno. + * @returns the result code. + */ +DBusResultCode +_dbus_result_from_errno (int error_number) +{ + switch (error_number) + { + case 0: + return DBUS_RESULT_SUCCESS; + +#ifdef EPROTONOSUPPORT + case EPROTONOSUPPORT: + return DBUS_RESULT_NOT_SUPPORTED; +#endif +#ifdef EAFNOSUPPORT + case EAFNOSUPPORT: + return DBUS_RESULT_NOT_SUPPORTED; +#endif +#ifdef ENFILE + case ENFILE: + return DBUS_RESULT_LIMITS_EXCEEDED; /* kernel out of memory */ +#endif +#ifdef EMFILE + case EMFILE: + return DBUS_RESULT_LIMITS_EXCEEDED; +#endif +#ifdef EACCES + case EACCES: + return DBUS_RESULT_ACCESS_DENIED; +#endif +#ifdef EPERM + case EPERM: + return DBUS_RESULT_ACCESS_DENIED; +#endif +#ifdef ENOBUFS + case ENOBUFS: + return DBUS_RESULT_NO_MEMORY; +#endif +#ifdef ENOMEM + case ENOMEM: + return DBUS_RESULT_NO_MEMORY; +#endif +#ifdef EINVAL + case EINVAL: + return DBUS_RESULT_FAILED; +#endif +#ifdef EBADF + case EBADF: + return DBUS_RESULT_FAILED; +#endif +#ifdef EFAULT + case EFAULT: + return DBUS_RESULT_FAILED; +#endif +#ifdef ENOTSOCK + case ENOTSOCK: + return DBUS_RESULT_FAILED; +#endif +#ifdef EISCONN + case EISCONN: + return DBUS_RESULT_FAILED; +#endif +#ifdef ECONNREFUSED + case ECONNREFUSED: + return DBUS_RESULT_NO_SERVER; +#endif +#ifdef ETIMEDOUT + case ETIMEDOUT: + return DBUS_RESULT_TIMEOUT; +#endif +#ifdef ENETUNREACH + case ENETUNREACH: + return DBUS_RESULT_NO_NETWORK; +#endif +#ifdef EADDRINUSE + case EADDRINUSE: + return DBUS_RESULT_ADDRESS_IN_USE; +#endif +#ifdef EEXIST + case EEXIST: + return DBUS_RESULT_FILE_NOT_FOUND; +#endif +#ifdef ENOENT + case ENOENT: + return DBUS_RESULT_FILE_NOT_FOUND; +#endif + } + + return DBUS_RESULT_FAILED; +} + +/** + * Converts a UNIX errno into a #DBusError name. + * + * @todo should cover more errnos, specifically those + * from open(). + * + * @param error_number the errno. + * @returns an error name + */ +const char* +_dbus_error_from_errno (int error_number) +{ + switch (error_number) + { + case 0: + return DBUS_ERROR_FAILED; + +#ifdef EPROTONOSUPPORT + case EPROTONOSUPPORT: + return DBUS_ERROR_NOT_SUPPORTED; +#endif +#ifdef EAFNOSUPPORT + case EAFNOSUPPORT: + return DBUS_ERROR_NOT_SUPPORTED; +#endif +#ifdef ENFILE + case ENFILE: + return DBUS_ERROR_LIMITS_EXCEEDED; /* kernel out of memory */ +#endif +#ifdef EMFILE + case EMFILE: + return DBUS_ERROR_LIMITS_EXCEEDED; +#endif +#ifdef EACCES + case EACCES: + return DBUS_ERROR_ACCESS_DENIED; +#endif +#ifdef EPERM + case EPERM: + return DBUS_ERROR_ACCESS_DENIED; +#endif +#ifdef ENOBUFS + case ENOBUFS: + return DBUS_ERROR_NO_MEMORY; +#endif +#ifdef ENOMEM + case ENOMEM: + return DBUS_ERROR_NO_MEMORY; +#endif +#ifdef EINVAL + case EINVAL: + return DBUS_ERROR_FAILED; +#endif +#ifdef EBADF + case EBADF: + return DBUS_ERROR_FAILED; +#endif +#ifdef EFAULT + case EFAULT: + return DBUS_ERROR_FAILED; +#endif +#ifdef ENOTSOCK + case ENOTSOCK: + return DBUS_ERROR_FAILED; +#endif +#ifdef EISCONN + case EISCONN: + return DBUS_ERROR_FAILED; +#endif +#ifdef ECONNREFUSED + case ECONNREFUSED: + return DBUS_ERROR_NO_SERVER; +#endif +#ifdef ETIMEDOUT + case ETIMEDOUT: + return DBUS_ERROR_TIMEOUT; +#endif +#ifdef ENETUNREACH + case ENETUNREACH: + return DBUS_ERROR_NO_NETWORK; +#endif +#ifdef EADDRINUSE + case EADDRINUSE: + return DBUS_ERROR_ADDRESS_IN_USE; +#endif +#ifdef EEXIST + case EEXIST: + return DBUS_ERROR_FILE_NOT_FOUND; +#endif +#ifdef ENOENT + case ENOENT: + return DBUS_ERROR_FILE_NOT_FOUND; +#endif + } + + return DBUS_ERROR_FAILED; +} + +/** + * Exit the process, returning the given value. + * + * @param code the exit code + */ +void +_dbus_exit (int code) +{ + _exit (code); +} + +/** + * stat() wrapper. + * + * @param filename the filename to stat + * @param statbuf the stat info to fill in + * @param error return location for error + * @returns #FALSE if error was set + */ +dbus_bool_t +_dbus_stat (const DBusString *filename, + DBusStat *statbuf, + DBusError *error) +{ + const char *filename_c; + struct stat sb; + + _dbus_string_get_const_data (filename, &filename_c); + + if (stat (filename_c, &sb) < 0) + { + dbus_set_error (error, _dbus_error_from_errno (errno), + "%s", _dbus_strerror (errno)); + return FALSE; + } + + statbuf->mode = sb.st_mode; + statbuf->nlink = sb.st_nlink; + statbuf->uid = sb.st_uid; + statbuf->gid = sb.st_gid; + statbuf->size = sb.st_size; + statbuf->atime = sb.st_atime; + statbuf->mtime = sb.st_mtime; + statbuf->ctime = sb.st_ctime; + + return TRUE; +} + /** @} end of sysdeps */ diff --git a/dbus/dbus-sysdeps.h b/dbus/dbus-sysdeps.h index fb8362e..f1ac47c 100644 --- a/dbus/dbus-sysdeps.h +++ b/dbus/dbus-sysdeps.h @@ -138,8 +138,9 @@ void _dbus_sleep_milliseconds (int milliseconds); void _dbus_get_current_time (long *tv_sec, long *tv_usec); -DBusResultCode _dbus_file_get_contents (DBusString *str, - const DBusString *filename); +dbus_bool_t _dbus_file_get_contents (DBusString *str, + const DBusString *filename, + DBusError *error); DBusResultCode _dbus_string_save_to_file (const DBusString *str, const DBusString *filename); @@ -156,17 +157,18 @@ dbus_bool_t _dbus_concat_dir_and_file (DBusString *dir, typedef struct DBusDirIter DBusDirIter; DBusDirIter* _dbus_directory_open (const DBusString *filename, - DBusResultCode *result); + DBusError *error); dbus_bool_t _dbus_directory_get_next_file (DBusDirIter *iter, DBusString *filename, - DBusResultCode *result); + DBusError *error); void _dbus_directory_close (DBusDirIter *iter); dbus_bool_t _dbus_generate_random_bytes (DBusString *str, int n_bytes); -const char *_dbus_errno_to_string (int errnum); +const char *_dbus_errno_to_string (int errnum); +const char* _dbus_error_from_errno (int error_number); typedef void (* DBusSpawnChildSetupFunc) (void *user_data); @@ -180,6 +182,24 @@ void _dbus_disable_sigpipe (void); void _dbus_fd_set_close_on_exec (int fd); +void _dbus_exit (int code); + +typedef struct +{ + unsigned long mode; + unsigned long nlink; + unsigned long uid; + unsigned long gid; + unsigned long size; + unsigned long atime; + unsigned long mtime; + unsigned long ctime; +} DBusStat; + +dbus_bool_t _dbus_stat (const DBusString *filename, + DBusStat *statbuf, + DBusError *error); + DBUS_END_DECLS; #endif /* DBUS_SYSDEPS_H */ diff --git a/glib/test-dbus-glib.c b/glib/test-dbus-glib.c index fe9cd6b..b5c4402 100644 --- a/glib/test-dbus-glib.c +++ b/glib/test-dbus-glib.c @@ -7,13 +7,13 @@ main (int argc, char **argv) { DBusConnection *connection; DBusResultCode result; - DBusMessage *message, *reply; - + DBusMessage *message, *reply; GMainLoop *loop; + DBusError error; if (argc < 2) { - fprintf (stderr, "Give the server address as an argument\n"); + g_printerr ("Give the server address as an argument\n"); return 1; } @@ -22,8 +22,8 @@ main (int argc, char **argv) connection = dbus_connection_open (argv[1], &result); if (connection == NULL) { - fprintf (stderr, "Failed to open connection to %s: %s\n", argv[1], - dbus_result_to_string (result)); + g_printerr ("Failed to open connection to %s: %s\n", argv[1], + dbus_result_to_string (result)); return 1; } @@ -31,7 +31,15 @@ main (int argc, char **argv) message = dbus_message_new ("org.freedesktop.DBus", "org.freedesktop.DBus.Hello"); - reply = dbus_connection_send_message_with_reply_and_block (connection, message, -1, &result); + dbus_error_init (&error); + reply = dbus_connection_send_with_reply_and_block (connection, message, -1, &error); + if (reply == NULL) + { + g_printerr ("Error on hello message: %s\n", error.message); + dbus_error_free (&error); + return 1; + } + g_print ("reply name: %s\n", dbus_message_get_name (reply)); g_main_loop_run (loop); diff --git a/glib/test-thread-client.c b/glib/test-thread-client.c index ca78dbb..23ec3f3 100644 --- a/glib/test-thread-client.c +++ b/glib/test-thread-client.c @@ -37,12 +37,13 @@ thread_func (gpointer data) } g_free (str); - if (!dbus_connection_send_message (connection, - message, - NULL, NULL)) + if (!dbus_connection_send (connection, + message, + NULL)) { - g_print ("thread %d: send message failerd\n", threadnr); + g_print ("thread %d: send message failed\n", threadnr); } + dbus_message_unref (message); counter ++; diff --git a/test/bus-test.c b/test/bus-test.c index 342e806..e059e6c 100644 --- a/test/bus-test.c +++ b/test/bus-test.c @@ -62,24 +62,34 @@ test_hello_client1_handler (DBusMessageHandler *handler, if (!test_hello_succeeding) goto out; + +#if 1 + printf ("In stage %d got message %s\n", + client1_stage, dbus_message_get_name (message)); +#endif if (dbus_message_name_is (message, DBUS_MESSAGE_HELLO)) { TEST_HELLO_HANDLE_FAIL (client1_stage == 0); - TEST_HELLO_HANDLE_FAIL ((dbus_message_get_args (message, - DBUS_TYPE_STRING, &client1_name, - 0) == DBUS_RESULT_SUCCESS)); + TEST_HELLO_HANDLE_FAIL (dbus_message_get_args (message, NULL, + DBUS_TYPE_STRING, &client1_name, + 0)); client1_stage += 1; } else if (dbus_message_name_is (message, DBUS_MESSAGE_SERVICE_CREATED)) { - TEST_HELLO_HANDLE_FAIL (client1_stage == 1 || client1_stage == 3); + TEST_HELLO_HANDLE_FAIL (dbus_message_get_args (message, NULL, + DBUS_TYPE_STRING, &tmp, + 0)); - TEST_HELLO_HANDLE_FAIL ((dbus_message_get_args (message, - DBUS_TYPE_STRING, &tmp, - 0) == DBUS_RESULT_SUCCESS)); +#if 0 + printf ("ServiceCreated is %s\n", tmp); +#endif + + TEST_HELLO_HANDLE_FAIL (client1_stage == 1 || client1_stage == 3); + if (client1_stage == 1) TEST_HELLO_HANDLE_FAIL (strcmp (client1_name, tmp) == 0); else @@ -94,9 +104,9 @@ test_hello_client1_handler (DBusMessageHandler *handler, { TEST_HELLO_HANDLE_FAIL (client1_stage == 2); - TEST_HELLO_HANDLE_FAIL ((dbus_message_get_args (message, - DBUS_TYPE_STRING, &tmp, - 0) == DBUS_RESULT_SUCCESS)); + TEST_HELLO_HANDLE_FAIL (dbus_message_get_args (message, NULL, + DBUS_TYPE_STRING, &tmp, + 0)); TEST_HELLO_HANDLE_FAIL (strcmp (client1_name, tmp) == 0); client1_stage += 1; @@ -132,9 +142,9 @@ test_hello_client2_handler (DBusMessageHandler *handler, { TEST_HELLO_HANDLE_FAIL (client2_stage == 0); - TEST_HELLO_HANDLE_FAIL ((dbus_message_get_args (message, - DBUS_TYPE_STRING, &client2_name, - 0) == DBUS_RESULT_SUCCESS)); + TEST_HELLO_HANDLE_FAIL (dbus_message_get_args (message, NULL, + DBUS_TYPE_STRING, &client2_name, + 0)); client2_stage += 1; } @@ -142,9 +152,9 @@ test_hello_client2_handler (DBusMessageHandler *handler, { TEST_HELLO_HANDLE_FAIL (client2_stage == 1); - TEST_HELLO_HANDLE_FAIL ((dbus_message_get_args (message, - DBUS_TYPE_STRING, &tmp, - 0) == DBUS_RESULT_SUCCESS)); + TEST_HELLO_HANDLE_FAIL (dbus_message_get_args (message, NULL, + DBUS_TYPE_STRING, &tmp, + 0)); TEST_HELLO_HANDLE_FAIL (strcmp (client2_name, tmp) == 0); client2_stage += 1; @@ -153,9 +163,9 @@ test_hello_client2_handler (DBusMessageHandler *handler, { TEST_HELLO_HANDLE_FAIL (client2_stage == 2); - TEST_HELLO_HANDLE_FAIL ((dbus_message_get_args (message, - DBUS_TYPE_STRING, &tmp, - 0) == DBUS_RESULT_SUCCESS)); + TEST_HELLO_HANDLE_FAIL (dbus_message_get_args (message, NULL, + DBUS_TYPE_STRING, &tmp, + 0)); TEST_HELLO_HANDLE_FAIL (strcmp (client2_name, tmp) == 0); client2_stage += 1; @@ -177,9 +187,9 @@ static dbus_bool_t test_hello_replies (void) { DBusConnection *connection; - DBusResultCode result; DBusMessage *message; DBusMessageHandler *handler; + DBusResultCode result; /* First start client 1 */ connection = dbus_connection_open ("debug:name=test-server", &result); @@ -188,7 +198,8 @@ test_hello_replies (void) DBUS_MESSAGE_HELLO); handler = dbus_message_handler_new (test_hello_client1_handler, NULL, NULL); dbus_connection_add_filter (connection, handler); - dbus_connection_send_message (connection, message, NULL, NULL); + if (!dbus_connection_send (connection, message, NULL)) + die ("no memory to send message"); dbus_message_unref (message); /* Then start client 2 */ @@ -198,7 +209,8 @@ test_hello_replies (void) DBUS_MESSAGE_HELLO); handler = dbus_message_handler_new (test_hello_client2_handler, NULL, NULL); dbus_connection_add_filter (connection, handler); - dbus_connection_send_message (connection, message, NULL, NULL); + if (!dbus_connection_send (connection, message, NULL)) + die ("no memory to send message"); dbus_message_unref (message); bus_test_loop_run (); diff --git a/test/data/valid-messages/dict-simple.message b/test/data/valid-messages/dict-simple.message index 0b9d018..0de1a78 100644 --- a/test/data/valid-messages/dict-simple.message +++ b/test/data/valid-messages/dict-simple.message @@ -1,6 +1,9 @@ # A simple dict VALID_HEADER +FIELD_NAME name +TYPE STRING +STRING 'org.freedesktop.Foo' END_LENGTH Header ALIGN 8 START_LENGTH Body diff --git a/test/data/valid-messages/dict.message b/test/data/valid-messages/dict.message index 0532e68..ce99a28 100644 --- a/test/data/valid-messages/dict.message +++ b/test/data/valid-messages/dict.message @@ -1,8 +1,11 @@ # Dict with different values VALID_HEADER -END_LENGTH Header +FIELD_NAME name +TYPE STRING +STRING 'org.freedesktop.Foo' ALIGN 8 +END_LENGTH Header START_LENGTH Body TYPE DICT STRING_ARRAY { 'boolean', 'int32', 'uint32', 'double', 'string', 'boolean_array', 'int32_array', 'uint32_array', 'double_array', 'string_array' } diff --git a/test/data/valid-messages/lots-of-arguments.message b/test/data/valid-messages/lots-of-arguments.message index 6a7d5eb..cc9c5a7 100644 --- a/test/data/valid-messages/lots-of-arguments.message +++ b/test/data/valid-messages/lots-of-arguments.message @@ -1,6 +1,9 @@ # Message with lots of different argument types VALID_HEADER +FIELD_NAME name +TYPE STRING +STRING 'org.freedesktop.Foo' END_LENGTH Header ALIGN 8 START_LENGTH Body diff --git a/test/data/valid-messages/no-padding.message b/test/data/valid-messages/no-padding.message index c21c84d..ab5b5a8 100644 --- a/test/data/valid-messages/no-padding.message +++ b/test/data/valid-messages/no-padding.message @@ -3,6 +3,10 @@ ## VALID_HEADER includes a LENGTH Header and LENGTH Body VALID_HEADER +FIELD_NAME name +TYPE STRING +STRING 'org.freedesktop.Foo' + ## this byte array is filled with zeros to the natural length ## of the header FIELD_NAME unkn diff --git a/test/data/valid-messages/simplest-manual.message b/test/data/valid-messages/simplest-manual.message index 3f002ed..8eed1e5 100644 --- a/test/data/valid-messages/simplest-manual.message +++ b/test/data/valid-messages/simplest-manual.message @@ -10,6 +10,9 @@ LENGTH Header LENGTH Body ## client serial INT32 7 +FIELD_NAME name +TYPE STRING +STRING 'org.freedesktop.Foo' ALIGN 8 END_LENGTH Header START_LENGTH Body diff --git a/test/data/valid-messages/simplest.message b/test/data/valid-messages/simplest.message index a0283aa..7bb1872 100644 --- a/test/data/valid-messages/simplest.message +++ b/test/data/valid-messages/simplest.message @@ -2,6 +2,9 @@ ## VALID_HEADER includes a LENGTH Header and LENGTH Body VALID_HEADER +FIELD_NAME name +TYPE STRING +STRING 'org.freedesktop.Foo' ALIGN 8 END_LENGTH Header START_LENGTH Body diff --git a/test/echo-client.c b/test/echo-client.c index 47d7314..de32957 100644 --- a/test/echo-client.c +++ b/test/echo-client.c @@ -28,10 +28,10 @@ main (int argc, /* Send a message to get things going */ message = dbus_message_new ("org.freedesktop.DBus.Test", "org.freedesktop.DBus.Test"); - dbus_connection_send_message (connection, - message, - NULL, - NULL); + if (!dbus_connection_send (connection, + message, + NULL)) + fprintf (stderr, "No memory to send reply\n"); dbus_message_unref (message); do_mainloop (); diff --git a/test/unbase64.c b/test/unbase64.c index cc12365..f3894bd 100644 --- a/test/unbase64.c +++ b/test/unbase64.c @@ -14,6 +14,7 @@ main (int argc, DBusString decoded; DBusString filename; const char *s; + DBusError error; if (argc < 2) { @@ -29,8 +30,13 @@ main (int argc, if (!_dbus_string_init (&decoded, _DBUS_INT_MAX)) return 1; - if (_dbus_file_get_contents (&contents, &filename) != DBUS_RESULT_SUCCESS) - return 1; + dbus_error_init (&error); + if (!_dbus_file_get_contents (&contents, &filename, &error)) + { + fprintf (stderr, "Failed to load file: %s\n", error.message); + dbus_error_free (&error); + return 1; + } if (!_dbus_string_base64_decode (&contents, 0, &decoded, 0)) diff --git a/test/watch.c b/test/watch.c index 1a31e64..d8e91b7 100644 --- a/test/watch.c +++ b/test/watch.c @@ -168,10 +168,10 @@ check_messages (void) fprintf (stderr, "Received message %d, sending reply\n", count); reply = dbus_message_new ("org.freedesktop.DBus.Test", "org.freedesktop.DBus.Test"); - dbus_connection_send_message (connection, - reply, - NULL, - NULL); + if (!dbus_connection_send (connection, + reply, + NULL)) + fprintf (stderr, "No memory to send reply\n"); dbus_message_unref (reply); dbus_message_unref (message); -- 2.7.4