2004-03-16 Richard Hult <richard@imendio.com>
authorRichard Hult <richard@imendio.com>
Tue, 16 Mar 2004 18:00:35 +0000 (18:00 +0000)
committerRichard Hult <richard@imendio.com>
Tue, 16 Mar 2004 18:00:35 +0000 (18:00 +0000)
* 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.

ChangeLog
bus/activation.c
bus/activation.h
bus/dispatch.c
bus/driver.c
bus/services.c
dbus/dbus-message.c
dbus/dbus-message.h
dbus/dbus-protocol.h
doc/dbus-specification.xml

index b74774a..809664e 100644 (file)
--- 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):
index e53fa22..e286ba9 100644 (file)
@@ -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;
index 76a1b26..fbac5d1 100644 (file)
 #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 */
index b4d782e..b7191d7 100644 (file)
@@ -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);
index 1679a87..3ffae2e 100644 (file)
@@ -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);
index ae7b783..c5a6ded 100644 (file)
@@ -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;
index ffaef43..696b250 100644 (file)
@@ -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.
index 3655d2e..d9ddc94 100644 (file)
@@ -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);
 
index f042f02..54d70e4 100644 (file)
@@ -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
index 5f62cfd..94dc740 100644 (file)
                 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>
           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>