summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Hult <richard@imendio.com>2004-03-16 18:00:35 +0000
committerRichard Hult <richard@imendio.com>2004-03-16 18:00:35 +0000
commit93f433a17a0aabff91a0384bf9c4f99c9cf30ae1 (patch)
treebe2ffbc0160abfb63808d994d076faa67e4ff81a
parent24ffe79c80d376b058c2d154b2b5f0ef8fee1c36 (diff)
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.
-rw-r--r--ChangeLog20
-rw-r--r--bus/activation.c101
-rw-r--r--bus/activation.h29
-rw-r--r--bus/dispatch.c564
-rw-r--r--bus/driver.c2
-rw-r--r--bus/services.c7
-rw-r--r--dbus/dbus-message.c29
-rw-r--r--dbus/dbus-message.h4
-rw-r--r--dbus/dbus-protocol.h1
-rw-r--r--doc/dbus-specification.xml13
10 files changed, 738 insertions, 32 deletions
diff --git a/ChangeLog b/ChangeLog
index b74774ad..809664e7 100644
--- a/ChangeLog
+++ b/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):
diff --git a/bus/activation.c b/bus/activation.c
index e53fa229..e286ba9d 100644
--- a/bus/activation.c
+++ b/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)
- {
- BUS_SET_OOM (error);
- goto error;
- }
-
- if (!dbus_message_append_args (message,
- DBUS_TYPE_UINT32, DBUS_ACTIVATION_REPLY_ACTIVATED,
- DBUS_TYPE_INVALID))
+ /* Only send activation replies to regular activation requests. */
+ if (!entry->auto_activation)
{
+ 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);
- BUS_SET_OOM (error);
- goto error;
}
-
- if (!bus_transaction_send_from_driver (transaction, entry->connection, message))
+ }
+
+ link = next;
+ }
+
+ 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;
}
-
- 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;
diff --git a/bus/activation.h b/bus/activation.h
index 76a1b265..fbac5d1f 100644
--- a/bus/activation.h
+++ b/bus/activation.h
@@ -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 */
diff --git a/bus/dispatch.c b/bus/dispatch.c
index b4d782ee..b7191d7e 100644
--- a/bus/dispatch.c
+++ b/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,
@@ -1398,6 +1520,94 @@ check_service_activated (BusContext *context,
}
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,
const char *activated_name,
@@ -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);
diff --git a/bus/driver.c b/bus/driver.c
index 1679a876..3ffae2e0 100644
--- a/bus/driver.c
+++ b/bus/driver.c
@@ -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);
diff --git a/bus/services.c b/bus/services.c
index ae7b7838..c5a6ded8 100644
--- a/bus/services.c
+++ b/bus/services.c
@@ -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;
diff --git a/dbus/dbus-message.c b/dbus/dbus-message.c
index ffaef43c..696b2503 100644
--- a/dbus/dbus-message.c
+++ b/dbus/dbus-message.c
@@ -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.
diff --git a/dbus/dbus-message.h b/dbus/dbus-message.h
index 3655d2e4..d9ddc94c 100644
--- a/dbus/dbus-message.h
+++ b/dbus/dbus-message.h
@@ -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);
diff --git a/dbus/dbus-protocol.h b/dbus/dbus-protocol.h
index f042f026..54d70e4e 100644
--- a/dbus/dbus-protocol.h
+++ b/dbus/dbus-protocol.h
@@ -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
diff --git a/doc/dbus-specification.xml b/doc/dbus-specification.xml
index 5f62cfdd..94dc740c 100644
--- a/doc/dbus-specification.xml
+++ b/doc/dbus-specification.xml
@@ -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>