PATCH: Implicit activation

Richard Hult richard@imendio.com
Fri Mar 12 00:39:38 PST 2004


--=-roK24e5WA8RjmEsD2WNf
Content-Type: text/plain
Content-Transfer-Encoding: 7bit

Hi!

This patch implements implicit activation as discussed here earlier. An
implicit activation is done by setting a flag on the message before it's
sent off.

The exact spots where to do the adding to/sending of pending messages
could be argued, so some refactoring might be needed. I also need to go
through the patch and make sure that we cover all the cases of error
conditions from the design. Here comes a first version.

/Richard

-- 
Richard Hult                    richard@imendio.com
Imendio                         http://www.imendio.com

--=-roK24e5WA8RjmEsD2WNf
Content-Disposition: attachment; filename=implact.diff
Content-Type: text/x-patch; name=implact.diff; charset=ISO-8859-15
Content-Transfer-Encoding: 7bit

Index: bus/activation.c
===================================================================
RCS file: /cvs/dbus/dbus/bus/activation.c,v
retrieving revision 1.31
diff -u -b -B -p -r1.31 activation.c
--- a/bus/activation.c	2 Dec 2003 10:44:21 -0000	1.31
+++ b/bus/activation.c	12 Mar 2004 00:10:28 -0000
@@ -63,6 +63,8 @@ struct BusPendingActivationEntry
 {
   DBusMessage *activation_message;
   DBusConnection *connection;
+
+  dbus_bool_t implicit_activation;
 };
 
 typedef struct
@@ -603,6 +605,9 @@ bus_activation_service_created (BusActiv
       
       if (dbus_connection_get_is_connected (entry->connection))
 	{
+	  /* Only send activation replies to regular activation requests. */
+	  if (!entry->implicit_activation)
+	    {
 	  message = dbus_message_new_method_return (entry->activation_message);
 	  if (!message)
 	    {
@@ -628,6 +633,63 @@ bus_activation_service_created (BusActiv
           
           dbus_message_unref (message);
 	}
+	}
+      
+      link = next;
+    }
+
+  return TRUE;
+
+ error:
+  return FALSE;
+}
+
+dbus_bool_t
+bus_activation_send_pending_implicit_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->implicit_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))
+	    {
+	      BUS_SET_OOM (error);
+	      goto error;
+	    }
+	}
 
       link = next;
     }
@@ -639,7 +701,7 @@ bus_activation_service_created (BusActiv
       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;
 
@@ -844,6 +906,7 @@ dbus_bool_t
 bus_activation_activate_service (BusActivation  *activation,
 				 DBusConnection *connection,
                                  BusTransaction *transaction,
+				 dbus_bool_t     implicit_activation,
 				 DBusMessage    *activation_message,
                                  const char     *service_name,
 				 DBusError      *error)
@@ -921,6 +984,8 @@ bus_activation_activate_service (BusActi
       return FALSE;
     }
 
+  pending_activation_entry->implicit_activation = implicit_activation;
+
   pending_activation_entry->activation_message = activation_message;
   dbus_message_ref (activation_message);
   pending_activation_entry->connection = connection;
Index: bus/activation.h
===================================================================
RCS file: /cvs/dbus/dbus/bus/activation.h,v
retrieving revision 1.11
diff -u -b -B -p -r1.11 activation.h
--- a/bus/activation.h	2 Dec 2003 10:44:21 -0000	1.11
+++ b/bus/activation.h	12 Mar 2004 00:10:28 -0000
@@ -37,6 +37,7 @@ void           bus_activation_unref     
 dbus_bool_t    bus_activation_activate_service (BusActivation     *activation,
                                                 DBusConnection    *connection,
                                                 BusTransaction    *transaction,
+						dbus_bool_t        implicit_activation,
                                                 DBusMessage       *activation_message,
                                                 const char        *service_name,
                                                 DBusError         *error);
@@ -45,5 +46,11 @@ dbus_bool_t    bus_activation_service_cr
                                                 BusTransaction    *transaction,
                                                 DBusError         *error);
 
+dbus_bool_t    bus_activation_send_pending_implicit_activation_messages (BusActivation     *activation,
+									 BusService        *service,
+									 BusTransaction    *transaction,
+									 DBusError         *error);
+
+
 
 #endif /* BUS_ACTIVATION_H */
Index: bus/bus.c
===================================================================
RCS file: /cvs/dbus/dbus/bus/bus.c,v
retrieving revision 1.48
diff -u -b -B -p -r1.48 bus.c
Index: bus/connection.c
===================================================================
RCS file: /cvs/dbus/dbus/bus/connection.c,v
retrieving revision 1.53
diff -u -b -B -p -r1.53 connection.c
Index: bus/dispatch.c
===================================================================
RCS file: /cvs/dbus/dbus/bus/dispatch.c,v
retrieving revision 1.56
diff -u -b -B -p -r1.56 dispatch.c
--- a/bus/dispatch.c	2 Dec 2003 10:44:21 -0000	1.56
+++ b/bus/dispatch.c	12 Mar 2004 00:10:29 -0000
@@ -26,6 +26,7 @@
 #include "connection.h"
 #include "driver.h"
 #include "services.h"
+#include "activation.h"
 #include "utils.h"
 #include "bus.h"
 #include "signals.h"
@@ -257,7 +258,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_implicit_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 +399,8 @@ bus_dispatch_remove_connection (DBusConn
 
 #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 +1193,104 @@ check_nonexistent_service_activation (Bu
   return retval;
 }
 
+/* returns TRUE if the correct thing happens,
+ * but the correct thing may include OOM errors.
+ */
+static dbus_bool_t
+check_nonexistent_service_implicit_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_implicit_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 (implicit 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,
@@ -1308,6 +1429,8 @@ check_service_activated (BusContext     
             }
         }
 
+      printf ("*** Got service name (created): %s\n", service_name);
+      
       if (strcmp (service_name, activated_name) != 0)
         {
           _dbus_warn ("Expected to see service %s created, saw %s instead\n",
@@ -1398,6 +1522,94 @@ check_service_activated (BusContext     
 }
 
 static dbus_bool_t
+check_service_implicitly_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,63 +2186,490 @@ check_segfault_service_activation (BusCo
   return retval;
 }
 
-typedef struct
-{
-  Check1Func func;
-  BusContext *context;
-} Check1Data;
 
+/* returns TRUE if the correct thing happens,
+ * but the correct thing may include OOM errors.
+ */
 static dbus_bool_t
-check_oom_check1_func (void *data)
-{
-  Check1Data *d = data;
-
-  if (! (* d->func) (d->context))
-    return FALSE;
-  
-  if (!check_no_leftovers (d->context))
-    {
-      _dbus_warn ("Messages were left over, should be covered by test suite\n");
-      return FALSE;
-    }
-
-  return TRUE;
-}
-
-static void
-check1_try_iterations (BusContext *context,
-                       const char *description,
-                       Check1Func  func)
+check_segfault_service_implicit_activation (BusContext     *context,
+					    DBusConnection *connection)
 {
-  Check1Data d;
+  DBusMessage *message;
+  dbus_uint32_t serial;
+  dbus_bool_t retval;
+  DBusError error;
 
-  d.func = func;
-  d.context = context;
+  dbus_error_init (&error);
 
-  if (!_dbus_test_oom_handling (description, check_oom_check1_func,
-                                &d))
-    _dbus_assert_not_reached ("test failed");
-}
+  dbus_error_init (&error);
 
-typedef struct
-{
-  Check2Func func;
-  BusContext *context;
-  DBusConnection *connection;
-} Check2Data;
+  message = dbus_message_new_method_call ("org.freedesktop.DBus.TestSuiteSegfaultService",
+                                          "/org/freedesktop/TestSuite",
+                                          "org.freedesktop.TestSuite",
+                                          "Echo");
 
-static dbus_bool_t
-check_oom_check2_func (void *data)
-{
-  Check2Data *d = data;
+  if (message == NULL)
+    return TRUE;
 
-  if (! (* d->func) (d->context, d->connection))
-    return FALSE;
+  dbus_message_set_implicit_activation (message, TRUE);
   
-  if (!check_no_leftovers (d->context))
+  if (!dbus_connection_send (connection, message, &serial))
     {
-      _dbus_warn ("Messages were left over, should be covered by test suite");
-      return FALSE;
+      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 (implicit 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_implicit_activation (BusContext     *context,
+					    DBusConnection *connection)
+{
+  DBusMessage *message;
+  dbus_uint32_t serial;
+  dbus_bool_t retval;
+  DBusError error;
+  char *base_service;
+  static int i = 1;
+
+  base_service = NULL;
+
+  printf ("New run: %d\n\n", i++);
+  
+  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_implicit_activation (message, TRUE);
+
+  if (!dbus_message_append_args (message,
+                                 DBUS_TYPE_STRING, TEST_ECHO_MESSAGE,
+                                 DBUS_TYPE_INVALID))
+    {
+      dbus_message_unref (message);
+      return TRUE;
+    }
+
+  printf ("Q: Send impl.act message, %p\n", message);
+
+  serial = 0;
+  if (!dbus_connection_send_with_reply (connection, message, NULL, 3000))//&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.
+   */
+
+  printf ("Q: block until message from bus (1)\n");
+  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, unless the
+   * service was already running, then we get the reply immediately.
+   */
+  message = pop_message_waiting_for_memory (connection);
+  if (message == NULL)
+    {
+      _dbus_warn ("Did not receive any messages after implicit activation %d on %p\n",
+                  serial, connection);
+      goto out;
+    }
+
+  printf ("Q: Checking for ServiceCreated or error\n");
+  
+  verbose_message_received (connection, message);
+  _dbus_verbose ("  (after sending %s)\n", "ActivateService");
+
+  printf ("Q: Noticing reply serial: %d, orig: %d (if same => already activated)\n",
+	  dbus_message_get_reply_serial (message), serial);
+  
+  if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR)
+    {
+      printf ("Q: Got error\n");
+      
+      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)");
+	  printf ("Q: Error has wrong sender\n");
+	  goto out;
+        }
+      
+      if (dbus_message_is_error (message,
+                                 DBUS_ERROR_NO_MEMORY))
+        {
+          ; /* good, this is a valid response */
+	  printf ("Q: Got NO_MEMORY error\n");
+        }
+      else if (dbus_message_is_error (message,
+                                      DBUS_ERROR_SPAWN_CHILD_EXITED))
+        {
+          ; /* good, this is expected also */
+	  printf ("Q: Got CHILD_EXITED error\n");
+        }
+      else
+        {
+          _dbus_warn ("Did not expect error %s\n",
+                      dbus_message_get_error_name (message));
+	  printf ("Q: Invalid error\n");
+          goto out;
+        }
+    }
+  else if (TRUE || dbus_message_get_reply_serial (message) != serial)
+    {
+      dbus_bool_t got_service_deleted;
+      dbus_bool_t got_error;
+
+      printf ("Q: Check for base service ServiceCreated\n");
+      
+      /* Since this is not a reply to the sent message, it should be a
+       * ServiceCreated for the base service or an error.
+       */
+      if (!check_base_service_activated (context, connection,
+                                         message, &base_service))
+	goto out;
+
+      printf ("Q: Base service created OK\n");
+      
+      dbus_message_unref (message);
+      message = NULL;
+
+      printf ("Q: block until message from bus (2)\n");
+
+      /* 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;
+
+      printf ("Q: got_service_deleted: %d, got_error: %d\n", got_service_deleted, got_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;
+
+	  printf ("Q: Got correct error (no_memory)\n");
+	  
+          /* 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)
+            {
+	      printf ("Q: Didn't get error yet, wait for it\n");
+	  
+              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;
+            }
+
+	  printf ("Q: Check for ServiceCreated for named service...\n");
+	  
+	  /* Check that ServiceCreated was correctly received */
+          if (!check_service_implicitly_activated (context, connection, EXISTENT_SERVICE_NAME,
+						   base_service, message))
+            goto out;
+
+	  printf ("Q: ...check OK\n");
+	  
+          dbus_message_unref (message);
+          message = NULL;
+	}
+
+      printf ("Q: block until message from bus (3)\n");
+      block_connection_until_message_from_bus (context, connection);
+
+      message = pop_message_waiting_for_memory (connection);
+    }
+
+  /* If we got this far, we should receive a reply or an error from the echo
+   * service.
+   */
+  
+  printf ("Q: Check reply or error from echo service\n");
+
+  if (message == NULL)
+    {
+      _dbus_warn ("Expected a reply to %s, got nothing\n",
+		  "Echo (implicit activation)");
+      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)
+    {
+      char *str = NULL;
+      
+      if (!dbus_message_get_args (message, &error,
+				  DBUS_TYPE_STRING, &str,
+				  DBUS_TYPE_INVALID))
+	{
+	  if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
+	    {
+	      _dbus_verbose ("no memory to get echoed string\n");
+	    }
+	  else
+	    {
+	      _dbus_assert (dbus_error_is_set (&error));
+	      _dbus_warn ("Did not get the expected single string argument\n");
+	      goto out;
+	    }
+	}
+      else if (strcmp (str, TEST_ECHO_MESSAGE) != 0)
+	{
+	  _dbus_warn ("Expected an echo reply argument of '%s', got '%s'\n",
+		      TEST_ECHO_MESSAGE, str);
+	  goto out;
+	}
+      else
+	{
+	  printf ("Got echoed message: '%s'\n", str);
+	}
+      
+      dbus_free (str);
+    }
+  
+  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;
+  
+  retval = TRUE;
+
+  printf ("----\n");
+  
+ out:
+  if (message)
+    dbus_message_unref (message);
+
+  if (base_service)
+    dbus_free (base_service);
+
+  return retval;
+}
+
+typedef struct
+{
+  Check1Func func;
+  BusContext *context;
+} Check1Data;
+
+static dbus_bool_t
+check_oom_check1_func (void *data)
+{
+  Check1Data *d = data;
+
+  if (! (* d->func) (d->context))
+    return FALSE;
+  
+  if (!check_no_leftovers (d->context))
+    {
+      _dbus_warn ("Messages were left over, should be covered by test suite\n");
+      return FALSE;
+    }
+
+  return TRUE;
+}
+
+static void
+check1_try_iterations (BusContext *context,
+                       const char *description,
+                       Check1Func  func)
+{
+  Check1Data d;
+
+  d.func = func;
+  d.context = context;
+
+  if (!_dbus_test_oom_handling (description, check_oom_check1_func,
+                                &d))
+    _dbus_assert_not_reached ("test failed");
+}
+
+typedef struct
+{
+  Check2Func func;
+  BusContext *context;
+  DBusConnection *connection;
+} Check2Data;
+
+static dbus_bool_t
+check_oom_check2_func (void *data)
+{
+  Check2Data *d = data;
+
+  if (! (* d->func) (d->context, d->connection))
+    return FALSE;
+  
+  if (!check_no_leftovers (d->context))
+    {
+      _dbus_warn ("Messages were left over, should be covered by test suite");
+      return FALSE;
     }
 
   return TRUE;
@@ -2058,8 +2697,9 @@ bus_dispatch_test (const DBusString *tes
 {
   BusContext *context;
   DBusConnection *foo;
-  DBusConnection *bar;
+  /*  DBusConnection *bar;
   DBusConnection *baz;
+  */
   DBusError error;
 
   dbus_error_init (&error);
@@ -2068,7 +2708,7 @@ bus_dispatch_test (const DBusString *tes
                                   "valid-config-files/debug-allow-all.conf");
   if (context == NULL)
     return FALSE;
-  
+  /*
   foo = dbus_connection_open ("debug-pipe:name=test-server", &error);
   if (foo == NULL)
     _dbus_assert_not_reached ("could not alloc connection");
@@ -2131,6 +2771,46 @@ bus_dispatch_test (const DBusString *tes
   kill_client_connection_unchecked (foo);
   kill_client_connection_unchecked (bar);
   kill_client_connection_unchecked (baz);
+  */
+
+  foo = dbus_connection_open ("debug-pipe:name=test-server", &error);
+  if (foo == NULL)
+    _dbus_assert_not_reached ("could not alloc connection");
+
+  if (!bus_setup_debug_client (foo))
+    _dbus_assert_not_reached ("could not set up connection");
+
+  if (!check_hello_message (context, foo))
+    _dbus_assert_not_reached ("hello message failed");
+
+   if (!check_add_match_all (context, foo))
+     _dbus_assert_not_reached ("AddMatch message failed");
+
+  if (!check_no_leftovers (context))
+    {
+      _dbus_warn ("Messages were left over after setting up initial connections");
+      _dbus_assert_not_reached ("initial connection setup failed");
+    }
+  
+  if (0)
+    {
+      check2_try_iterations (context, foo, "nonexistent_implicit_service_activation",
+			     check_nonexistent_service_implicit_activation);
+    }
+
+  if (0)
+    {
+      check2_try_iterations (context, foo, "segfault_implicit_service_activation",
+			     check_segfault_service_implicit_activation);
+    }
+
+  if (1)
+    {
+      check2_try_iterations (context, foo, "existent_implicit_service_activation",
+			     check_existent_service_implicit_activation);
+    }
+
+  kill_client_connection_unchecked (foo);
 
   bus_context_unref (context);
   
Index: bus/driver.c
===================================================================
RCS file: /cvs/dbus/dbus/bus/driver.c,v
retrieving revision 1.45
diff -u -b -B -p -r1.45 driver.c
--- a/bus/driver.c	2 Dec 2003 10:44:21 -0000	1.45
+++ b/bus/driver.c	12 Mar 2004 00:10:29 -0000
@@ -587,7 +587,7 @@ bus_driver_handle_activate_service (DBus
 
   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: bus/services.c
===================================================================
RCS file: /cvs/dbus/dbus/bus/services.c,v
retrieving revision 1.19
diff -u -b -B -p -r1.19 services.c
--- a/bus/services.c	24 Feb 2004 19:50:25 -0000	1.19
+++ b/bus/services.c	12 Mar 2004 00:10:29 -0000
@@ -262,6 +262,7 @@ bus_registry_acquire_service (BusRegistr
   DBusConnection *current_owner;
   BusClientPolicy *policy;
   BusService *service;
+  BusActivation  *activation;
   
   retval = FALSE;
 
@@ -376,7 +377,11 @@ bus_registry_acquire_service (BusRegistr
       *result = DBUS_SERVICE_REPLY_PRIMARY_OWNER;
     }
 
-  retval = TRUE;
+  activation = bus_context_get_activation (registry->context);
+  retval = bus_activation_send_pending_implicit_activation_messages (activation,
+								     service,
+								     transaction,
+								     error);
   
  out:
   return retval;
Index: bus/signals.c
===================================================================
RCS file: /cvs/dbus/dbus/bus/signals.c,v
retrieving revision 1.7
diff -u -b -B -p -r1.7 signals.c
Index: bus/test-main.c
===================================================================
RCS file: /cvs/dbus/dbus/bus/test-main.c,v
retrieving revision 1.15
diff -u -b -B -p -r1.15 test-main.c
--- a/bus/test-main.c	2 Dec 2003 10:44:21 -0000	1.15
+++ b/bus/test-main.c	12 Mar 2004 00:10:29 -0000
@@ -77,7 +77,7 @@ main (int argc, char **argv)
     die ("initializing debug threads");
 #endif
 
-  printf ("%s: Running expire list test\n", argv[0]);
+  /*  printf ("%s: Running expire list test\n", argv[0]);
   if (!bus_expire_list_test (&test_data_dir))
     die ("expire list");
   
@@ -106,7 +106,7 @@ main (int argc, char **argv)
     die ("sha1");
 
   check_memleaks (argv[0]);
-  
+  */
   printf ("%s: Running message dispatch test\n", argv[0]);
   if (!bus_dispatch_test (&test_data_dir))
     die ("dispatch");
Index: bus/test.c
===================================================================
RCS file: /cvs/dbus/dbus/bus/test.c,v
retrieving revision 1.23
diff -u -b -B -p -r1.23 test.c
Index: dbus/dbus-message.c
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-message.c,v
retrieving revision 1.119
diff -u -b -B -p -r1.119 dbus-message.c
--- a/dbus/dbus-message.c	8 Mar 2004 10:29:16 -0000	1.119
+++ b/dbus/dbus-message.c	12 Mar 2004 00:10:30 -0000
@@ -4387,6 +4387,35 @@ dbus_message_get_no_reply (DBusMessage *
   return (*header & DBUS_HEADER_FLAG_NO_REPLY_EXPECTED) != 0;
 }
 
+void
+dbus_message_set_implicit_activation (DBusMessage *message,
+				      dbus_bool_t  implicit_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 (implicit_activation)
+    *header |= DBUS_HEADER_FLAG_IMPLICIT_ACTIVATION;
+  else
+    *header &= ~DBUS_HEADER_FLAG_IMPLICIT_ACTIVATION;
+}
+
+dbus_bool_t
+dbus_message_get_implicit_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_IMPLICIT_ACTIVATION) != 0;
+}
+
 /**
  * Gets the service which originated this message,
  * or #NULL if unknown or inapplicable.
Index: dbus/dbus-message.h
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-message.h,v
retrieving revision 1.49
diff -u -b -B -p -r1.49 dbus-message.h
--- a/dbus/dbus-message.h	2 Dec 2003 10:44:21 -0000	1.49
+++ b/dbus/dbus-message.h	12 Mar 2004 00:10:30 -0000
@@ -119,6 +119,10 @@ dbus_bool_t   dbus_message_set_reply_ser
                                              dbus_uint32_t  reply_serial);
 dbus_uint32_t dbus_message_get_reply_serial (DBusMessage   *message);
 
+void          dbus_message_set_implicit_activation (DBusMessage *message,
+						    dbus_bool_t  implicit_activation);
+dbus_bool_t   dbus_message_get_implicit_activation (DBusMessage *message);
+
 dbus_bool_t   dbus_message_get_path_decomposed (DBusMessage   *message,
                                                 char        ***path);
 
Index: dbus/dbus-protocol.h
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-protocol.h,v
retrieving revision 1.25
diff -u -b -B -p -r1.25 dbus-protocol.h
--- a/dbus/dbus-protocol.h	2 Dec 2003 10:44:21 -0000	1.25
+++ b/dbus/dbus-protocol.h	12 Mar 2004 00:10:30 -0000
@@ -72,6 +72,7 @@ extern "C" {
   
 /* Header flags */
 #define DBUS_HEADER_FLAG_NO_REPLY_EXPECTED 0x1
+#define DBUS_HEADER_FLAG_IMPLICIT_ACTIVATION 0x2
   
 /* Header fields */
 #define DBUS_HEADER_FIELD_INVALID        0
Index: test/test-service.c
===================================================================
RCS file: /cvs/dbus/dbus/test/test-service.c,v
retrieving revision 1.14
diff -u -b -B -p -r1.14 test-service.c
--- a/test/test-service.c	21 Oct 2003 05:46:52 -0000	1.14
+++ b/test/test-service.c	12 Mar 2004 00:10:30 -0000
@@ -152,6 +152,13 @@ filter_func (DBusConnection     *connect
     }
   else
     {
+      if (dbus_message_get_type (message) == 3)
+        {
+	  fprintf (stderr, "test-service got error from %s (%s)\n",
+		   dbus_message_get_sender (message),
+		   dbus_message_get_error_name (message));
+	}
+	    
       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
     }
 }

--=-roK24e5WA8RjmEsD2WNf--





More information about the dbus mailing list