mirror of
https://gitlab.freedesktop.org/dbus/dbus.git
synced 2026-05-04 22:18:11 +02:00
2004-03-16 Richard Hult <richard@imendio.com>
* bus/activation.c: (bus_activation_service_created), (bus_activation_send_pending_auto_activation_messages), (bus_activation_activate_service): * bus/activation.h: * bus/dispatch.c: (bus_dispatch), (check_nonexistent_service_auto_activation), (check_service_auto_activated), (check_segfault_service_auto_activation), (check_existent_service_auto_activation), (bus_dispatch_test): * bus/driver.c: (bus_driver_handle_activate_service): * bus/services.c: (bus_registry_acquire_service): * dbus/dbus-message.c: (dbus_message_set_auto_activation), (dbus_message_get_auto_activation): * dbus/dbus-message.h: * dbus/dbus-protocol.h: Implement auto-activation.
This commit is contained in:
parent
24ffe79c80
commit
93f433a17a
10 changed files with 738 additions and 32 deletions
20
ChangeLog
20
ChangeLog
|
|
@ -1,3 +1,23 @@
|
|||
2004-03-16 Richard Hult <richard@imendio.com>
|
||||
|
||||
* bus/activation.c: (bus_activation_service_created),
|
||||
(bus_activation_send_pending_auto_activation_messages),
|
||||
(bus_activation_activate_service):
|
||||
* bus/activation.h:
|
||||
* bus/dispatch.c: (bus_dispatch),
|
||||
(check_nonexistent_service_auto_activation),
|
||||
(check_service_auto_activated),
|
||||
(check_segfault_service_auto_activation),
|
||||
(check_existent_service_auto_activation), (bus_dispatch_test):
|
||||
* bus/driver.c: (bus_driver_handle_activate_service):
|
||||
* bus/services.c: (bus_registry_acquire_service):
|
||||
* dbus/dbus-message.c: (dbus_message_set_auto_activation),
|
||||
(dbus_message_get_auto_activation):
|
||||
* dbus/dbus-message.h:
|
||||
* dbus/dbus-protocol.h: Implement auto-activation.
|
||||
|
||||
* doc/dbus-specification.xml: Add auto-activation to the spec.
|
||||
|
||||
2004-03-12 Olivier Andrieu <oliv__a@users.sourceforge.net>
|
||||
|
||||
* dbus/dbus-marshal.c (_dbus_marshal_get_arg_end_pos):
|
||||
|
|
|
|||
101
bus/activation.c
101
bus/activation.c
|
|
@ -76,6 +76,8 @@ struct BusPendingActivationEntry
|
|||
{
|
||||
DBusMessage *activation_message;
|
||||
DBusConnection *connection;
|
||||
|
||||
dbus_bool_t auto_activation;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
|
|
@ -904,30 +906,90 @@ bus_activation_service_created (BusActivation *activation,
|
|||
|
||||
if (dbus_connection_get_is_connected (entry->connection))
|
||||
{
|
||||
message = dbus_message_new_method_return (entry->activation_message);
|
||||
if (!message)
|
||||
/* Only send activation replies to regular activation requests. */
|
||||
if (!entry->auto_activation)
|
||||
{
|
||||
BUS_SET_OOM (error);
|
||||
goto error;
|
||||
message = dbus_message_new_method_return (entry->activation_message);
|
||||
if (!message)
|
||||
{
|
||||
BUS_SET_OOM (error);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!dbus_message_append_args (message,
|
||||
DBUS_TYPE_UINT32, DBUS_ACTIVATION_REPLY_ACTIVATED,
|
||||
DBUS_TYPE_INVALID))
|
||||
{
|
||||
dbus_message_unref (message);
|
||||
BUS_SET_OOM (error);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!bus_transaction_send_from_driver (transaction, entry->connection, message))
|
||||
{
|
||||
dbus_message_unref (message);
|
||||
BUS_SET_OOM (error);
|
||||
goto error;
|
||||
}
|
||||
|
||||
dbus_message_unref (message);
|
||||
}
|
||||
}
|
||||
|
||||
link = next;
|
||||
}
|
||||
|
||||
if (!dbus_message_append_args (message,
|
||||
DBUS_TYPE_UINT32, DBUS_ACTIVATION_REPLY_ACTIVATED,
|
||||
DBUS_TYPE_INVALID))
|
||||
return TRUE;
|
||||
|
||||
error:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
dbus_bool_t
|
||||
bus_activation_send_pending_auto_activation_messages (BusActivation *activation,
|
||||
BusService *service,
|
||||
BusTransaction *transaction,
|
||||
DBusError *error)
|
||||
{
|
||||
BusPendingActivation *pending_activation;
|
||||
DBusList *link;
|
||||
|
||||
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
|
||||
|
||||
/* Check if it's a pending activation */
|
||||
pending_activation = _dbus_hash_table_lookup_string (activation->pending_activations,
|
||||
bus_service_get_name (service));
|
||||
|
||||
if (!pending_activation)
|
||||
return TRUE;
|
||||
|
||||
link = _dbus_list_get_first_link (&pending_activation->entries);
|
||||
while (link != NULL)
|
||||
{
|
||||
BusPendingActivationEntry *entry = link->data;
|
||||
DBusList *next = _dbus_list_get_next_link (&pending_activation->entries, link);
|
||||
|
||||
if (entry->auto_activation && dbus_connection_get_is_connected (entry->connection))
|
||||
{
|
||||
DBusConnection *addressed_recipient;
|
||||
|
||||
addressed_recipient = bus_service_get_primary_owner (service);
|
||||
|
||||
/* Check the security policy, which has the side-effect of adding an
|
||||
* expected pending reply.
|
||||
*/
|
||||
if (!bus_context_check_security_policy (activation->context, transaction,
|
||||
entry->connection,
|
||||
addressed_recipient,
|
||||
addressed_recipient,
|
||||
entry->activation_message, error))
|
||||
goto error;
|
||||
|
||||
if (!bus_transaction_send (transaction, addressed_recipient, entry->activation_message))
|
||||
{
|
||||
dbus_message_unref (message);
|
||||
BUS_SET_OOM (error);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!bus_transaction_send_from_driver (transaction, entry->connection, message))
|
||||
{
|
||||
dbus_message_unref (message);
|
||||
BUS_SET_OOM (error);
|
||||
goto error;
|
||||
}
|
||||
|
||||
dbus_message_unref (message);
|
||||
}
|
||||
|
||||
link = next;
|
||||
|
|
@ -940,7 +1002,7 @@ bus_activation_service_created (BusActivation *activation,
|
|||
goto error;
|
||||
}
|
||||
|
||||
_dbus_hash_table_remove_string (activation->pending_activations, service_name);
|
||||
_dbus_hash_table_remove_string (activation->pending_activations, bus_service_get_name (service));
|
||||
|
||||
return TRUE;
|
||||
|
||||
|
|
@ -1225,6 +1287,7 @@ dbus_bool_t
|
|||
bus_activation_activate_service (BusActivation *activation,
|
||||
DBusConnection *connection,
|
||||
BusTransaction *transaction,
|
||||
dbus_bool_t auto_activation,
|
||||
DBusMessage *activation_message,
|
||||
const char *service_name,
|
||||
DBusError *error)
|
||||
|
|
@ -1300,6 +1363,8 @@ bus_activation_activate_service (BusActivation *activation,
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
pending_activation_entry->auto_activation = auto_activation;
|
||||
|
||||
pending_activation_entry->activation_message = activation_message;
|
||||
dbus_message_ref (activation_message);
|
||||
pending_activation_entry->connection = connection;
|
||||
|
|
|
|||
|
|
@ -29,21 +29,28 @@
|
|||
#include "bus.h"
|
||||
|
||||
BusActivation* bus_activation_new (BusContext *context,
|
||||
const DBusString *address,
|
||||
DBusList **directories,
|
||||
DBusError *error);
|
||||
const DBusString *address,
|
||||
DBusList **directories,
|
||||
DBusError *error);
|
||||
BusActivation* bus_activation_ref (BusActivation *activation);
|
||||
void bus_activation_unref (BusActivation *activation);
|
||||
dbus_bool_t bus_activation_activate_service (BusActivation *activation,
|
||||
DBusConnection *connection,
|
||||
BusTransaction *transaction,
|
||||
DBusMessage *activation_message,
|
||||
const char *service_name,
|
||||
DBusError *error);
|
||||
DBusConnection *connection,
|
||||
BusTransaction *transaction,
|
||||
dbus_bool_t auto_activation,
|
||||
DBusMessage *activation_message,
|
||||
const char *service_name,
|
||||
DBusError *error);
|
||||
dbus_bool_t bus_activation_service_created (BusActivation *activation,
|
||||
const char *service_name,
|
||||
BusTransaction *transaction,
|
||||
DBusError *error);
|
||||
const char *service_name,
|
||||
BusTransaction *transaction,
|
||||
DBusError *error);
|
||||
|
||||
dbus_bool_t bus_activation_send_pending_auto_activation_messages (BusActivation *activation,
|
||||
BusService *service,
|
||||
BusTransaction *transaction,
|
||||
DBusError *error);
|
||||
|
||||
|
||||
|
||||
#endif /* BUS_ACTIVATION_H */
|
||||
|
|
|
|||
564
bus/dispatch.c
564
bus/dispatch.c
|
|
@ -3,6 +3,7 @@
|
|||
*
|
||||
* Copyright (C) 2003 CodeFactory AB
|
||||
* Copyright (C) 2003 Red Hat, Inc.
|
||||
* Copyright (C) 2004 Imendio HB
|
||||
*
|
||||
* Licensed under the Academic Free License version 2.0
|
||||
*
|
||||
|
|
@ -26,6 +27,7 @@
|
|||
#include "connection.h"
|
||||
#include "driver.h"
|
||||
#include "services.h"
|
||||
#include "activation.h"
|
||||
#include "utils.h"
|
||||
#include "bus.h"
|
||||
#include "signals.h"
|
||||
|
|
@ -257,7 +259,27 @@ bus_dispatch (DBusConnection *connection,
|
|||
_dbus_string_init_const (&service_string, service_name);
|
||||
service = bus_registry_lookup (registry, &service_string);
|
||||
|
||||
if (service == NULL)
|
||||
if (service == NULL && dbus_message_get_auto_activation (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\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
goto out;
|
||||
}
|
||||
else if (service == NULL)
|
||||
{
|
||||
dbus_set_error (&error,
|
||||
DBUS_ERROR_SERVICE_DOES_NOT_EXIST,
|
||||
|
|
@ -378,6 +400,8 @@ bus_dispatch_remove_connection (DBusConnection *connection)
|
|||
|
||||
#ifdef DBUS_BUILD_TESTS
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
typedef dbus_bool_t (* Check1Func) (BusContext *context);
|
||||
typedef dbus_bool_t (* Check2Func) (BusContext *context,
|
||||
DBusConnection *connection);
|
||||
|
|
@ -1170,6 +1194,104 @@ check_nonexistent_service_activation (BusContext *context,
|
|||
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_activation (BusContext *context,
|
||||
DBusConnection *connection)
|
||||
{
|
||||
DBusMessage *message;
|
||||
dbus_uint32_t serial;
|
||||
dbus_bool_t retval;
|
||||
DBusError error;
|
||||
|
||||
dbus_error_init (&error);
|
||||
|
||||
message = dbus_message_new_method_call (NONEXISTENT_SERVICE_NAME,
|
||||
"/org/freedesktop/TestSuite",
|
||||
"org.freedesktop.TestSuite",
|
||||
"Echo");
|
||||
|
||||
if (message == NULL)
|
||||
return TRUE;
|
||||
|
||||
dbus_message_set_auto_activation (message, 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);
|
||||
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_ORG_FREEDESKTOP_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_ACTIVATE_SERVICE_NOT_FOUND))
|
||||
{
|
||||
; /* 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,
|
||||
|
|
@ -1397,6 +1519,94 @@ check_service_activated (BusContext *context,
|
|||
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_ORG_FREEDESKTOP_DBUS,
|
||||
"ServiceCreated"))
|
||||
{
|
||||
char *service_name;
|
||||
CheckServiceCreatedData scd;
|
||||
|
||||
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",
|
||||
"ServiceCreated",
|
||||
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);
|
||||
dbus_free (service_name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
scd.skip_connection = connection;
|
||||
scd.failed = FALSE;
|
||||
scd.expected_service_name = service_name;
|
||||
bus_test_clients_foreach (check_service_created_foreach,
|
||||
&scd);
|
||||
|
||||
dbus_free (service_name);
|
||||
|
||||
if (scd.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;
|
||||
}
|
||||
else
|
||||
{
|
||||
warn_unexpected (connection, message, "ServiceCreated 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,
|
||||
|
|
@ -1974,6 +2184,340 @@ check_segfault_service_activation (BusContext *context,
|
|||
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_activation (BusContext *context,
|
||||
DBusConnection *connection)
|
||||
{
|
||||
DBusMessage *message;
|
||||
dbus_uint32_t serial;
|
||||
dbus_bool_t retval;
|
||||
DBusError error;
|
||||
|
||||
dbus_error_init (&error);
|
||||
|
||||
dbus_error_init (&error);
|
||||
|
||||
message = dbus_message_new_method_call ("org.freedesktop.DBus.TestSuiteSegfaultService",
|
||||
"/org/freedesktop/TestSuite",
|
||||
"org.freedesktop.TestSuite",
|
||||
"Echo");
|
||||
|
||||
if (message == NULL)
|
||||
return TRUE;
|
||||
|
||||
dbus_message_set_auto_activation (message, 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);
|
||||
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_ORG_FREEDESKTOP_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;
|
||||
}
|
||||
|
||||
#define TEST_ECHO_MESSAGE "Test echo message"
|
||||
|
||||
/* returns TRUE if the correct thing happens,
|
||||
* but the correct thing may include OOM errors.
|
||||
*/
|
||||
static dbus_bool_t
|
||||
check_existent_service_auto_activation (BusContext *context,
|
||||
DBusConnection *connection)
|
||||
{
|
||||
DBusMessage *message;
|
||||
dbus_uint32_t serial;
|
||||
dbus_bool_t retval;
|
||||
DBusError error;
|
||||
char *base_service;
|
||||
|
||||
base_service = NULL;
|
||||
|
||||
dbus_error_init (&error);
|
||||
|
||||
message = dbus_message_new_method_call (EXISTENT_SERVICE_NAME,
|
||||
"/org/freedesktop/TestSuite",
|
||||
"org.freedesktop.TestSuite",
|
||||
"Echo");
|
||||
|
||||
if (message == NULL)
|
||||
return TRUE;
|
||||
|
||||
dbus_message_set_auto_activation (message, TRUE);
|
||||
|
||||
if (!dbus_message_append_args (message,
|
||||
DBUS_TYPE_STRING, TEST_ECHO_MESSAGE,
|
||||
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);
|
||||
bus_test_run_everything (context);
|
||||
|
||||
if (!dbus_connection_get_is_connected (connection))
|
||||
{
|
||||
_dbus_verbose ("connection was disconnected\n");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
retval = FALSE;
|
||||
|
||||
/* Should get ServiceCreated for the base service, or an error. */
|
||||
message = pop_message_waiting_for_memory (connection);
|
||||
if (message == NULL)
|
||||
{
|
||||
_dbus_warn ("Did not receive any messages after auto activation %d on %p\n",
|
||||
serial, connection);
|
||||
goto out;
|
||||
}
|
||||
|
||||
verbose_message_received (connection, message);
|
||||
_dbus_verbose (" (after sending %s)\n", "ActivateService");
|
||||
|
||||
if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR)
|
||||
{
|
||||
if (!dbus_message_has_sender (message, DBUS_SERVICE_ORG_FREEDESKTOP_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) ||
|
||||
dbus_message_is_error (message, DBUS_ERROR_SPAWN_CHILD_EXITED) ||
|
||||
dbus_message_is_error (message, DBUS_ERROR_TIMED_OUT))
|
||||
{
|
||||
; /* good, those are expected */
|
||||
retval = TRUE;
|
||||
goto out;
|
||||
}
|
||||
else
|
||||
{
|
||||
_dbus_warn ("Did not expect error %s\n",
|
||||
dbus_message_get_error_name (message));
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dbus_bool_t got_service_deleted;
|
||||
dbus_bool_t got_error;
|
||||
|
||||
if (!check_base_service_activated (context, connection,
|
||||
message, &base_service))
|
||||
goto out;
|
||||
|
||||
dbus_message_unref (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);
|
||||
|
||||
/* Should get ServiceCreated for the activated service name,
|
||||
* ServiceDeleted on the base service name, or an error.
|
||||
*/
|
||||
message = dbus_connection_borrow_message (connection);
|
||||
if (message == NULL)
|
||||
{
|
||||
_dbus_warn ("Did not receive any messages after base service creation notification\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
got_service_deleted = dbus_message_is_signal (message,
|
||||
DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,
|
||||
"ServiceDeleted");
|
||||
got_error = dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR;
|
||||
|
||||
dbus_connection_return_message (connection, message);
|
||||
message = NULL;
|
||||
|
||||
if (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.
|
||||
*/
|
||||
got_service_deleted = TRUE;
|
||||
}
|
||||
|
||||
if (got_service_deleted)
|
||||
{
|
||||
/* The service started up and got a base address, but then
|
||||
* failed to register under EXISTENT_SERVICE_NAME
|
||||
*/
|
||||
CheckServiceDeletedData csdd;
|
||||
|
||||
csdd.expected_service_name = base_service;
|
||||
csdd.failed = FALSE;
|
||||
bus_test_clients_foreach (check_service_deleted_foreach,
|
||||
&csdd);
|
||||
|
||||
if (csdd.failed)
|
||||
goto out;
|
||||
|
||||
/* Now we should get an error about the service exiting
|
||||
* if we didn't get it before.
|
||||
*/
|
||||
if (!got_error)
|
||||
{
|
||||
block_connection_until_message_from_bus (context, connection);
|
||||
|
||||
/* and process everything again */
|
||||
bus_test_run_everything (context);
|
||||
|
||||
if (!check_got_error (context, connection,
|
||||
DBUS_ERROR_SPAWN_CHILD_EXITED,
|
||||
NULL))
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
message = pop_message_waiting_for_memory (connection);
|
||||
if (message == NULL)
|
||||
{
|
||||
_dbus_warn ("Failed to pop message we just put back! should have been a ServiceCreated\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Check that ServiceCreated was correctly received */
|
||||
if (!check_service_auto_activated (context, connection, EXISTENT_SERVICE_NAME,
|
||||
base_service, message))
|
||||
goto out;
|
||||
|
||||
dbus_message_unref (message);
|
||||
message = NULL;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
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_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)
|
||||
dbus_free (base_service);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Check1Func func;
|
||||
|
|
@ -2126,6 +2670,24 @@ bus_dispatch_test (const DBusString *test_data_dir)
|
|||
check2_try_iterations (context, foo, "existent_service_activation",
|
||||
check_existent_service_activation);
|
||||
|
||||
check2_try_iterations (context, foo, "nonexistent_service_auto_activation",
|
||||
check_nonexistent_service_auto_activation);
|
||||
|
||||
check2_try_iterations (context, foo, "segfault_service_auto_activation",
|
||||
check_segfault_service_auto_activation);
|
||||
|
||||
#if 0
|
||||
/* Note: need to resolve some issues with the testing code in order to run
|
||||
* this in oom (handle that we sometimes don't get replies back from the bus
|
||||
* when oom happens, without blocking the test).
|
||||
*/
|
||||
check2_try_iterations (context, foo, "existent_service_auto_activation",
|
||||
check_existent_service_auto_activation);
|
||||
#endif
|
||||
|
||||
if (!check_existent_service_auto_activation (context, foo))
|
||||
_dbus_assert_not_reached ("existent service auto activation failed");
|
||||
|
||||
_dbus_verbose ("Disconnecting foo, bar, and baz\n");
|
||||
|
||||
kill_client_connection_unchecked (foo);
|
||||
|
|
|
|||
|
|
@ -587,7 +587,7 @@ bus_driver_handle_activate_service (DBusConnection *connection,
|
|||
|
||||
retval = FALSE;
|
||||
|
||||
if (!bus_activation_activate_service (activation, connection, transaction,
|
||||
if (!bus_activation_activate_service (activation, connection, transaction, FALSE,
|
||||
message, name, error))
|
||||
{
|
||||
_DBUS_ASSERT_ERROR_IS_SET (error);
|
||||
|
|
|
|||
|
|
@ -262,6 +262,7 @@ bus_registry_acquire_service (BusRegistry *registry,
|
|||
DBusConnection *current_owner;
|
||||
BusClientPolicy *policy;
|
||||
BusService *service;
|
||||
BusActivation *activation;
|
||||
|
||||
retval = FALSE;
|
||||
|
||||
|
|
@ -376,7 +377,11 @@ bus_registry_acquire_service (BusRegistry *registry,
|
|||
*result = DBUS_SERVICE_REPLY_PRIMARY_OWNER;
|
||||
}
|
||||
|
||||
retval = TRUE;
|
||||
activation = bus_context_get_activation (registry->context);
|
||||
retval = bus_activation_send_pending_auto_activation_messages (activation,
|
||||
service,
|
||||
transaction,
|
||||
error);
|
||||
|
||||
out:
|
||||
return retval;
|
||||
|
|
|
|||
|
|
@ -4387,6 +4387,35 @@ dbus_message_get_no_reply (DBusMessage *message)
|
|||
return (*header & DBUS_HEADER_FLAG_NO_REPLY_EXPECTED) != 0;
|
||||
}
|
||||
|
||||
void
|
||||
dbus_message_set_auto_activation (DBusMessage *message,
|
||||
dbus_bool_t auto_activation)
|
||||
{
|
||||
char *header;
|
||||
|
||||
_dbus_return_if_fail (message != NULL);
|
||||
_dbus_return_if_fail (!message->locked);
|
||||
|
||||
header = _dbus_string_get_data_len (&message->header, FLAGS_OFFSET, 1);
|
||||
|
||||
if (auto_activation)
|
||||
*header |= DBUS_HEADER_FLAG_AUTO_ACTIVATION;
|
||||
else
|
||||
*header &= ~DBUS_HEADER_FLAG_AUTO_ACTIVATION;
|
||||
}
|
||||
|
||||
dbus_bool_t
|
||||
dbus_message_get_auto_activation (DBusMessage *message)
|
||||
{
|
||||
const char *header;
|
||||
|
||||
_dbus_return_val_if_fail (message != NULL, FALSE);
|
||||
|
||||
header = _dbus_string_get_const_data_len (&message->header, FLAGS_OFFSET, 1);
|
||||
|
||||
return (*header & DBUS_HEADER_FLAG_AUTO_ACTIVATION) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the service which originated this message,
|
||||
* or #NULL if unknown or inapplicable.
|
||||
|
|
|
|||
|
|
@ -119,6 +119,10 @@ dbus_bool_t dbus_message_set_reply_serial (DBusMessage *message,
|
|||
dbus_uint32_t reply_serial);
|
||||
dbus_uint32_t dbus_message_get_reply_serial (DBusMessage *message);
|
||||
|
||||
void dbus_message_set_auto_activation (DBusMessage *message,
|
||||
dbus_bool_t auto_activation);
|
||||
dbus_bool_t dbus_message_get_auto_activation (DBusMessage *message);
|
||||
|
||||
dbus_bool_t dbus_message_get_path_decomposed (DBusMessage *message,
|
||||
char ***path);
|
||||
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@ extern "C" {
|
|||
|
||||
/* Header flags */
|
||||
#define DBUS_HEADER_FLAG_NO_REPLY_EXPECTED 0x1
|
||||
#define DBUS_HEADER_FLAG_AUTO_ACTIVATION 0x2
|
||||
|
||||
/* Header fields */
|
||||
#define DBUS_HEADER_FIELD_INVALID 0
|
||||
|
|
|
|||
|
|
@ -249,6 +249,12 @@
|
|||
optimization. However, it is compliant with this specification
|
||||
to return the reply despite this flag.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>AUTO_ACTIVATION</entry>
|
||||
<entry>0x2</entry>
|
||||
<entry>This message automatically activates the
|
||||
addressed service before the message is delivered.</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</informaltable>
|
||||
|
|
@ -674,6 +680,13 @@
|
|||
However, it is also acceptable to ignore the NO_REPLY_EXPECTED
|
||||
flag and reply anyway.
|
||||
</para>
|
||||
<para>
|
||||
If a message has the flag AUTO_ACTIVATION, then the addressed
|
||||
service will be activated before the message is delivered, if
|
||||
not already active. The message will be held until the service
|
||||
is successfully activated or has failed to activate; in case
|
||||
of failure, an activation error will be returned.
|
||||
</para>
|
||||
<sect4 id="message-protocol-types-method-apis">
|
||||
<title>Mapping method calls to native APIs</title>
|
||||
<para>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue