| /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ |
| /* dispatch.c Message dispatcher |
| * |
| * Copyright (C) 2003 CodeFactory AB |
| * Copyright (C) 2003, 2004, 2005 Red Hat, Inc. |
| * Copyright (C) 2004 Imendio HB |
| * |
| * Licensed under the Academic Free License version 2.1 |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
| * |
| */ |
| |
| #include <config.h> |
| #include "dispatch.h" |
| #include "connection.h" |
| #include "driver.h" |
| #include "services.h" |
| #include "activation.h" |
| #include "utils.h" |
| #include "bus.h" |
| #include "signals.h" |
| #include "test.h" |
| #include <dbus/dbus-internals.h> |
| #include <string.h> |
| |
| #ifdef HAVE_UNIX_FD_PASSING |
| #include <dbus/dbus-sysdeps-unix.h> |
| #include <unistd.h> |
| #endif |
| |
| #ifndef TEST_CONNECTION |
| /* |
| TODO autotools: |
| move to build system as already done for cmake |
| */ |
| #ifdef DBUS_UNIX |
| #define TEST_CONNECTION "debug-pipe:name=test-server" |
| #else |
| #define TEST_CONNECTION "tcp:host=localhost,port=1234" |
| #endif |
| #endif |
| |
| static dbus_bool_t |
| send_one_message (DBusConnection *connection, |
| BusContext *context, |
| DBusConnection *sender, |
| DBusConnection *addressed_recipient, |
| DBusMessage *message, |
| BusTransaction *transaction, |
| DBusError *error) |
| { |
| if (!bus_context_check_security_policy (context, transaction, |
| sender, |
| addressed_recipient, |
| connection, |
| message, |
| NULL)) |
| return TRUE; /* silently don't send it */ |
| |
| if (dbus_message_contains_unix_fds(message) && |
| !dbus_connection_can_send_type(connection, DBUS_TYPE_UNIX_FD)) |
| return TRUE; /* silently don't send it */ |
| |
| if (!bus_transaction_send (transaction, |
| connection, |
| message)) |
| { |
| BUS_SET_OOM (error); |
| return FALSE; |
| } |
| |
| return TRUE; |
| } |
| |
| dbus_bool_t |
| bus_dispatch_matches (BusTransaction *transaction, |
| DBusConnection *sender, |
| DBusConnection *addressed_recipient, |
| DBusMessage *message, |
| DBusError *error) |
| { |
| DBusError tmp_error; |
| BusConnections *connections; |
| DBusList *recipients; |
| BusMatchmaker *matchmaker; |
| DBusList *link; |
| BusContext *context; |
| |
| _DBUS_ASSERT_ERROR_IS_CLEAR (error); |
| |
| /* sender and recipient can both be NULL for the bus driver, |
| * or for signals with no particular recipient |
| */ |
| |
| _dbus_assert (sender == NULL || bus_connection_is_active (sender)); |
| _dbus_assert (dbus_message_get_sender (message) != NULL); |
| |
| context = bus_transaction_get_context (transaction); |
| |
| /* First, send the message to the addressed_recipient, if there is one. */ |
| if (addressed_recipient != NULL) |
| { |
| if (!bus_context_check_security_policy (context, transaction, |
| sender, addressed_recipient, |
| addressed_recipient, |
| message, error)) |
| return FALSE; |
| |
| if (dbus_message_contains_unix_fds (message) && |
| !dbus_connection_can_send_type (addressed_recipient, |
| DBUS_TYPE_UNIX_FD)) |
| { |
| dbus_set_error (error, |
| DBUS_ERROR_NOT_SUPPORTED, |
| "Tried to send message with Unix file descriptors" |
| "to a client that doesn't support that."); |
| return FALSE; |
| } |
| |
| /* Dispatch the message */ |
| if (!bus_transaction_send (transaction, addressed_recipient, message)) |
| { |
| BUS_SET_OOM (error); |
| return FALSE; |
| } |
| } |
| |
| /* Now dispatch to others who look interested in this message */ |
| connections = bus_transaction_get_connections (transaction); |
| dbus_error_init (&tmp_error); |
| matchmaker = bus_context_get_matchmaker (context); |
| |
| recipients = NULL; |
| if (!bus_matchmaker_get_recipients (matchmaker, connections, |
| sender, addressed_recipient, message, |
| &recipients)) |
| { |
| BUS_SET_OOM (error); |
| return FALSE; |
| } |
| |
| link = _dbus_list_get_first_link (&recipients); |
| while (link != NULL) |
| { |
| DBusConnection *dest; |
| |
| dest = link->data; |
| |
| if (!send_one_message (dest, context, sender, addressed_recipient, |
| message, transaction, &tmp_error)) |
| break; |
| |
| link = _dbus_list_get_next_link (&recipients, link); |
| } |
| |
| _dbus_list_clear (&recipients); |
| |
| if (dbus_error_is_set (&tmp_error)) |
| { |
| dbus_move_error (&tmp_error, error); |
| return FALSE; |
| } |
| else |
| return TRUE; |
| } |
| |
| static DBusHandlerResult |
| bus_dispatch (DBusConnection *connection, |
| DBusMessage *message) |
| { |
| const char *sender, *service_name; |
| DBusError error; |
| BusTransaction *transaction; |
| BusContext *context; |
| DBusHandlerResult result; |
| DBusConnection *addressed_recipient; |
| |
| result = DBUS_HANDLER_RESULT_HANDLED; |
| |
| transaction = NULL; |
| addressed_recipient = NULL; |
| dbus_error_init (&error); |
| |
| context = bus_connection_get_context (connection); |
| _dbus_assert (context != NULL); |
| |
| /* If we can't even allocate an OOM error, we just go to sleep |
| * until we can. |
| */ |
| while (!bus_connection_preallocate_oom_error (connection)) |
| _dbus_wait_for_memory (); |
| |
| /* Ref connection in case we disconnect it at some point in here */ |
| dbus_connection_ref (connection); |
| |
| service_name = dbus_message_get_destination (message); |
| |
| #ifdef DBUS_ENABLE_VERBOSE_MODE |
| { |
| const char *interface_name, *member_name, *error_name; |
| |
| interface_name = dbus_message_get_interface (message); |
| member_name = dbus_message_get_member (message); |
| error_name = dbus_message_get_error_name (message); |
| |
| _dbus_verbose ("DISPATCH: %s %s %s to %s\n", |
| interface_name ? interface_name : "(no interface)", |
| member_name ? member_name : "(no member)", |
| error_name ? error_name : "(no error name)", |
| service_name ? service_name : "peer"); |
| } |
| #endif /* DBUS_ENABLE_VERBOSE_MODE */ |
| |
| /* If service_name is NULL, if it's a signal we send it to all |
| * connections with a match rule. If it's not a signal, there |
| * are some special cases here but mostly we just bail out. |
| */ |
| if (service_name == NULL) |
| { |
| if (dbus_message_is_signal (message, |
| DBUS_INTERFACE_LOCAL, |
| "Disconnected")) |
| { |
| bus_connection_disconnected (connection); |
| goto out; |
| } |
| |
| if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_SIGNAL) |
| { |
| /* DBusConnection also handles some of these automatically, we leave |
| * it to do so. |
| */ |
| result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; |
| goto out; |
| } |
| } |
| |
| /* Create our transaction */ |
| transaction = bus_transaction_new (context); |
| if (transaction == NULL) |
| { |
| BUS_SET_OOM (&error); |
| goto out; |
| } |
| |
| /* Assign a sender to the message */ |
| if (bus_connection_is_active (connection)) |
| { |
| sender = bus_connection_get_name (connection); |
| _dbus_assert (sender != NULL); |
| |
| if (!dbus_message_set_sender (message, sender)) |
| { |
| BUS_SET_OOM (&error); |
| goto out; |
| } |
| |
| /* We need to refetch the service name here, because |
| * dbus_message_set_sender can cause the header to be |
| * reallocated, and thus the service_name pointer will become |
| * invalid. |
| */ |
| service_name = dbus_message_get_destination (message); |
| } |
| |
| if (service_name && |
| strcmp (service_name, DBUS_SERVICE_DBUS) == 0) /* to bus driver */ |
| { |
| if (!bus_context_check_security_policy (context, transaction, |
| connection, NULL, NULL, message, &error)) |
| { |
| _dbus_verbose ("Security policy rejected message\n"); |
| goto out; |
| } |
| |
| _dbus_verbose ("Giving message to %s\n", DBUS_SERVICE_DBUS); |
| if (!bus_driver_handle_message (connection, transaction, message, &error)) |
| goto out; |
| } |
| 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_close (connection); |
| goto out; |
| } |
| else if (service_name != NULL) /* route to named service */ |
| { |
| DBusString service_string; |
| BusService *service; |
| BusRegistry *registry; |
| |
| _dbus_assert (service_name != NULL); |
| |
| registry = bus_connection_get_registry (connection); |
| |
| _dbus_string_init_const (&service_string, service_name); |
| service = bus_registry_lookup (registry, &service_string); |
| |
| if (service == NULL && dbus_message_get_auto_start (message)) |
| { |
| BusActivation *activation; |
| /* We can't do the security policy check here, since the addressed |
| * recipient service doesn't exist yet. We do it before sending the |
| * message after the service has been created. |
| */ |
| activation = bus_connection_get_activation (connection); |
| |
| if (!bus_activation_activate_service (activation, connection, transaction, TRUE, |
| message, service_name, &error)) |
| { |
| _DBUS_ASSERT_ERROR_IS_SET (&error); |
| _dbus_verbose ("bus_activation_activate_service() failed: %s\n", error.name); |
| goto out; |
| } |
| |
| goto out; |
| } |
| else if (service == NULL) |
| { |
| dbus_set_error (&error, |
| DBUS_ERROR_NAME_HAS_NO_OWNER, |
| "Name \"%s\" does not exist", |
| service_name); |
| goto out; |
| } |
| else |
| { |
| addressed_recipient = bus_service_get_primary_owners_connection (service); |
| _dbus_assert (addressed_recipient != NULL); |
| } |
| } |
| |
| /* Now send the message to its destination (or not, if |
| * addressed_recipient == NULL), and match it against other connections' |
| * match rules. |
| */ |
| if (!bus_dispatch_matches (transaction, connection, addressed_recipient, message, &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. |
| */ |
| _dbus_verbose ("Not sending error to connection we disconnected\n"); |
| } |
| else if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY)) |
| { |
| bus_connection_send_oom_error (connection, message); |
| |
| /* cancel transaction due to OOM */ |
| if (transaction != NULL) |
| { |
| bus_transaction_cancel_and_free (transaction); |
| transaction = NULL; |
| } |
| } |
| else |
| { |
| /* 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; |
| } |
| } |
| } |
| |
| |
| dbus_error_free (&error); |
| } |
| |
| if (transaction != NULL) |
| { |
| bus_transaction_execute_and_free (transaction); |
| } |
| |
| dbus_connection_unref (connection); |
| |
| return result; |
| } |
| |
| static DBusHandlerResult |
| bus_dispatch_message_filter (DBusConnection *connection, |
| DBusMessage *message, |
| void *user_data) |
| { |
| return bus_dispatch (connection, message); |
| } |
| |
| dbus_bool_t |
| bus_dispatch_add_connection (DBusConnection *connection) |
| { |
| if (!dbus_connection_add_filter (connection, |
| bus_dispatch_message_filter, |
| NULL, NULL)) |
| return FALSE; |
| |
| return TRUE; |
| } |
| |
| void |
| bus_dispatch_remove_connection (DBusConnection *connection) |
| { |
| /* Here we tell the bus driver that we want to get off. */ |
| bus_driver_remove_connection (connection); |
| |
| dbus_connection_remove_filter (connection, |
| bus_dispatch_message_filter, |
| NULL); |
| } |
| |
| #ifdef DBUS_BUILD_TESTS |
| |
| #include <stdio.h> |
| |
| /* This is used to know whether we need to block in order to finish |
| * sending a message, or whether the initial dbus_connection_send() |
| * already flushed the queue. |
| */ |
| #define SEND_PENDING(connection) (dbus_connection_has_messages_to_send (connection)) |
| |
| typedef dbus_bool_t (* Check1Func) (BusContext *context); |
| typedef dbus_bool_t (* Check2Func) (BusContext *context, |
| DBusConnection *connection); |
| |
| static dbus_bool_t check_no_leftovers (BusContext *context); |
| |
| static void |
| block_connection_until_message_from_bus (BusContext *context, |
| DBusConnection *connection, |
| const char *what_is_expected) |
| { |
| _dbus_verbose ("expecting: %s\n", what_is_expected); |
| |
| while (dbus_connection_get_dispatch_status (connection) == |
| DBUS_DISPATCH_COMPLETE && |
| dbus_connection_get_is_connected (connection)) |
| { |
| bus_test_run_bus_loop (context, TRUE); |
| bus_test_run_clients_loop (FALSE); |
| } |
| } |
| |
| static void |
| spin_connection_until_authenticated (BusContext *context, |
| DBusConnection *connection) |
| { |
| _dbus_verbose ("Spinning to auth connection %p\n", connection); |
| while (!dbus_connection_get_is_authenticated (connection) && |
| dbus_connection_get_is_connected (connection)) |
| { |
| bus_test_run_bus_loop (context, FALSE); |
| bus_test_run_clients_loop (FALSE); |
| } |
| _dbus_verbose (" ... done spinning to auth connection %p\n", connection); |
| } |
| |
| /* compensate for fact that pop_message() can return #NULL due to OOM */ |
| static DBusMessage* |
| pop_message_waiting_for_memory (DBusConnection *connection) |
| { |
| while (dbus_connection_get_dispatch_status (connection) == |
| DBUS_DISPATCH_NEED_MEMORY) |
| _dbus_wait_for_memory (); |
| |
| return dbus_connection_pop_message (connection); |
| } |
| |
| static DBusMessage* |
| borrow_message_waiting_for_memory (DBusConnection *connection) |
| { |
| while (dbus_connection_get_dispatch_status (connection) == |
| DBUS_DISPATCH_NEED_MEMORY) |
| _dbus_wait_for_memory (); |
| |
| return dbus_connection_borrow_message (connection); |
| } |
| |
| static void |
| warn_unexpected_real (DBusConnection *connection, |
| DBusMessage *message, |
| const char *expected, |
| const char *function, |
| int line) |
| { |
| if (message) |
| _dbus_warn ("%s:%d received message interface \"%s\" member \"%s\" error name \"%s\" on %p, expecting %s\n", |
| function, line, |
| dbus_message_get_interface (message) ? |
| dbus_message_get_interface (message) : "(unset)", |
| dbus_message_get_member (message) ? |
| dbus_message_get_member (message) : "(unset)", |
| dbus_message_get_error_name (message) ? |
| dbus_message_get_error_name (message) : "(unset)", |
| connection, |
| expected); |
| else |
| _dbus_warn ("%s:%d received no message on %p, expecting %s\n", |
| function, line, connection, expected); |
| } |
| |
| #define warn_unexpected(connection, message, expected) \ |
| warn_unexpected_real (connection, message, expected, _DBUS_FUNCTION_NAME, __LINE__) |
| |
| static void |
| verbose_message_received (DBusConnection *connection, |
| DBusMessage *message) |
| { |
| _dbus_verbose ("Received message interface \"%s\" member \"%s\" error name \"%s\" on %p\n", |
| dbus_message_get_interface (message) ? |
| dbus_message_get_interface (message) : "(unset)", |
| dbus_message_get_member (message) ? |
| dbus_message_get_member (message) : "(unset)", |
| dbus_message_get_error_name (message) ? |
| dbus_message_get_error_name (message) : "(unset)", |
| connection); |
| } |
| |
| typedef enum |
| { |
| SERVICE_CREATED, |
| OWNER_CHANGED, |
| SERVICE_DELETED |
| } ServiceInfoKind; |
| |
| typedef struct |
| { |
| ServiceInfoKind expected_kind; |
| const char *expected_service_name; |
| dbus_bool_t failed; |
| DBusConnection *skip_connection; |
| } CheckServiceOwnerChangedData; |
| |
| static dbus_bool_t |
| check_service_owner_changed_foreach (DBusConnection *connection, |
| void *data) |
| { |
| CheckServiceOwnerChangedData *d = data; |
| DBusMessage *message; |
| DBusError error; |
| const char *service_name, *old_owner, *new_owner; |
| |
| if (d->expected_kind == SERVICE_CREATED |
| && connection == d->skip_connection) |
| return TRUE; |
| |
| dbus_error_init (&error); |
| d->failed = TRUE; |
| |
| message = pop_message_waiting_for_memory (connection); |
| if (message == NULL) |
| { |
| _dbus_warn ("Did not receive a message on %p, expecting %s\n", |
| connection, "NameOwnerChanged"); |
| goto out; |
| } |
| else if (!dbus_message_is_signal (message, |
| DBUS_INTERFACE_DBUS, |
| "NameOwnerChanged")) |
| { |
| warn_unexpected (connection, message, "NameOwnerChanged"); |
| |
| goto out; |
| } |
| else |
| { |
| reget_service_info_data: |
| service_name = NULL; |
| old_owner = NULL; |
| new_owner = NULL; |
| |
| dbus_message_get_args (message, &error, |
| DBUS_TYPE_STRING, &service_name, |
| DBUS_TYPE_STRING, &old_owner, |
| DBUS_TYPE_STRING, &new_owner, |
| DBUS_TYPE_INVALID); |
| |
| if (dbus_error_is_set (&error)) |
| { |
| if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY)) |
| { |
| dbus_error_free (&error); |
| _dbus_wait_for_memory (); |
| goto reget_service_info_data; |
| } |
| else |
| { |
| _dbus_warn ("Did not get the expected arguments\n"); |
| goto out; |
| } |
| } |
| |
| if ((d->expected_kind == SERVICE_CREATED && ( old_owner[0] || !new_owner[0])) |
| || (d->expected_kind == OWNER_CHANGED && (!old_owner[0] || !new_owner[0])) |
| || (d->expected_kind == SERVICE_DELETED && (!old_owner[0] || new_owner[0]))) |
| { |
| _dbus_warn ("inconsistent NameOwnerChanged arguments\n"); |
| goto out; |
| } |
| |
| if (strcmp (service_name, d->expected_service_name) != 0) |
| { |
| _dbus_warn ("expected info on service %s, got info on %s\n", |
| d->expected_service_name, |
| service_name); |
| goto out; |
| } |
| |
| if (*service_name == ':' && new_owner[0] |
| && strcmp (service_name, new_owner) != 0) |
| { |
| _dbus_warn ("inconsistent ServiceOwnedChanged message (\"%s\" [ %s -> %s ])\n", |
| service_name, old_owner, new_owner); |
| goto out; |
| } |
| } |
| |
| d->failed = FALSE; |
| |
| out: |
| dbus_error_free (&error); |
| |
| if (message) |
| dbus_message_unref (message); |
| |
| return !d->failed; |
| } |
| |
| |
| static void |
| kill_client_connection (BusContext *context, |
| DBusConnection *connection) |
| { |
| char *base_service; |
| const char *s; |
| CheckServiceOwnerChangedData socd; |
| |
| _dbus_verbose ("killing connection %p\n", connection); |
| |
| s = dbus_bus_get_unique_name (connection); |
| _dbus_assert (s != NULL); |
| |
| while ((base_service = _dbus_strdup (s)) == NULL) |
| _dbus_wait_for_memory (); |
| |
| dbus_connection_ref (connection); |
| |
| /* kick in the disconnect handler that unrefs the connection */ |
| dbus_connection_close (connection); |
| |
| bus_test_run_everything (context); |
| |
| _dbus_assert (bus_test_client_listed (connection)); |
| |
| /* Run disconnect handler in test.c */ |
| if (bus_connection_dispatch_one_message (connection)) |
| _dbus_assert_not_reached ("something received on connection being killed other than the disconnect"); |
| |
| _dbus_assert (!dbus_connection_get_is_connected (connection)); |
| dbus_connection_unref (connection); |
| connection = NULL; |
| _dbus_assert (!bus_test_client_listed (connection)); |
| |
| socd.expected_kind = SERVICE_DELETED; |
| socd.expected_service_name = base_service; |
| socd.failed = FALSE; |
| socd.skip_connection = NULL; |
| |
| bus_test_clients_foreach (check_service_owner_changed_foreach, |
| &socd); |
| |
| dbus_free (base_service); |
| |
| if (socd.failed) |
| _dbus_assert_not_reached ("didn't get the expected NameOwnerChanged (deletion) messages"); |
| |
| if (!check_no_leftovers (context)) |
| _dbus_assert_not_reached ("stuff left in message queues after disconnecting a client"); |
| } |
| |
| static void |
| kill_client_connection_unchecked (DBusConnection *connection) |
| { |
| /* This kills the connection without expecting it to affect |
| * the rest of the bus. |
| */ |
| _dbus_verbose ("Unchecked kill of connection %p\n", connection); |
| |
| dbus_connection_ref (connection); |
| dbus_connection_close (connection); |
| /* dispatching disconnect handler will unref once */ |
| if (bus_connection_dispatch_one_message (connection)) |
| _dbus_assert_not_reached ("message other than disconnect dispatched after failure to register"); |
| |
| _dbus_assert (!bus_test_client_listed (connection)); |
| dbus_connection_unref (connection); |
| } |
| |
| typedef struct |
| { |
| dbus_bool_t failed; |
| } CheckNoMessagesData; |
| |
| static dbus_bool_t |
| check_no_messages_foreach (DBusConnection *connection, |
| void *data) |
| { |
| CheckNoMessagesData *d = data; |
| DBusMessage *message; |
| |
| message = pop_message_waiting_for_memory (connection); |
| if (message != NULL) |
| { |
| warn_unexpected (connection, message, "no messages"); |
| |
| d->failed = TRUE; |
| } |
| |
| if (message) |
| dbus_message_unref (message); |
| return !d->failed; |
| } |
| |
| static dbus_bool_t |
| check_no_leftovers (BusContext *context) |
| { |
| CheckNoMessagesData nmd; |
| |
| nmd.failed = FALSE; |
| bus_test_clients_foreach (check_no_messages_foreach, |
| &nmd); |
| |
| if (nmd.failed) |
| { |
| _dbus_verbose ("leftover message found\n"); |
| return FALSE; |
| } |
| else |
| return TRUE; |
| } |
| |
| /* returns TRUE if the correct thing happens, |
| * but the correct thing may include OOM errors. |
| */ |
| static dbus_bool_t |
| check_hello_message (BusContext *context, |
| DBusConnection *connection) |
| { |
| DBusMessage *message; |
| DBusMessage *name_message; |
| dbus_uint32_t serial; |
| dbus_bool_t retval; |
| DBusError error; |
| const char *name; |
| const char *acquired; |
| |
| retval = FALSE; |
| dbus_error_init (&error); |
| name = NULL; |
| acquired = NULL; |
| message = NULL; |
| name_message = NULL; |
| |
| _dbus_verbose ("check_hello_message for %p\n", connection); |
| |
| message = dbus_message_new_method_call (DBUS_SERVICE_DBUS, |
| DBUS_PATH_DBUS, |
| DBUS_INTERFACE_DBUS, |
| "Hello"); |
| |
| if (message == NULL) |
| return TRUE; |
| |
| dbus_connection_ref (connection); /* because we may get disconnected */ |
| |
| if (!dbus_connection_send (connection, message, &serial)) |
| { |
| dbus_message_unref (message); |
| dbus_connection_unref (connection); |
| return TRUE; |
| } |
| |
| _dbus_assert (dbus_message_has_signature (message, "")); |
| |
| dbus_message_unref (message); |
| message = NULL; |
| |
| if (!dbus_connection_get_is_connected (connection)) |
| { |
| _dbus_verbose ("connection was disconnected (presumably auth failed)\n"); |
| |
| dbus_connection_unref (connection); |
| |
| return TRUE; |
| } |
| |
| /* send our message */ |
| bus_test_run_clients_loop (SEND_PENDING (connection)); |
| |
| if (!dbus_connection_get_is_connected (connection)) |
| { |
| _dbus_verbose ("connection was disconnected (presumably auth failed)\n"); |
| |
| dbus_connection_unref (connection); |
| |
| return TRUE; |
| } |
| |
| block_connection_until_message_from_bus (context, connection, "reply to Hello"); |
| |
| if (!dbus_connection_get_is_connected (connection)) |
| { |
| _dbus_verbose ("connection was disconnected (presumably auth failed)\n"); |
| |
| dbus_connection_unref (connection); |
| |
| return TRUE; |
| } |
| |
| dbus_connection_unref (connection); |
| |
| message = pop_message_waiting_for_memory (connection); |
| if (message == NULL) |
| { |
| _dbus_warn ("Did not receive a reply to %s %d on %p\n", |
| "Hello", serial, connection); |
| goto out; |
| } |
| |
| verbose_message_received (connection, message); |
| |
| if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS)) |
| { |
| _dbus_warn ("Message has wrong sender %s\n", |
| dbus_message_get_sender (message) ? |
| dbus_message_get_sender (message) : "(none)"); |
| goto out; |
| } |
| |
| if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR) |
| { |
| if (dbus_message_is_error (message, |
| DBUS_ERROR_NO_MEMORY)) |
| { |
| ; /* good, this is a valid response */ |
| } |
| else |
| { |
| warn_unexpected (connection, message, "not this error"); |
| |
| goto out; |
| } |
| } |
| else |
| { |
| CheckServiceOwnerChangedData socd; |
| |
| if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_METHOD_RETURN) |
| { |
| ; /* good, expected */ |
| } |
| else |
| { |
| warn_unexpected (connection, message, "method return for Hello"); |
| |
| goto out; |
| } |
| |
| retry_get_hello_name: |
| if (!dbus_message_get_args (message, &error, |
| DBUS_TYPE_STRING, &name, |
| DBUS_TYPE_INVALID)) |
| { |
| if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY)) |
| { |
| _dbus_verbose ("no memory to get service name arg from hello\n"); |
| dbus_error_free (&error); |
| _dbus_wait_for_memory (); |
| goto retry_get_hello_name; |
| } |
| else |
| { |
| _dbus_assert (dbus_error_is_set (&error)); |
| _dbus_warn ("Did not get the expected single string argument to hello\n"); |
| goto out; |
| } |
| } |
| |
| _dbus_verbose ("Got hello name: %s\n", name); |
| |
| while (!dbus_bus_set_unique_name (connection, name)) |
| _dbus_wait_for_memory (); |
| |
| socd.expected_kind = SERVICE_CREATED; |
| socd.expected_service_name = name; |
| socd.failed = FALSE; |
| socd.skip_connection = connection; /* we haven't done AddMatch so won't get it ourselves */ |
| bus_test_clients_foreach (check_service_owner_changed_foreach, |
| &socd); |
| |
| if (socd.failed) |
| goto out; |
| |
| name_message = message; |
| /* Client should also have gotten ServiceAcquired */ |
| |
| message = pop_message_waiting_for_memory (connection); |
| if (message == NULL) |
| { |
| _dbus_warn ("Expecting %s, got nothing\n", |
| "NameAcquired"); |
| goto out; |
| } |
| if (! dbus_message_is_signal (message, DBUS_INTERFACE_DBUS, |
| "NameAcquired")) |
| { |
| _dbus_warn ("Expecting %s, got smthg else\n", |
| "NameAcquired"); |
| goto out; |
| } |
| |
| retry_get_acquired_name: |
| if (!dbus_message_get_args (message, &error, |
| DBUS_TYPE_STRING, &acquired, |
| DBUS_TYPE_INVALID)) |
| { |
| if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY)) |
| { |
| _dbus_verbose ("no memory to get service name arg from acquired\n"); |
| dbus_error_free (&error); |
| _dbus_wait_for_memory (); |
| goto retry_get_acquired_name; |
| } |
| else |
| { |
| _dbus_assert (dbus_error_is_set (&error)); |
| _dbus_warn ("Did not get the expected single string argument to ServiceAcquired\n"); |
| goto out; |
| } |
| } |
| |
| _dbus_verbose ("Got acquired name: %s\n", acquired); |
| |
| if (strcmp (acquired, name) != 0) |
| { |
| _dbus_warn ("Acquired name is %s but expected %s\n", |
| acquired, name); |
| goto out; |
| } |
| acquired = NULL; |
| } |
| |
| if (!check_no_leftovers (context)) |
| goto out; |
| |
| retval = TRUE; |
| |
| out: |
| _dbus_verbose ("ending - retval = %d\n", retval); |
| |
| dbus_error_free (&error); |
| |
| if (message) |
| dbus_message_unref (message); |
| |
| if (name_message) |
| dbus_message_unref (name_message); |
| |
| return retval; |
| } |
| |
| /* returns TRUE if the correct thing happens, |
| * but the correct thing may include OOM errors. |
| */ |
| static dbus_bool_t |
| check_double_hello_message (BusContext *context, |
| DBusConnection *connection) |
| { |
| DBusMessage *message; |
| dbus_uint32_t serial; |
| dbus_bool_t retval; |
| DBusError error; |
| |
| retval = FALSE; |
| dbus_error_init (&error); |
| message = NULL; |
| |
| _dbus_verbose ("check_double_hello_message for %p\n", connection); |
| |
| message = dbus_message_new_method_call (DBUS_SERVICE_DBUS, |
| DBUS_PATH_DBUS, |
| DBUS_INTERFACE_DBUS, |
| "Hello"); |
| |
| if (message == NULL) |
| return TRUE; |
| |
| if (!dbus_connection_send (connection, message, &serial)) |
| { |
| dbus_message_unref (message); |
| return TRUE; |
| } |
| |
| dbus_message_unref (message); |
| message = NULL; |
| |
| /* send our message */ |
| bus_test_run_clients_loop (SEND_PENDING (connection)); |
| |
| dbus_connection_ref (connection); /* because we may get disconnected */ |
| block_connection_until_message_from_bus (context, connection, "reply to Hello"); |
| |
| if (!dbus_connection_get_is_connected (connection)) |
| { |
| _dbus_verbose ("connection was disconnected\n"); |
| |
| dbus_connection_unref (connection); |
| |
| return TRUE; |
| } |
| |
| dbus_connection_unref (connection); |
| |
| message = pop_message_waiting_for_memory (connection); |
| if (message == NULL) |
| { |
| _dbus_warn ("Did not receive a reply to %s %d on %p\n", |
| "Hello", serial, connection); |
| goto out; |
| } |
| |
| verbose_message_received (connection, message); |
| |
| if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS)) |
| { |
| _dbus_warn ("Message has wrong sender %s\n", |
| dbus_message_get_sender (message) ? |
| dbus_message_get_sender (message) : "(none)"); |
| goto out; |
| } |
| |
| if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_ERROR) |
| { |
| warn_unexpected (connection, message, "method return for Hello"); |
| goto out; |
| } |
| |
| if (!check_no_leftovers (context)) |
| goto out; |
| |
| retval = TRUE; |
| |
| out: |
| dbus_error_free (&error); |
| |
| if (message) |
| dbus_message_unref (message); |
| |
| return retval; |
| } |
| |
| /* returns TRUE if the correct thing happens, |
| * but the correct thing may include OOM errors. |
| */ |
| static dbus_bool_t |
| check_get_connection_unix_user (BusContext *context, |
| DBusConnection *connection) |
| { |
| DBusMessage *message; |
| dbus_uint32_t serial; |
| dbus_bool_t retval; |
| DBusError error; |
| const char *base_service_name; |
| dbus_uint32_t uid; |
| |
| retval = FALSE; |
| dbus_error_init (&error); |
| message = NULL; |
| |
| _dbus_verbose ("check_get_connection_unix_user for %p\n", connection); |
| |
| message = dbus_message_new_method_call (DBUS_SERVICE_DBUS, |
| DBUS_PATH_DBUS, |
| DBUS_INTERFACE_DBUS, |
| "GetConnectionUnixUser"); |
| |
| if (message == NULL) |
| return TRUE; |
| |
| base_service_name = dbus_bus_get_unique_name (connection); |
| |
| if (!dbus_message_append_args (message, |
| DBUS_TYPE_STRING, &base_service_name, |
| DBUS_TYPE_INVALID)) |
| { |
| dbus_message_unref (message); |
| return TRUE; |
| } |
| |
| if (!dbus_connection_send (connection, message, &serial)) |
| { |
| dbus_message_unref (message); |
| return TRUE; |
| } |
| |
| /* send our message */ |
| bus_test_run_clients_loop (SEND_PENDING (connection)); |
| |
| dbus_message_unref (message); |
| message = NULL; |
| |
| dbus_connection_ref (connection); /* because we may get disconnected */ |
| block_connection_until_message_from_bus (context, connection, "reply to GetConnectionUnixUser"); |
| |
| if (!dbus_connection_get_is_connected (connection)) |
| { |
| _dbus_verbose ("connection was disconnected\n"); |
| |
| dbus_connection_unref (connection); |
| |
| return TRUE; |
| } |
| |
| dbus_connection_unref (connection); |
| |
| message = pop_message_waiting_for_memory (connection); |
| if (message == NULL) |
| { |
| _dbus_warn ("Did not receive a reply to %s %d on %p\n", |
| "GetConnectionUnixUser", serial, connection); |
| goto out; |
| } |
| |
| verbose_message_received (connection, message); |
| |
| if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR) |
| { |
| if (dbus_message_is_error (message, DBUS_ERROR_NO_MEMORY)) |
| { |
| ; /* good, this is a valid response */ |
| } |
| else |
| { |
| warn_unexpected (connection, message, "not this error"); |
| |
| goto out; |
| } |
| } |
| else |
| { |
| if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_METHOD_RETURN) |
| { |
| ; /* good, expected */ |
| } |
| else |
| { |
| warn_unexpected (connection, message, |
| "method_return for GetConnectionUnixUser"); |
| |
| goto out; |
| } |
| |
| retry_get_property: |
| |
| if (!dbus_message_get_args (message, &error, |
| DBUS_TYPE_UINT32, &uid, |
| DBUS_TYPE_INVALID)) |
| { |
| if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY)) |
| { |
| _dbus_verbose ("no memory to get uid by GetConnectionUnixUser\n"); |
| dbus_error_free (&error); |
| _dbus_wait_for_memory (); |
| goto retry_get_property; |
| } |
| else |
| { |
| _dbus_assert (dbus_error_is_set (&error)); |
| _dbus_warn ("Did not get the expected DBUS_TYPE_UINT32 from GetConnectionUnixUser\n"); |
| goto out; |
| } |
| } |
| } |
| |
| if (!check_no_leftovers (context)) |
| goto out; |
| |
| retval = TRUE; |
| |
| out: |
| dbus_error_free (&error); |
| |
| if (message) |
| dbus_message_unref (message); |
| |
| return retval; |
| } |
| |
| /* returns TRUE if the correct thing happens, |
| * but the correct thing may include OOM errors. |
| */ |
| static dbus_bool_t |
| check_get_connection_unix_process_id (BusContext *context, |
| DBusConnection *connection) |
| { |
| DBusMessage *message; |
| dbus_uint32_t serial; |
| dbus_bool_t retval; |
| DBusError error; |
| const char *base_service_name; |
| dbus_uint32_t pid; |
| |
| retval = FALSE; |
| dbus_error_init (&error); |
| message = NULL; |
| |
| _dbus_verbose ("check_get_connection_unix_process_id for %p\n", connection); |
| |
| message = dbus_message_new_method_call (DBUS_SERVICE_DBUS, |
| DBUS_PATH_DBUS, |
| DBUS_INTERFACE_DBUS, |
| "GetConnectionUnixProcessID"); |
| |
| if (message == NULL) |
| return TRUE; |
| |
| base_service_name = dbus_bus_get_unique_name (connection); |
| |
| if (!dbus_message_append_args (message, |
| DBUS_TYPE_STRING, &base_service_name, |
| DBUS_TYPE_INVALID)) |
| { |
| dbus_message_unref (message); |
| return TRUE; |
| } |
| |
| if (!dbus_connection_send (connection, message, &serial)) |
| { |
| dbus_message_unref (message); |
| return TRUE; |
| } |
| |
| /* send our message */ |
| bus_test_run_clients_loop (SEND_PENDING (connection)); |
| |
| dbus_message_unref (message); |
| message = NULL; |
| |
| dbus_connection_ref (connection); /* because we may get disconnected */ |
| block_connection_until_message_from_bus (context, connection, "reply to GetConnectionUnixProcessID"); |
| |
| if (!dbus_connection_get_is_connected (connection)) |
| { |
| _dbus_verbose ("connection was disconnected\n"); |
| |
| dbus_connection_unref (connection); |
| |
| return TRUE; |
| } |
| |
| dbus_connection_unref (connection); |
| |
| message = pop_message_waiting_for_memory (connection); |
| if (message == NULL) |
| { |
| _dbus_warn ("Did not receive a reply to %s %d on %p\n", |
| "GetConnectionUnixProcessID", serial, connection); |
| goto out; |
| } |
| |
| verbose_message_received (connection, message); |
| |
| if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR) |
| { |
| if (dbus_message_is_error (message, DBUS_ERROR_NO_MEMORY)) |
| { |
| ; /* good, this is a valid response */ |
| } |
| #ifdef DBUS_WIN |
| else if (dbus_message_is_error (message, DBUS_ERROR_UNIX_PROCESS_ID_UNKNOWN)) |
| { |
| /* We are expecting this error, since we know in the test suite we aren't |
| * talking to a client running on UNIX |
| */ |
| _dbus_verbose ("Windows correctly does not support GetConnectionUnixProcessID\n"); |
| } |
| #endif |
| else |
| { |
| warn_unexpected (connection, message, "not this error"); |
| |
| goto out; |
| } |
| } |
| else |
| { |
| #ifdef DBUS_WIN |
| warn_unexpected (connection, message, "GetConnectionUnixProcessID to fail on Windows"); |
| goto out; |
| #else |
| if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_METHOD_RETURN) |
| { |
| ; /* good, expected */ |
| } |
| else |
| { |
| warn_unexpected (connection, message, |
| "method_return for GetConnectionUnixProcessID"); |
| |
| goto out; |
| } |
| |
| retry_get_property: |
| |
| if (!dbus_message_get_args (message, &error, |
| DBUS_TYPE_UINT32, &pid, |
| DBUS_TYPE_INVALID)) |
| { |
| if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY)) |
| { |
| _dbus_verbose ("no memory to get pid by GetConnectionUnixProcessID\n"); |
| dbus_error_free (&error); |
| _dbus_wait_for_memory (); |
| goto retry_get_property; |
| } |
| else |
| { |
| _dbus_assert (dbus_error_is_set (&error)); |
| _dbus_warn ("Did not get the expected DBUS_TYPE_UINT32 from GetConnectionUnixProcessID\n"); |
| goto out; |
| } |
| } |
| else |
| { |
| /* test if returned pid is the same as our own pid |
| * |
| * @todo It would probably be good to restructure the tests |
| * in a way so our parent is the bus that we're testing |
| * cause then we can test that the pid returned matches |
| * getppid() |
| */ |
| if (pid != (dbus_uint32_t) _dbus_getpid ()) |
| { |
| _dbus_assert (dbus_error_is_set (&error)); |
| _dbus_warn ("Result from GetConnectionUnixProcessID is not our own pid\n"); |
| goto out; |
| } |
| } |
| #endif /* !DBUS_WIN */ |
| } |
| |
| if (!check_no_leftovers (context)) |
| goto out; |
| |
| retval = TRUE; |
| |
| out: |
| dbus_error_free (&error); |
| |
| if (message) |
| dbus_message_unref (message); |
| |
| return retval; |
| } |
| |
| /* returns TRUE if the correct thing happens, |
| * but the correct thing may include OOM errors. |
| */ |
| static dbus_bool_t |
| check_add_match_all (BusContext *context, |
| DBusConnection *connection) |
| { |
| DBusMessage *message; |
| dbus_bool_t retval; |
| dbus_uint32_t serial; |
| DBusError error; |
| const char *empty = ""; |
| |
| retval = FALSE; |
| dbus_error_init (&error); |
| message = NULL; |
| |
| _dbus_verbose ("check_add_match_all for %p\n", connection); |
| |
| message = dbus_message_new_method_call (DBUS_SERVICE_DBUS, |
| DBUS_PATH_DBUS, |
| DBUS_INTERFACE_DBUS, |
| "AddMatch"); |
| |
| if (message == NULL) |
| return TRUE; |
| |
| /* empty string match rule matches everything */ |
| if (!dbus_message_append_args (message, DBUS_TYPE_STRING, &empty, |
| DBUS_TYPE_INVALID)) |
| { |
| dbus_message_unref (message); |
| return TRUE; |
| } |
| |
| if (!dbus_connection_send (connection, message, &serial)) |
| { |
| dbus_message_unref (message); |
| return TRUE; |
| } |
| |
| dbus_message_unref (message); |
| message = NULL; |
| |
| dbus_connection_ref (connection); /* because we may get disconnected */ |
| |
| /* send our message */ |
| bus_test_run_clients_loop (SEND_PENDING (connection)); |
| |
| if (!dbus_connection_get_is_connected (connection)) |
| { |
| _dbus_verbose ("connection was disconnected\n"); |
| |
| dbus_connection_unref (connection); |
| |
| return TRUE; |
| } |
| |
| block_connection_until_message_from_bus (context, connection, "reply to AddMatch"); |
| |
| if (!dbus_connection_get_is_connected (connection)) |
| { |
| _dbus_verbose ("connection was disconnected\n"); |
| |
| dbus_connection_unref (connection); |
| |
| return TRUE; |
| } |
| |
| dbus_connection_unref (connection); |
| |
| message = pop_message_waiting_for_memory (connection); |
| if (message == NULL) |
| { |
| _dbus_warn ("Did not receive a reply to %s %d on %p\n", |
| "AddMatch", serial, connection); |
| goto out; |
| } |
| |
| verbose_message_received (connection, message); |
| |
| if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS)) |
| { |
| _dbus_warn ("Message has wrong sender %s\n", |
| dbus_message_get_sender (message) ? |
| dbus_message_get_sender (message) : "(none)"); |
| goto out; |
| } |
| |
| if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR) |
| { |
| if (dbus_message_is_error (message, |
| DBUS_ERROR_NO_MEMORY)) |
| { |
| ; /* good, this is a valid response */ |
| } |
| else |
| { |
| warn_unexpected (connection, message, "not this error"); |
| |
| goto out; |
| } |
| } |
| else |
| { |
| if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_METHOD_RETURN) |
| { |
| ; /* good, expected */ |
| _dbus_assert (dbus_message_get_reply_serial (message) == serial); |
| } |
| else |
| { |
| warn_unexpected (connection, message, "method return for AddMatch"); |
| |
| goto out; |
| } |
| } |
| |
| if (!check_no_leftovers (context)) |
| goto out; |
| |
| retval = TRUE; |
| |
| out: |
| dbus_error_free (&error); |
| |
| if (message) |
| dbus_message_unref (message); |
| |
| return retval; |
| } |
| |
| /* returns TRUE if the correct thing happens, |
| * but the correct thing may include OOM errors. |
| */ |
| static dbus_bool_t |
| check_hello_connection (BusContext *context) |
| { |
| DBusConnection *connection; |
| DBusError error; |
| |
| dbus_error_init (&error); |
| |
| connection = dbus_connection_open_private (TEST_CONNECTION, &error); |
| if (connection == NULL) |
| { |
| _DBUS_ASSERT_ERROR_IS_SET (&error); |
| dbus_error_free (&error); |
| return TRUE; |
| } |
| |
| if (!bus_setup_debug_client (connection)) |
| { |
| dbus_connection_close (connection); |
| dbus_connection_unref (connection); |
| return TRUE; |
| } |
| |
| spin_connection_until_authenticated (context, connection); |
| |
| if (!check_hello_message (context, connection)) |
| return FALSE; |
| |
| if (dbus_bus_get_unique_name (connection) == NULL) |
| { |
| /* We didn't successfully register, so we can't |
| * do the usual kill_client_connection() checks |
| */ |
| kill_client_connection_unchecked (connection); |
| } |
| else |
| { |
| if (!check_add_match_all (context, connection)) |
| return FALSE; |
| |
| kill_client_connection (context, connection); |
| } |
| |
| return TRUE; |
| } |
| |
| #define NONEXISTENT_SERVICE_NAME "test.this.service.does.not.exist.ewuoiurjdfxcvn" |
| |
| /* returns TRUE if the correct thing happens, |
| * but the correct thing may include OOM errors. |
| */ |
| static dbus_bool_t |
| check_nonexistent_service_no_auto_start (BusContext *context, |
| DBusConnection *connection) |
| { |
| DBusMessage *message; |
| dbus_uint32_t serial; |
| dbus_bool_t retval; |
| const char *nonexistent = NONEXISTENT_SERVICE_NAME; |
| dbus_uint32_t flags; |
| |
| message = dbus_message_new_method_call (DBUS_SERVICE_DBUS, |
| DBUS_PATH_DBUS, |
| DBUS_INTERFACE_DBUS, |
| "StartServiceByName"); |
| |
| if (message == NULL) |
| return TRUE; |
| |
| dbus_message_set_auto_start (message, FALSE); |
| |
| flags = 0; |
| if (!dbus_message_append_args (message, |
| DBUS_TYPE_STRING, &nonexistent, |
| DBUS_TYPE_UINT32, &flags, |
| DBUS_TYPE_INVALID)) |
| { |
| dbus_message_unref (message); |
| return TRUE; |
| } |
| |
| if (!dbus_connection_send (connection, message, &serial)) |
| { |
| dbus_message_unref (message); |
| return TRUE; |
| } |
| |
| dbus_message_unref (message); |
| message = NULL; |
| |
| bus_test_run_everything (context); |
| block_connection_until_message_from_bus (context, connection, "reply to ActivateService on nonexistent"); |
| bus_test_run_everything (context); |
| |
| if (!dbus_connection_get_is_connected (connection)) |
| { |
| _dbus_verbose ("connection was disconnected\n"); |
| return TRUE; |
| } |
| |
| retval = FALSE; |
| |
| message = pop_message_waiting_for_memory (connection); |
| if (message == NULL) |
| { |
| _dbus_warn ("Did not receive a reply to %s %d on %p\n", |
| "StartServiceByName", serial, connection); |
| goto out; |
| } |
| |
| verbose_message_received (connection, message); |
| |
| if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR) |
| { |
| if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS)) |
| { |
| _dbus_warn ("Message has wrong sender %s\n", |
| dbus_message_get_sender (message) ? |
| dbus_message_get_sender (message) : "(none)"); |
| goto out; |
| } |
| |
| if (dbus_message_is_error (message, |
| DBUS_ERROR_NO_MEMORY)) |
| { |
| ; /* good, this is a valid response */ |
| } |
| else if (dbus_message_is_error (message, |
| DBUS_ERROR_SERVICE_UNKNOWN)) |
| { |
| ; /* good, this is expected also */ |
| } |
| else |
| { |
| warn_unexpected (connection, message, "not this error"); |
| goto out; |
| } |
| } |
| else |
| { |
| _dbus_warn ("Did not expect to successfully activate %s\n", |
| NONEXISTENT_SERVICE_NAME); |
| goto out; |
| } |
| |
| retval = TRUE; |
| |
| out: |
| if (message) |
| dbus_message_unref (message); |
| |
| return retval; |
| } |
| |
| /* returns TRUE if the correct thing happens, |
| * but the correct thing may include OOM errors. |
| */ |
| static dbus_bool_t |
| check_nonexistent_service_auto_start (BusContext *context, |
| DBusConnection *connection) |
| { |
| DBusMessage *message; |
| dbus_uint32_t serial; |
| dbus_bool_t retval; |
| |
| message = dbus_message_new_method_call (NONEXISTENT_SERVICE_NAME, |
| "/org/freedesktop/TestSuite", |
| "org.freedesktop.TestSuite", |
| "Echo"); |
| |
| if (message == NULL) |
| return TRUE; |
| |
| if (!dbus_connection_send (connection, message, &serial)) |
| { |
| dbus_message_unref (message); |
| return TRUE; |
| } |
| |
| dbus_message_unref (message); |
| message = NULL; |
| |
| bus_test_run_everything (context); |
| block_connection_until_message_from_bus (context, connection, "reply to Echo"); |
| bus_test_run_everything (context); |
| |
| if (!dbus_connection_get_is_connected (connection)) |
| { |
| _dbus_verbose ("connection was disconnected\n"); |
| return TRUE; |
| } |
| |
| retval = FALSE; |
| |
| message = pop_message_waiting_for_memory (connection); |
| |
| if (message == NULL) |
| { |
| _dbus_warn ("Did not receive a reply to %s %d on %p\n", |
| "Echo message (auto activation)", serial, connection); |
| goto out; |
| } |
| |
| verbose_message_received (connection, message); |
| |
| if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR) |
| { |
| if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS)) |
| { |
| _dbus_warn ("Message has wrong sender %s\n", |
| dbus_message_get_sender (message) ? |
| dbus_message_get_sender (message) : "(none)"); |
| goto out; |
| } |
| |
| if (dbus_message_is_error (message, |
| DBUS_ERROR_NO_MEMORY)) |
| { |
| ; /* good, this is a valid response */ |
| } |
| else if (dbus_message_is_error (message, |
| DBUS_ERROR_SERVICE_UNKNOWN)) |
| { |
| ; /* good, this is expected also */ |
| } |
| else |
| { |
| warn_unexpected (connection, message, "not this error"); |
| goto out; |
| } |
| } |
| else |
| { |
| _dbus_warn ("Did not expect to successfully activate %s\n", |
| NONEXISTENT_SERVICE_NAME); |
| goto out; |
| } |
| |
| retval = TRUE; |
| |
| out: |
| if (message) |
| dbus_message_unref (message); |
| |
| return retval; |
| } |
| |
| static dbus_bool_t |
| check_base_service_activated (BusContext *context, |
| DBusConnection *connection, |
| DBusMessage *initial_message, |
| const char **base_service_p) |
| { |
| DBusMessage *message; |
| dbus_bool_t retval; |
| DBusError error; |
| const char *base_service, *base_service_from_bus, *old_owner; |
| |
| retval = FALSE; |
| |
| dbus_error_init (&error); |
| base_service = NULL; |
| old_owner = NULL; |
| base_service_from_bus = NULL; |
| |
| message = initial_message; |
| dbus_message_ref (message); |
| |
| if (dbus_message_is_signal (message, |
| DBUS_INTERFACE_DBUS, |
| "NameOwnerChanged")) |
| { |
| CheckServiceOwnerChangedData socd; |
| |
| reget_service_name_arg: |
| base_service = NULL; |
| old_owner = NULL; |
| base_service_from_bus = NULL; |
| |
| if (!dbus_message_get_args (message, &error, |
| DBUS_TYPE_STRING, &base_service, |
| DBUS_TYPE_STRING, &old_owner, |
| DBUS_TYPE_STRING, &base_service_from_bus, |
| DBUS_TYPE_INVALID)) |
| { |
| if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY)) |
| { |
| dbus_error_free (&error); |
| _dbus_wait_for_memory (); |
| goto reget_service_name_arg; |
| } |
| else |
| { |
| _dbus_warn ("Message %s doesn't have a service name: %s\n", |
| "NameOwnerChanged (creation)", |
| error.message); |
| goto out; |
| } |
| } |
| |
| if (*base_service != ':') |
| { |
| _dbus_warn ("Expected base service activation, got \"%s\" instead\n", |
| base_service); |
| goto out; |
| } |
| |
| if (strcmp (base_service, base_service_from_bus) != 0) |
| { |
| _dbus_warn ("Expected base service activation, got \"%s\" instead with owner \"%s\"\n", |
| base_service, base_service_from_bus); |
| goto out; |
| } |
| |
| if (old_owner[0]) |
| { |
| _dbus_warn ("Received an old_owner argument during base service activation, \"%s\"\n", |
| old_owner); |
| goto out; |
| } |
| |
| socd.expected_kind = SERVICE_CREATED; |
| socd.expected_service_name = base_service; |
| socd.failed = FALSE; |
| socd.skip_connection = connection; |
| bus_test_clients_foreach (check_service_owner_changed_foreach, |
| &socd); |
| |
| if (socd.failed) |
| goto out; |
| } |
| else |
| { |
| warn_unexpected (connection, message, "NameOwnerChanged (creation) for base service"); |
| |
| goto out; |
| } |
| |
| if (base_service_p) |
| *base_service_p = base_service; |
| |
| retval = TRUE; |
| |
| out: |
| if (message) |
| dbus_message_unref (message); |
| dbus_error_free (&error); |
| |
| return retval; |
| } |
| |
| static dbus_bool_t |
| check_service_activated (BusContext *context, |
| DBusConnection *connection, |
| const char *activated_name, |
| const char *base_service_name, |
| DBusMessage *initial_message) |
| { |
| DBusMessage *message; |
| dbus_bool_t retval; |
| DBusError error; |
| dbus_uint32_t activation_result; |
| |
| retval = FALSE; |
| |
| dbus_error_init (&error); |
| |
| message = initial_message; |
| dbus_message_ref (message); |
| |
| if (dbus_message_is_signal (message, |
| DBUS_INTERFACE_DBUS, |
| "NameOwnerChanged")) |
| { |
| CheckServiceOwnerChangedData socd; |
| const char *service_name, *base_service_from_bus, *old_owner; |
| |
| reget_service_name_arg: |
| service_name = NULL; |
| old_owner = NULL; |
| base_service_from_bus = NULL; |
| |
| if (!dbus_message_get_args (message, &error, |
| DBUS_TYPE_STRING, &service_name, |
| DBUS_TYPE_STRING, &old_owner, |
| DBUS_TYPE_STRING, &base_service_from_bus, |
| DBUS_TYPE_INVALID)) |
| { |
| if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY)) |
| { |
| dbus_error_free (&error); |
| _dbus_wait_for_memory (); |
| goto reget_service_name_arg; |
| } |
| else |
| { |
| _dbus_warn ("Message %s doesn't have a service name: %s\n", |
| "NameOwnerChanged (creation)", |
| error.message); |
| goto out; |
| } |
| } |
| |
| if (strcmp (service_name, activated_name) != 0) |
| { |
| _dbus_warn ("Expected to see service %s created, saw %s instead\n", |
| activated_name, service_name); |
| goto out; |
| } |
| |
| if (strcmp (base_service_name, base_service_from_bus) != 0) |
| { |
| _dbus_warn ("NameOwnerChanged reports wrong base service: %s owner, expected %s instead\n", |
| base_service_from_bus, base_service_name); |
| goto out; |
| } |
| |
| if (old_owner[0]) |
| { |
| _dbus_warn ("expected a %s, got a %s\n", |
| "NameOwnerChanged (creation)", |
| "NameOwnerChanged (change)"); |
| goto out; |
| } |
| |
| socd.expected_kind = SERVICE_CREATED; |
| socd.skip_connection = connection; |
| socd.failed = FALSE; |
| socd.expected_service_name = service_name; |
| bus_test_clients_foreach (check_service_owner_changed_foreach, |
| &socd); |
| |
| if (socd.failed) |
| goto out; |
| |
| dbus_message_unref (message); |
| service_name = NULL; |
| old_owner = NULL; |
| base_service_from_bus = NULL; |
| |
| message = pop_message_waiting_for_memory (connection); |
| if (message == NULL) |
| { |
| _dbus_warn ("Expected a reply to %s, got nothing\n", |
| "StartServiceByName"); |
| goto out; |
| } |
| } |
| else |
| { |
| warn_unexpected (connection, message, "NameOwnerChanged for the activated name"); |
| |
| goto out; |
| } |
| |
| if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_METHOD_RETURN) |
| { |
| warn_unexpected (connection, message, "reply to StartServiceByName"); |
| |
| goto out; |
| } |
| |
| activation_result = 0; |
| if (!dbus_message_get_args (message, &error, |
| DBUS_TYPE_UINT32, &activation_result, |
| DBUS_TYPE_INVALID)) |
| { |
| if (!dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY)) |
| { |
| _dbus_warn ("Did not have activation result first argument to %s: %s\n", |
| "StartServiceByName", error.message); |
| goto out; |
| } |
| |
| dbus_error_free (&error); |
| } |
| else |
| { |
| if (activation_result == DBUS_START_REPLY_SUCCESS) |
| ; /* Good */ |
| else if (activation_result == DBUS_START_REPLY_ALREADY_RUNNING) |
| ; /* Good also */ |
| else |
| { |
| _dbus_warn ("Activation result was %u, no good.\n", |
| activation_result); |
| goto out; |
| } |
| } |
| |
| dbus_message_unref (message); |
| message = NULL; |
| |
| if (!check_no_leftovers (context)) |
| { |
| _dbus_warn ("Messages were left over after verifying existent activation results\n"); |
| goto out; |
| } |
| |
| retval = TRUE; |
| |
| out: |
| if (message) |
| dbus_message_unref (message); |
| dbus_error_free (&error); |
| |
| return retval; |
| } |
| |
| static dbus_bool_t |
| check_service_auto_activated (BusContext *context, |
| DBusConnection *connection, |
| const char *activated_name, |
| const char *base_service_name, |
| DBusMessage *initial_message) |
| { |
| DBusMessage *message; |
| dbus_bool_t retval; |
| DBusError error; |
| |
| retval = FALSE; |
| |
| dbus_error_init (&error); |
| |
| message = initial_message; |
| dbus_message_ref (message); |
| |
| if (dbus_message_is_signal (message, |
| DBUS_INTERFACE_DBUS, |
| "NameOwnerChanged")) |
| { |
| const char *service_name; |
| CheckServiceOwnerChangedData socd; |
| |
| reget_service_name_arg: |
| if (!dbus_message_get_args (message, &error, |
| DBUS_TYPE_STRING, &service_name, |
| DBUS_TYPE_INVALID)) |
| { |
| if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY)) |
| { |
| dbus_error_free (&error); |
| _dbus_wait_for_memory (); |
| goto reget_service_name_arg; |
| } |
| else |
| { |
| _dbus_warn ("Message %s doesn't have a service name: %s\n", |
| "NameOwnerChanged", |
| error.message); |
| dbus_error_free (&error); |
| goto out; |
| } |
| } |
| |
| if (strcmp (service_name, activated_name) != 0) |
| { |
| _dbus_warn ("Expected to see service %s created, saw %s instead\n", |
| activated_name, service_name); |
| goto out; |
| } |
| |
| socd.expected_kind = SERVICE_CREATED; |
| socd.expected_service_name = service_name; |
| socd.failed = FALSE; |
| socd.skip_connection = connection; |
| bus_test_clients_foreach (check_service_owner_changed_foreach, |
| &socd); |
| |
| if (socd.failed) |
| goto out; |
| |
| /* Note that this differs from regular activation in that we don't get a |
| * reply to ActivateService here. |
| */ |
| |
| dbus_message_unref (message); |
| message = NULL; |
| service_name = NULL; |
| } |
| else |
| { |
| warn_unexpected (connection, message, "NameOwnerChanged for the activated name"); |
| |
| goto out; |
| } |
| |
| retval = TRUE; |
| |
| out: |
| if (message) |
| dbus_message_unref (message); |
| |
| return retval; |
| } |
| |
| static dbus_bool_t |
| check_service_deactivated (BusContext *context, |
| DBusConnection *connection, |
| const char *activated_name, |
| const char *base_service) |
| { |
| dbus_bool_t retval; |
| CheckServiceOwnerChangedData socd; |
| |
| retval = FALSE; |
| |
| /* Now we are expecting ServiceOwnerChanged (deletion) messages for the base |
| * service and the activated_name. The base service |
| * notification is required to come last. |
| */ |
| socd.expected_kind = SERVICE_DELETED; |
| socd.expected_service_name = activated_name; |
| socd.failed = FALSE; |
| socd.skip_connection = NULL; |
| bus_test_clients_foreach (check_service_owner_changed_foreach, |
| &socd); |
| |
| if (socd.failed) |
| goto out; |
| |
| socd.expected_kind = SERVICE_DELETED; |
| socd.expected_service_name = base_service; |
| socd.failed = FALSE; |
| socd.skip_connection = NULL; |
| bus_test_clients_foreach (check_service_owner_changed_foreach, |
| &socd); |
| |
| if (socd.failed) |
| goto out; |
| |
| retval = TRUE; |
| |
| out: |
| return retval; |
| } |
| |
| static dbus_bool_t |
| check_send_exit_to_service (BusContext *context, |
| DBusConnection *connection, |
| const char *service_name, |
| const char *base_service) |
| { |
| dbus_bool_t got_error; |
| DBusMessage *message; |
| dbus_uint32_t serial; |
| dbus_bool_t retval; |
| |
| _dbus_verbose ("Sending exit message to the test service\n"); |
| |
| retval = FALSE; |
| |
| /* Kill off the test service by sending it a quit message */ |
| message = dbus_message_new_method_call (service_name, |
| "/org/freedesktop/TestSuite", |
| "org.freedesktop.TestSuite", |
| "Exit"); |
| |
| if (message == NULL) |
| { |
| /* Do this again; we still need the service to exit... */ |
| if (!check_send_exit_to_service (context, connection, |
| service_name, base_service)) |
| goto out; |
| |
| return TRUE; |
| } |
| |
| if (!dbus_connection_send (connection, message, &serial)) |
| { |
| dbus_message_unref (message); |
| |
| /* Do this again; we still need the service to exit... */ |
| if (!check_send_exit_to_service (context, connection, |
| service_name, base_service)) |
| goto out; |
| |
| return TRUE; |
| } |
| |
| dbus_message_unref (message); |
| message = NULL; |
| |
| /* send message */ |
| bus_test_run_clients_loop (SEND_PENDING (connection)); |
| |
| /* read it in and write it out to test service */ |
| bus_test_run_bus_loop (context, FALSE); |
| |
| /* see if we got an error during message bus dispatching */ |
| bus_test_run_clients_loop (FALSE); |
| message = borrow_message_waiting_for_memory (connection); |
| got_error = message != NULL && dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR; |
| if (message) |
| { |
| dbus_connection_return_message (connection, message); |
| message = NULL; |
| } |
| |
| if (!got_error) |
| { |
| /* If no error, wait for the test service to exit */ |
| block_connection_until_message_from_bus (context, connection, "test service to exit"); |
| |
| bus_test_run_everything (context); |
| } |
| |
| if (got_error) |
| { |
| message = pop_message_waiting_for_memory (connection); |
| _dbus_assert (message != NULL); |
| |
| if (dbus_message_get_reply_serial (message) != serial) |
| { |
| warn_unexpected (connection, message, |
| "error with the correct reply serial"); |
| goto out; |
| } |
| |
| if (!dbus_message_is_error (message, |
| DBUS_ERROR_NO_MEMORY)) |
| { |
| warn_unexpected (connection, message, |
| "a no memory error from asking test service to exit"); |
| goto out; |
| } |
| |
| _dbus_verbose ("Got error %s when asking test service to exit\n", |
| dbus_message_get_error_name (message)); |
| |
| /* Do this again; we still need the service to exit... */ |
| if (!check_send_exit_to_service (context, connection, |
| service_name, base_service)) |
| goto out; |
| } |
| else |
| { |
| if (!check_service_deactivated (context, connection, |
| service_name, base_service)) |
| goto out; |
| |
| /* Should now have a NoReply error from the Exit() method |
| * call; it should have come after all the deactivation |
| * stuff. |
| */ |
| message = pop_message_waiting_for_memory (connection); |
| |
| if (message == NULL) |
| { |
| warn_unexpected (connection, NULL, |
| "reply to Exit() method call"); |
| goto out; |
| } |
| if (!dbus_message_is_error (message, |
| DBUS_ERROR_NO_REPLY)) |
| { |
| warn_unexpected (connection, message, |
| "NoReply error from Exit() method call"); |
| goto out; |
| } |
| |
| if (dbus_message_get_reply_serial (message) != serial) |
| { |
| warn_unexpected (connection, message, |
| "error with the correct reply serial"); |
| goto out; |
| } |
| |
| _dbus_verbose ("Got error %s after test service exited\n", |
| dbus_message_get_error_name (message)); |
| |
| if (!check_no_leftovers (context)) |
| { |
| _dbus_warn ("Messages were left over after %s\n", |
| _DBUS_FUNCTION_NAME); |
| goto out; |
| } |
| } |
| |
| retval = TRUE; |
| |
| out: |
| if (message) |
| dbus_message_unref (message); |
| |
| return retval; |
| } |
| |
| static dbus_bool_t |
| check_got_error (BusContext *context, |
| DBusConnection *connection, |
| const char *first_error_name, |
| ...) |
| { |
| DBusMessage *message; |
| dbus_bool_t retval; |
| va_list ap; |
| dbus_bool_t error_found; |
| const char *error_name; |
| |
| retval = FALSE; |
| |
| message = pop_message_waiting_for_memory (connection); |
| if (message == NULL) |
| { |
| _dbus_warn ("Did not get an expected error\n"); |
| goto out; |
| } |
| |
| if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_ERROR) |
| { |
| warn_unexpected (connection, message, "an error"); |
| |
| goto out; |
| } |
| |
| error_found = FALSE; |
| |
| va_start (ap, first_error_name); |
| error_name = first_error_name; |
| while (error_name != NULL) |
| { |
| if (dbus_message_is_error (message, error_name)) |
| { |
| error_found = TRUE; |
| break; |
| } |
| error_name = va_arg (ap, char*); |
| } |
| va_end (ap); |
| |
| if (!error_found) |
| { |
| _dbus_warn ("Expected error %s or other, got %s instead\n", |
| first_error_name, |
| dbus_message_get_error_name (message)); |
| goto out; |
| } |
| |
| retval = TRUE; |
| |
| out: |
| if (message) |
| dbus_message_unref (message); |
| |
| return retval; |
| } |
| |
| typedef enum |
| { |
| GOT_SERVICE_CREATED, |
| GOT_SERVICE_DELETED, |
| GOT_ERROR, |
| GOT_SOMETHING_ELSE |
| } GotServiceInfo; |
| |
| static GotServiceInfo |
| check_got_service_info (DBusMessage *message) |
| { |
| GotServiceInfo message_kind; |
| |
| if (dbus_message_is_signal (message, |
| DBUS_INTERFACE_DBUS, |
| "NameOwnerChanged")) |
| { |
| DBusError error; |
| const char *service_name, *old_owner, *new_owner; |
| dbus_error_init (&error); |
| |
| reget_service_info_data: |
| service_name = NULL; |
| old_owner = NULL; |
| new_owner = NULL; |
| |
| dbus_message_get_args (message, &error, |
| DBUS_TYPE_STRING, &service_name, |
| DBUS_TYPE_STRING, &old_owner, |
| DBUS_TYPE_STRING, &new_owner, |
| DBUS_TYPE_INVALID); |
| if (dbus_error_is_set (&error)) |
| { |
| if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY)) |
| { |
| dbus_error_free (&error); |
| goto reget_service_info_data; |
| } |
| else |
| { |
| _dbus_warn ("unexpected arguments for NameOwnerChanged message\n"); |
| message_kind = GOT_SOMETHING_ELSE; |
| } |
| } |
| else if (!old_owner[0]) |
| message_kind = GOT_SERVICE_CREATED; |
| else if (!new_owner[0]) |
| message_kind = GOT_SERVICE_DELETED; |
| else |
| message_kind = GOT_SOMETHING_ELSE; |
| |
| dbus_error_free (&error); |
| } |
| else if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR) |
| message_kind = GOT_ERROR; |
| else |
| message_kind = GOT_SOMETHING_ELSE; |
| |
| return message_kind; |
| } |
| |
| #define EXISTENT_SERVICE_NAME "org.freedesktop.DBus.TestSuiteEchoService" |
| |
| /* returns TRUE if the correct thing happens, |
| * but the correct thing may include OOM errors. |
| */ |
| static dbus_bool_t |
| check_existent_service_no_auto_start (BusContext *context, |
| DBusConnection *connection) |
| { |
| DBusMessage *message; |
| DBusMessage *base_service_message; |
| const char *base_service; |
| dbus_uint32_t serial; |
| dbus_bool_t retval; |
| const char *existent = EXISTENT_SERVICE_NAME; |
| dbus_uint32_t flags; |
| |
| base_service_message = NULL; |
| |
| message = dbus_message_new_method_call (DBUS_SERVICE_DBUS, |
| DBUS_PATH_DBUS, |
| DBUS_INTERFACE_DBUS, |
| "StartServiceByName"); |
| |
| if (message == NULL) |
| return TRUE; |
| |
| dbus_message_set_auto_start (message, FALSE); |
| |
| flags = 0; |
| if (!dbus_message_append_args (message, |
| DBUS_TYPE_STRING, &existent, |
| DBUS_TYPE_UINT32, &flags, |
| DBUS_TYPE_INVALID)) |
| { |
| dbus_message_unref (message); |
| return TRUE; |
| } |
| |
| if (!dbus_connection_send (connection, message, &serial)) |
| { |
| dbus_message_unref (message); |
| return TRUE; |
| } |
| |
| dbus_message_unref (message); |
| message = NULL; |
| |
| bus_test_run_everything (context); |
| |
| /* now wait for the message bus to hear back from the activated |
| * service. |
| */ |
| block_connection_until_message_from_bus (context, connection, "activated service to connect"); |
| |
| bus_test_run_everything (context); |
| |
| if (!dbus_connection_get_is_connected (connection)) |
| { |
| _dbus_verbose ("connection was disconnected\n"); |
| return TRUE; |
| } |
| |
| retval = FALSE; |
| |
| message = pop_message_waiting_for_memory (connection); |
| if (message == NULL) |
| { |
| _dbus_warn ("Did not receive any messages after %s %d on %p\n", |
| "StartServiceByName", serial, connection); |
| goto out; |
| } |
| |
| verbose_message_received (connection, message); |
| _dbus_verbose (" (after sending %s)\n", "StartServiceByName"); |
| |
| if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR) |
| { |
| if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS)) |
| { |
| _dbus_warn ("Message has wrong sender %s\n", |
| dbus_message_get_sender (message) ? |
| dbus_message_get_sender (message) : "(none)"); |
| goto out; |
| } |
| |
| if (dbus_message_is_error (message, |
| DBUS_ERROR_NO_MEMORY)) |
| { |
| ; /* good, this is a valid response */ |
| } |
| else if (dbus_message_is_error (message, |
| DBUS_ERROR_SPAWN_CHILD_EXITED) || |
| dbus_message_is_error (message, |
| DBUS_ERROR_SPAWN_CHILD_SIGNALED) || |
| dbus_message_is_error (message, |
| DBUS_ERROR_SPAWN_EXEC_FAILED)) |
| { |
| ; /* good, this is expected also */ |
| } |
| else |
| { |
| _dbus_warn ("Did not expect error %s\n", |
| dbus_message_get_error_name (message)); |
| goto out; |
| } |
| } |
| else |
| { |
| GotServiceInfo message_kind; |
| |
| if (!check_base_service_activated (context, connection, |
| message, &base_service)) |
| goto out; |
| |
| base_service_message = message; |
| message = NULL; |
| |
| /* We may need to block here for the test service to exit or finish up */ |
| block_connection_until_message_from_bus (context, connection, "test service to exit or finish up"); |
| |
| message = dbus_connection_borrow_message (connection); |
| if (message == NULL) |
| { |
| _dbus_warn ("Did not receive any messages after base service creation notification\n"); |
| goto out; |
| } |
| |
| message_kind = check_got_service_info (message); |
| |
| dbus_connection_return_message (connection, message); |
| message = NULL; |
| |
| switch (message_kind) |
| { |
| case GOT_SOMETHING_ELSE: |
| _dbus_warn ("Unexpected message after ActivateService " |
| "(should be an error or a service announcement"); |
| goto out; |
| |
| case GOT_ERROR: |
| if (!check_got_error (context, connection, |
| DBUS_ERROR_SPAWN_CHILD_EXITED, |
| DBUS_ERROR_NO_MEMORY, |
| NULL)) |
| goto out; |
| /* A service deleted should be coming along now after this error. |
| * We can also get the error *after* the service deleted. |
| */ |
| |
| /* fall through */ |
| |
| case GOT_SERVICE_DELETED: |
| { |
| /* The service started up and got a base address, but then |
| * failed to register under EXISTENT_SERVICE_NAME |
| */ |
| CheckServiceOwnerChangedData socd; |
| |
| socd.expected_kind = SERVICE_DELETED; |
| socd.expected_service_name = base_service; |
| socd.failed = FALSE; |
| socd.skip_connection = NULL; |
| |
| bus_test_clients_foreach (check_service_owner_changed_foreach, |
| &socd); |
| |
| if (socd.failed) |
| goto out; |
| |
| /* Now we should get an error about the service exiting |
| * if we didn't get it before. |
| */ |
| if (message_kind != GOT_ERROR) |
| { |
| block_connection_until_message_from_bus (context, connection, "error about service exiting"); |
| |
| /* and process everything again */ |
| bus_test_run_everything (context); |
| |
| if (!check_got_error (context, connection, |
| DBUS_ERROR_SPAWN_CHILD_EXITED, |
| DBUS_ERROR_NO_MEMORY, |
| NULL)) |
| goto out; |
| } |
| break; |
| } |
| |
| case GOT_SERVICE_CREATED: |
| message = pop_message_waiting_for_memory (connection); |
| if (message == NULL) |
| { |
| _dbus_warn ("Failed to pop message we just put back! " |
| "should have been a NameOwnerChanged (creation)\n"); |
| goto out; |
| } |
| |
| if (!check_service_activated (context, connection, EXISTENT_SERVICE_NAME, |
| base_service, message)) |
| goto out; |
| |
| dbus_message_unref (message); |
| message = NULL; |
| |
| if (!check_no_leftovers (context)) |
| { |
| _dbus_warn ("Messages were left over after successful activation\n"); |
| goto out; |
| } |
| |
| if (!check_send_exit_to_service (context, connection, |
| EXISTENT_SERVICE_NAME, base_service)) |
| goto out; |
| |
| break; |
| } |
| } |
| |
| retval = TRUE; |
| |
| out: |
| if (message) |
| dbus_message_unref (message); |
| |
| if (base_service_message) |
| dbus_message_unref (base_service_message); |
| |
| return retval; |
| } |
| |
| #ifndef DBUS_WIN_FIXME |
| /* returns TRUE if the correct thing happens, |
| * but the correct thing may include OOM errors. |
| */ |
| static dbus_bool_t |
| check_segfault_service_no_auto_start (BusContext *context, |
| DBusConnection *connection) |
| { |
| DBusMessage *message; |
| dbus_uint32_t serial; |
| dbus_bool_t retval; |
| const char *segv_service; |
| dbus_uint32_t flags; |
| |
| message = dbus_message_new_method_call (DBUS_SERVICE_DBUS, |
| DBUS_PATH_DBUS, |
| DBUS_INTERFACE_DBUS, |
| "StartServiceByName"); |
| |
| if (message == NULL) |
| return TRUE; |
| |
| dbus_message_set_auto_start (message, FALSE); |
| |
| segv_service = "org.freedesktop.DBus.TestSuiteSegfaultService"; |
| flags = 0; |
| if (!dbus_message_append_args (message, |
| DBUS_TYPE_STRING, &segv_service, |
| DBUS_TYPE_UINT32, &flags, |
| DBUS_TYPE_INVALID)) |
| { |
| dbus_message_unref (message); |
| return TRUE; |
| } |
| |
| if (!dbus_connection_send (connection, message, &serial)) |
| { |
| dbus_message_unref (message); |
| return TRUE; |
| } |
| |
| dbus_message_unref (message); |
| message = NULL; |
| |
| bus_test_run_everything (context); |
| block_connection_until_message_from_bus (context, connection, "reply to activating segfault service"); |
| bus_test_run_everything (context); |
| |
| if (!dbus_connection_get_is_connected (connection)) |
| { |
| _dbus_verbose ("connection was disconnected\n"); |
| return TRUE; |
| } |
| |
| retval = FALSE; |
| |
| message = pop_message_waiting_for_memory (connection); |
| if (message == NULL) |
| { |
| _dbus_warn ("Did not receive a reply to %s %d on %p\n", |
| "StartServiceByName", serial, connection); |
| goto out; |
| } |
| |
| verbose_message_received (connection, message); |
| |
| if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR) |
| { |
| if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS)) |
| { |
| _dbus_warn ("Message has wrong sender %s\n", |
| dbus_message_get_sender (message) ? |
| dbus_message_get_sender (message) : "(none)"); |
| goto out; |
| } |
| |
| if (dbus_message_is_error (message, |
| DBUS_ERROR_NO_MEMORY)) |
| { |
| ; /* good, this is a valid response */ |
| } |
| else if (dbus_message_is_error (message, |
| DBUS_ERROR_FAILED)) |
| { |
| const char *servicehelper; |
| servicehelper = bus_context_get_servicehelper (context); |
| /* make sure this only happens with the launch helper */ |
| _dbus_assert (servicehelper != NULL); |
| } |
| else if (dbus_message_is_error (message, |
| DBUS_ERROR_SPAWN_CHILD_SIGNALED)) |
| { |
| ; /* good, this is expected also */ |
| } |
| else |
| { |
| warn_unexpected (connection, message, "not this error"); |
| |
| goto out; |
| } |
| } |
| else |
| { |
| _dbus_warn ("Did not expect to successfully activate segfault service\n"); |
| goto out; |
| } |
| |
| retval = TRUE; |
| |
| out: |
| if (message) |
| dbus_message_unref (message); |
| |
| return retval; |
| } |
| |
| |
| /* returns TRUE if the correct thing happens, |
| * but the correct thing may include OOM errors. |
| */ |
| static dbus_bool_t |
| check_segfault_service_auto_start (BusContext *context, |
| DBusConnection *connection) |
| { |
| DBusMessage *message; |
| dbus_uint32_t serial; |
| dbus_bool_t retval; |
| |
| message = dbus_message_new_method_call ("org.freedesktop.DBus.TestSuiteSegfaultService", |
| "/org/freedesktop/TestSuite", |
| "org.freedesktop.TestSuite", |
| "Echo"); |
| |
| if (message == NULL) |
| return TRUE; |
| |
| if (!dbus_connection_send (connection, message, &serial)) |
| { |
| dbus_message_unref (message); |
| return TRUE; |
| } |
| |
| dbus_message_unref (message); |
| message = NULL; |
| |
| bus_test_run_everything (context); |
| block_connection_until_message_from_bus (context, connection, "reply to Echo on segfault service"); |
| bus_test_run_everything (context); |
| |
| if (!dbus_connection_get_is_connected (connection)) |
| { |
| _dbus_verbose ("connection was disconnected\n"); |
| return TRUE; |
| } |
| |
| retval = FALSE; |
| |
| message = pop_message_waiting_for_memory (connection); |
| if (message == NULL) |
| { |
| _dbus_warn ("Did not receive a reply to %s %d on %p\n", |
| "Echo message (auto activation)", serial, connection); |
| goto out; |
| } |
| |
| verbose_message_received (connection, message); |
| |
| if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR) |
| { |
| if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS)) |
| { |
| _dbus_warn ("Message has wrong sender %s\n", |
| dbus_message_get_sender (message) ? |
| dbus_message_get_sender (message) : "(none)"); |
| goto out; |
| } |
| |
| if (dbus_message_is_error (message, |
| DBUS_ERROR_NO_MEMORY)) |
| { |
| ; /* good, this is a valid response */ |
| } |
| else if (dbus_message_is_error (message, |
| DBUS_ERROR_SPAWN_CHILD_SIGNALED)) |
| { |
| ; /* good, this is expected also */ |
| } |
| else |
| { |
| warn_unexpected (connection, message, "not this error"); |
| |
| goto out; |
| } |
| } |
| else |
| { |
| _dbus_warn ("Did not expect to successfully activate segfault service\n"); |
| goto out; |
| } |
| |
| retval = TRUE; |
| |
| out: |
| if (message) |
| dbus_message_unref (message); |
| |
| return retval; |
| } |
| #endif |
| |
| #define TEST_ECHO_MESSAGE "Test echo message" |
| #define TEST_RUN_HELLO_FROM_SELF_MESSAGE "Test sending message to self" |
| |
| /* returns TRUE if the correct thing happens, |
| * but the correct thing may include OOM errors. |
| */ |
| static dbus_bool_t |
| check_existent_hello_from_self (BusContext *context, |
| DBusConnection *connection) |
| { |
| DBusMessage *message; |
| dbus_uint32_t serial; |
| const char *text; |
| |
| message = dbus_message_new_method_call (EXISTENT_SERVICE_NAME, |
| "/org/freedesktop/TestSuite", |
| "org.freedesktop.TestSuite", |
| "RunHelloFromSelf"); |
| |
| if (message == NULL) |
| return TRUE; |
| |
| text = TEST_RUN_HELLO_FROM_SELF_MESSAGE; |
| if (!dbus_message_append_args (message, |
| DBUS_TYPE_STRING, &text, |
| DBUS_TYPE_INVALID)) |
| { |
| dbus_message_unref (message); |
| return TRUE; |
| } |
| |
| if (!dbus_connection_send (connection, message, &serial)) |
| { |
| dbus_message_unref (message); |
| return TRUE; |
| } |
| |
| dbus_message_unref (message); |
| message = NULL; |
| |
| bus_test_run_everything (context); |
| |
| /* Note: if this test is run in OOM mode, it will block when the bus |
| * doesn't send a reply due to OOM. |
| */ |
| block_connection_until_message_from_bus (context, connection, "reply from running hello from self"); |
| |
| message = pop_message_waiting_for_memory (connection); |
| if (message == NULL) |
| { |
| _dbus_warn ("Failed to pop message! Should have been reply from RunHelloFromSelf message\n"); |
| return FALSE; |
| } |
| |
| if (dbus_message_get_reply_serial (message) != serial) |
| { |
| _dbus_warn ("Wrong reply serial\n"); |
| dbus_message_unref (message); |
| return FALSE; |
| } |
| |
| dbus_message_unref (message); |
| message = NULL; |
| |
| return TRUE; |
| } |
| |
| /* returns TRUE if the correct thing happens, |
| * but the correct thing may include OOM errors. |
| */ |
| static dbus_bool_t |
| check_existent_ping (BusContext *context, |
| DBusConnection *connection) |
| { |
| DBusMessage *message; |
| dbus_uint32_t serial; |
| message = dbus_message_new_method_call (EXISTENT_SERVICE_NAME, |
| "/org/freedesktop/TestSuite", |
| "org.freedesktop.DBus.Peer", |
| "Ping"); |
| |
| if (message == NULL) |
| return TRUE; |
| |
| if (!dbus_connection_send (connection, message, &serial)) |
| { |
| dbus_message_unref (message); |
| return TRUE; |
| } |
| |
| dbus_message_unref (message); |
| message = NULL; |
| |
| bus_test_run_everything (context); |
| |
| /* Note: if this test is run in OOM mode, it will block when the bus |
| * doesn't send a reply due to OOM. |
| */ |
| block_connection_until_message_from_bus (context, connection, "reply from running Ping"); |
| |
| message = pop_message_waiting_for_memory (connection); |
| if (message == NULL) |
| { |
| _dbus_warn ("Failed to pop message! Should have been reply from Ping message\n"); |
| return FALSE; |
| } |
| |
| if (dbus_message_get_reply_serial (message) != serial) |
| { |
| _dbus_warn ("Wrong reply serial\n"); |
| dbus_message_unref (message); |
| return FALSE; |
| } |
| |
| if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_METHOD_RETURN) |
| { |
| _dbus_warn ("Unexpected message return during Ping\n"); |
| dbus_message_unref (message); |
| return FALSE; |
| } |
| |
| dbus_message_unref (message); |
| message = NULL; |
| |
| return TRUE; |
| } |
| |
| /* returns TRUE if the correct thing happens, |
| * but the correct thing may include OOM errors. |
| */ |
| static dbus_bool_t |
| check_existent_get_machine_id (BusContext *context, |
| DBusConnection *connection) |
| { |
| DBusMessage *message; |
| dbus_uint32_t serial; |
| const char *machine_id; |
| |
| message = dbus_message_new_method_call (EXISTENT_SERVICE_NAME, |
| "/org/freedesktop/TestSuite", |
| "org.freedesktop.DBus.Peer", |
| "GetMachineId"); |
| |
| if (message == NULL) |
| return TRUE; |
| |
| if (!dbus_connection_send (connection, message, &serial)) |
| { |
| dbus_message_unref (message); |
| return TRUE; |
| } |
| |
| dbus_message_unref (message); |
| message = NULL; |
| |
| bus_test_run_everything (context); |
| |
| /* Note: if this test is run in OOM mode, it will block when the bus |
| * doesn't send a reply due to OOM. |
| */ |
| block_connection_until_message_from_bus (context, connection, "reply from running GetMachineId"); |
| |
| message = pop_message_waiting_for_memory (connection); |
| if (message == NULL) |
| { |
| _dbus_warn ("Failed to pop message! Should have been reply from GetMachineId message\n"); |
| return FALSE; |
| } |
| |
| if (dbus_message_get_reply_serial (message) != serial) |
| { |
| _dbus_warn ("Wrong reply serial\n"); |
| dbus_message_unref (message); |
| return FALSE; |
| } |
| |
| if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_METHOD_RETURN) |
| { |
| _dbus_warn ("Unexpected message return during GetMachineId\n"); |
| dbus_message_unref (message); |
| return FALSE; |
| } |
| |
| machine_id = NULL; |
| if (!dbus_message_get_args (message, NULL, DBUS_TYPE_STRING, &machine_id, DBUS_TYPE_INVALID)) |
| { |
| _dbus_warn ("Did not get a machine ID in reply to GetMachineId\n"); |
| dbus_message_unref (message); |
| return FALSE; |
| } |
| |
| if (machine_id == NULL || strlen (machine_id) != 32) |
| { |
| _dbus_warn ("Machine id looks bogus: '%s'\n", machine_id ? machine_id : "null"); |
| dbus_message_unref (message); |
| return FALSE; |
| } |
| |
| /* We can't check that the machine id is correct because during make check it is |
| * just made up for each process separately |
| */ |
| |
| dbus_message_unref (message); |
| message = NULL; |
| |
| return TRUE; |
| } |
| |
| /* returns TRUE if the correct thing happens, |
| * but the correct thing may include OOM errors. |
| */ |
| static dbus_bool_t |
| check_existent_service_auto_start (BusContext *context, |
| DBusConnection *connection) |
| { |
| DBusMessage *message; |
| DBusMessage *base_service_message; |
| dbus_uint32_t serial; |
| dbus_bool_t retval; |
| const char *base_service; |
| const char *text; |
| |
| base_service_message = NULL; |
| |
| message = dbus_message_new_method_call (EXISTENT_SERVICE_NAME, |
| "/org/freedesktop/TestSuite", |
| "org.freedesktop.TestSuite", |
| "Echo"); |
| |
| if (message == NULL) |
| return TRUE; |
| |
| text = TEST_ECHO_MESSAGE; |
| if (!dbus_message_append_args (message, |
| DBUS_TYPE_STRING, &text, |
| DBUS_TYPE_INVALID)) |
| { |
| dbus_message_unref (message); |
| return TRUE; |
| } |
| |
| if (!dbus_connection_send (connection, message, &serial)) |
| { |
| dbus_message_unref (message); |
| return TRUE; |
| } |
| |
| dbus_message_unref (message); |
| message = NULL; |
| |
| bus_test_run_everything (context); |
| |
| /* now wait for the message bus to hear back from the activated |
| * service. |
| */ |
| block_connection_until_message_from_bus (context, connection, "reply to Echo on existent service"); |
| bus_test_run_everything (context); |
| |
| if (!dbus_connection_get_is_connected (connection)) |
| { |
| _dbus_verbose ("connection was disconnected\n"); |
| return TRUE; |
| } |
| |
| retval = FALSE; |
| |
| message = pop_message_waiting_for_memory (connection); |
| if (message == NULL) |
| { |
| _dbus_warn ("Did not receive any messages after auto start %d on %p\n", |
| serial, connection); |
| goto out; |
| } |
| |
| verbose_message_received (connection, message); |
| _dbus_verbose (" (after sending %s)\n", "auto start"); |
| |
| /* we should get zero or two ServiceOwnerChanged signals */ |
| if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_SIGNAL) |
| { |
| GotServiceInfo message_kind; |
| |
| if (!check_base_service_activated (context, connection, |
| message, &base_service)) |
| goto out; |
| |
| base_service_message = message; |
| message = NULL; |
| |
| /* We may need to block here for the test service to exit or finish up */ |
| block_connection_until_message_from_bus (context, connection, "service to exit"); |
| |
| /* Should get a service creation notification for the activated |
| * service name, or a service deletion on the base service name |
| */ |
| message = dbus_connection_borrow_message (connection); |
| if (message == NULL) |
| { |
| _dbus_warn ("No message after auto activation " |
| "(should be a service announcement)\n"); |
| dbus_connection_return_message (connection, message); |
| message = NULL; |
| goto out; |
| } |
| |
| message_kind = check_got_service_info (message); |
| |
| dbus_connection_return_message (connection, message); |
| message = NULL; |
| |
| switch (message_kind) |
| { |
| case GOT_SERVICE_CREATED: |
| message = pop_message_waiting_for_memory (connection); |
| if (message == NULL) |
| { |
| _dbus_warn ("Failed to pop message we just put back! " |
| "should have been a NameOwnerChanged (creation)\n"); |
| goto out; |
| } |
| |
| /* Check that ServiceOwnerChanged (creation) was correctly received */ |
| if (!check_service_auto_activated (context, connection, EXISTENT_SERVICE_NAME, |
| base_service, message)) |
| goto out; |
| |
| dbus_message_unref (message); |
| message = NULL; |
| |
| break; |
| |
| case GOT_SERVICE_DELETED: |
| { |
| /* The service started up and got a base address, but then |
| * failed to register under EXISTENT_SERVICE_NAME |
| */ |
| CheckServiceOwnerChangedData socd; |
| |
| socd.expected_kind = SERVICE_DELETED; |
| socd.expected_service_name = base_service; |
| socd.failed = FALSE; |
| socd.skip_connection = NULL; |
| bus_test_clients_foreach (check_service_owner_changed_foreach, |
| &socd); |
| |
| if (socd.failed) |
| goto out; |
| |
| break; |
| } |
| |
| case GOT_ERROR: |
| case GOT_SOMETHING_ELSE: |
| _dbus_warn ("Unexpected message after auto activation\n"); |
| goto out; |
| } |
| } |
| |
| /* OK, now we've dealt with ServiceOwnerChanged signals, now should |
| * come the method reply (or error) from the initial method call |
| */ |
| |
| /* Note: if this test is run in OOM mode, it will block when the bus |
| * doesn't send a reply due to OOM. |
| */ |
| block_connection_until_message_from_bus (context, connection, "reply from echo message after auto-activation"); |
| |
| message = pop_message_waiting_for_memory (connection); |
| if (message == NULL) |
| { |
| _dbus_warn ("Failed to pop message! Should have been reply from echo message\n"); |
| goto out; |
| } |
| |
| if (dbus_message_get_reply_serial (message) != serial) |
| { |
| _dbus_warn ("Wrong reply serial\n"); |
| goto out; |
| } |
| |
| dbus_message_unref (message); |
| message = NULL; |
| |
| if (!check_existent_ping (context, connection)) |
| goto out; |
| |
| if (!check_existent_get_machine_id (context, connection)) |
| goto out; |
| |
| if (!check_existent_hello_from_self (context, connection)) |
| goto out; |
| |
| if (!check_send_exit_to_service (context, connection, |
| EXISTENT_SERVICE_NAME, |
| base_service)) |
| goto out; |
| |
| retval = TRUE; |
| |
| out: |
| if (message) |
| dbus_message_unref (message); |
| |
| if (base_service_message) |
| dbus_message_unref (base_service_message); |
| |
| return retval; |
| } |
| |
| #define SERVICE_FILE_MISSING_NAME "org.freedesktop.DBus.TestSuiteEchoServiceDotServiceFileDoesNotExist" |
| |
| /* returns TRUE if the correct thing happens, |
| * but the correct thing may include OOM errors. |
| */ |
| static dbus_bool_t |
| check_launch_service_file_missing (BusContext *context, |
| DBusConnection *connection) |
| { |
| DBusMessage *message; |
| dbus_uint32_t serial; |
| dbus_bool_t retval; |
| |
| message = dbus_message_new_method_call (SERVICE_FILE_MISSING_NAME, |
| "/org/freedesktop/TestSuite", |
| "org.freedesktop.TestSuite", |
| "Echo"); |
| |
| if (message == NULL) |
| return TRUE; |
| |
| if (!dbus_connection_send (connection, message, &serial)) |
| { |
| dbus_message_unref (message); |
| return TRUE; |
| } |
| |
| dbus_message_unref (message); |
| message = NULL; |
| |
| bus_test_run_everything (context); |
| block_connection_until_message_from_bus (context, connection, "reply to service file missing should fail to auto-start"); |
| bus_test_run_everything (context); |
| |
| if (!dbus_connection_get_is_connected (connection)) |
| { |
| _dbus_verbose ("connection was disconnected\n"); |
| return TRUE; |
| } |
| |
| retval = FALSE; |
| |
| message = pop_message_waiting_for_memory (connection); |
| if (message == NULL) |
| { |
| _dbus_warn ("Did not receive a reply to %s %d on %p\n", |
| "Echo message (auto activation)", serial, connection); |
| goto out; |
| } |
| |
| verbose_message_received (connection, message); |
| |
| if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR) |
| { |
| if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS)) |
| { |
| _dbus_warn ("Message has wrong sender %s\n", |
| dbus_message_get_sender (message) ? |
| dbus_message_get_sender (message) : "(none)"); |
| goto out; |
| } |
| |
| if (dbus_message_is_error (message, |
| DBUS_ERROR_NO_MEMORY)) |
| { |
| ; /* good, this is a valid response */ |
| } |
| else if (dbus_message_is_error (message, |
| DBUS_ERROR_SERVICE_UNKNOWN)) |
| { |
| _dbus_verbose("got service unknown\n"); |
| ; /* good, this is expected (only valid when using launch helper) */ |
| } |
| else |
| { |
| warn_unexpected (connection, message, "not this error"); |
| |
| goto out; |
| } |
| } |
| else |
| { |
| _dbus_warn ("Did not expect to successfully auto-start missing service\n"); |
| goto out; |
| } |
| |
| retval = TRUE; |
| |
| out: |
| if (message) |
| dbus_message_unref (message); |
| |
| return retval; |
| } |
| |
| #define SERVICE_USER_MISSING_NAME "org.freedesktop.DBus.TestSuiteNoUser" |
| |
| /* returns TRUE if the correct thing happens, |
| * but the correct thing may include OOM errors. |
| */ |
| static dbus_bool_t |
| check_launch_service_user_missing (BusContext *context, |
| DBusConnection *connection) |
| { |
| DBusMessage *message; |
| dbus_uint32_t serial; |
| dbus_bool_t retval; |
| |
| message = dbus_message_new_method_call (SERVICE_USER_MISSING_NAME, |
| "/org/freedesktop/TestSuite", |
| "org.freedesktop.TestSuite", |
| "Echo"); |
| |
| if (message == NULL) |
| return TRUE; |
| |
| if (!dbus_connection_send (connection, message, &serial)) |
| { |
| dbus_message_unref (message); |
| return TRUE; |
| } |
| |
| dbus_message_unref (message); |
| message = NULL; |
| |
| bus_test_run_everything (context); |
| block_connection_until_message_from_bus (context, connection, |
| "reply to service which should fail to auto-start (missing User)"); |
| bus_test_run_everything (context); |
| |
| if (!dbus_connection_get_is_connected (connection)) |
| { |
| _dbus_warn ("connection was disconnected\n"); |
| return TRUE; |
| } |
| |
| retval = FALSE; |
| |
| message = pop_message_waiting_for_memory (connection); |
| if (message == NULL) |
| { |
| _dbus_warn ("Did not receive a reply to %s %d on %p\n", |
| "Echo message (auto activation)", serial, connection); |
| goto out; |
| } |