2003-04-07 Havoc Pennington <hp@redhat.com>
authorHavoc Pennington <hp@redhat.com>
Mon, 7 Apr 2003 23:28:16 +0000 (23:28 +0000)
committerHavoc Pennington <hp@redhat.com>
Mon, 7 Apr 2003 23:28:16 +0000 (23:28 +0000)
* doc/dbus-specification.sgml: require that base service names
start with ':' and that the base service is created/deleted
as first and last things a connection does on the bus

* bus/dispatch.c (check_existent_service_activation): lots more
work on the activation test; it doesn't fully pass yet...

* test/test-service.c (main): fix so we don't memleak the
connection to the message bus
(filter_func): accept a message asking us to exit

ChangeLog
bus/activation.c
bus/dispatch.c
bus/test.c
bus/test.h
dbus/dbus-bus.c
dbus/dbus-connection.c
doc/dbus-specification.sgml
test/test-service.c
test/test-utils.c
test/test-utils.h

index 3f86737..8528c67 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2003-04-07  Havoc Pennington  <hp@redhat.com>
+
+       * doc/dbus-specification.sgml: require that base service names 
+       start with ':' and that the base service is created/deleted 
+       as first and last things a connection does on the bus
+
+       * bus/dispatch.c (check_existent_service_activation): lots more 
+       work on the activation test; it doesn't fully pass yet...
+
+       * test/test-service.c (main): fix so we don't memleak the
+       connection to the message bus
+       (filter_func): accept a message asking us to exit
+
 2003-04-06  Havoc Pennington  <hp@pobox.com>
 
        * qt/Makefile.am (dbusinclude_HEADERS): install dbus-qt.h, 
index 425d9c1..8ecf6ec 100644 (file)
@@ -515,7 +515,7 @@ bus_activation_service_created (BusActivation  *activation,
              BUS_SET_OOM (error);
              goto error;
            }
-
+          
           dbus_message_unref (message);
        }
 
index ce0d71c..4761a4b 100644 (file)
@@ -1034,6 +1034,231 @@ check_nonexistent_service_activation (BusContext     *context,
   return retval;
 }
 
+static dbus_bool_t
+check_service_activated (BusContext     *context,
+                         DBusConnection *connection,
+                         const char     *activated_name,
+                         dbus_bool_t     require_base_service,
+                         DBusMessage    *initial_message,
+                         char          **base_service_p)
+{
+  DBusMessage *message;
+  dbus_bool_t retval;
+  DBusError error;
+  char *base_service;
+  dbus_uint32_t activation_result;
+  dbus_bool_t already_saw_base_created;
+  
+  base_service = NULL;
+  retval = FALSE;
+  
+  dbus_error_init (&error);
+
+  message = initial_message;
+  dbus_message_ref (message);
+  
+  /* This is kind of a mess since we get the creation of
+   * the base service only if the activated service didn't
+   * already exist. Right now the test kills and restarts
+   * the service each time, so the mess is pointless.
+   */
+  already_saw_base_created = FALSE;
+
+ recheck_service_created:
+  if (dbus_message_name_is (message, DBUS_MESSAGE_SERVICE_CREATED))
+    {
+      char *service_name;
+      CheckServiceCreatedData scd;
+          
+      if (!dbus_message_get_args (message, &error,
+                                  DBUS_TYPE_STRING, &service_name,
+                                  DBUS_TYPE_INVALID))
+        {
+          _dbus_warn ("Message %s doesn't have a service name: %s\n",
+                      dbus_message_get_name (message),
+                      error.message);
+          dbus_error_free (&error);
+          goto out;
+        }
+
+      if (!already_saw_base_created && *service_name == ':')
+        {
+          /* This is a base service name, mop up all the
+           * other messages about it
+           */
+              
+          base_service = service_name;
+          service_name = NULL;
+              
+          scd.skip_connection = connection;
+          scd.failed = FALSE;
+          scd.expected_service_name = base_service;
+          bus_test_clients_foreach (check_service_created_foreach,
+                                    &scd);
+              
+          if (scd.failed)
+            goto out;
+
+          already_saw_base_created = TRUE;
+
+          dbus_message_unref (message);
+          message = dbus_connection_pop_message (connection);
+          if (message == NULL)
+            {
+              _dbus_warn ("Expected a ServiceCreated for the activated service, got nothing\n");
+              goto out;
+            }
+              
+          goto recheck_service_created;
+        }
+      else if (require_base_service)
+        {
+          _dbus_warn ("Did not get a ServiceCreated for a base service\n");
+          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;
+          
+      dbus_message_unref (message);
+      message = dbus_connection_pop_message (connection);
+      if (message == NULL)
+        {
+          _dbus_warn ("Expected a reply to %s, got nothing\n",
+                      DBUS_MESSAGE_ACTIVATE_SERVICE);
+          goto out;
+        }
+    }
+      
+  if (!dbus_message_name_is (message, DBUS_MESSAGE_ACTIVATE_SERVICE))
+    {
+      _dbus_warn ("Expected reply to %s, got message %s instead\n",
+                  DBUS_MESSAGE_ACTIVATE_SERVICE,
+                  dbus_message_get_name (message));
+      goto out;
+    }
+
+  activation_result = 0;
+  if (!dbus_message_get_args (message, &error,
+                              DBUS_TYPE_UINT32, &activation_result,
+                              DBUS_TYPE_INVALID))
+    {
+      if (!dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
+        {
+          _dbus_warn ("Did not have activation result first argument to %s: %s\n",
+                      DBUS_MESSAGE_ACTIVATE_SERVICE, error.message);
+          dbus_error_free (&error);
+          goto out;
+        }
+
+      dbus_error_free (&error);
+    }
+  else
+    {
+      if (activation_result == DBUS_ACTIVATION_REPLY_ACTIVATED)
+        ; /* Good */
+      else if (activation_result == DBUS_ACTIVATION_REPLY_ALREADY_ACTIVE)
+        ; /* Good also */
+      else
+        {
+          _dbus_warn ("Activation result was 0x%x, no good.\n",
+                      activation_result);
+          goto out;
+        }
+    }
+
+  dbus_message_unref (message);
+  message = NULL;
+      
+  if (!check_no_leftovers (context))
+    {
+      _dbus_warn ("Messages were left over after verifying existent activation results\n");
+      goto out;
+    }
+
+  retval = TRUE;
+
+  if (base_service_p)
+    {
+      *base_service_p = base_service;
+      base_service = NULL;
+    }
+  
+ out:
+  if (message)
+    dbus_message_unref (message);
+
+  if (base_service)
+    dbus_free (base_service);
+  
+  return retval;
+}
+
+static dbus_bool_t
+check_service_deactivated (BusContext     *context,
+                           DBusConnection *connection,
+                           const char     *activated_name,
+                           const char     *base_service)
+{
+  DBusMessage *message;
+  dbus_bool_t retval;
+  DBusError error;
+  CheckServiceDeletedData csdd;
+
+  message = NULL;
+  retval = FALSE;
+  
+  dbus_error_init (&error);
+
+  /* Now we are expecting ServiceDeleted messages for the base
+   * service and the activated_name.  The base service
+   * notification is required to come second.
+   */
+  csdd.expected_service_name = activated_name;
+  csdd.failed = FALSE;
+  bus_test_clients_foreach (check_service_deleted_foreach,
+                            &csdd);      
+
+  if (csdd.failed)
+    goto out;
+      
+  csdd.expected_service_name = base_service;
+  csdd.failed = FALSE;
+  bus_test_clients_foreach (check_service_deleted_foreach,
+                            &csdd);
+
+  if (csdd.failed)
+    goto out;
+      
+  if (!check_no_leftovers (context))
+    {
+      _dbus_warn ("Messages were left over after verifying results of service exiting\n");
+      goto out;
+    }
+  
+ out:
+  if (message)
+    dbus_message_unref (message);
+  
+  return retval;
+}
+
 #define EXISTENT_SERVICE_NAME "org.freedesktop.DBus.TestSuiteEchoService"
 
 /* returns TRUE if the correct thing happens,
@@ -1047,6 +1272,9 @@ check_existent_service_activation (BusContext     *context,
   dbus_int32_t serial;
   dbus_bool_t retval;
   DBusError error;
+  char *base_service;
+
+  base_service = NULL;
   
   dbus_error_init (&error);
   
@@ -1079,7 +1307,7 @@ check_existent_service_activation (BusContext     *context,
   if (dbus_connection_get_dispatch_status (connection) ==
       DBUS_DISPATCH_COMPLETE)
     /* now wait for the message bus to hear back from the activated service */
-    bus_test_run_bus_loop (context);
+    bus_test_run_bus_loop (context, TRUE);
   
   /* and process everything again */
   bus_test_run_everything (context);
@@ -1132,9 +1360,51 @@ check_existent_service_activation (BusContext     *context,
     }
   else
     {
-      _dbus_warn ("Did not expect to successfully activate %s\n",
-                  EXISTENT_SERVICE_NAME);
-      goto out;
+      if (!check_service_activated (context, connection,
+                                    EXISTENT_SERVICE_NAME, TRUE,
+                                    message, &base_service))
+        goto out;
+
+      dbus_message_unref (message);
+      message = NULL;
+  
+      /* Now kill off the test service by sending it a quit message */
+      message = dbus_message_new (EXISTENT_SERVICE_NAME,
+                                  "org.freedesktop.DBus.TestSuiteExit");
+      
+      if (message == NULL)
+        {
+          dbus_free (base_service);
+          return TRUE;
+        }
+      
+      if (!dbus_connection_send (connection, message, &serial))
+        {
+          dbus_message_unref (message);
+          dbus_free (base_service);
+          return TRUE;
+        }
+
+      dbus_message_unref (message);
+      message = NULL;
+
+      /* send message */
+      bus_test_run_clients_loop (TRUE);
+
+      /* read it in and write it out to test service */
+      bus_test_run_bus_loop (context, FALSE);
+      
+      if (dbus_connection_get_dispatch_status (connection) ==
+          DBUS_DISPATCH_COMPLETE)
+        /* now wait for the message bus to hear back from the activated service exiting */
+        bus_test_run_bus_loop (context, TRUE);
+      
+      /* and process everything again */
+      bus_test_run_everything (context);
+
+      if (!check_service_deactivated (context, connection,
+                                      EXISTENT_SERVICE_NAME, base_service))
+        goto out;
     }
 
   retval = TRUE;
@@ -1142,6 +1412,9 @@ check_existent_service_activation (BusContext     *context,
  out:
   if (message)
     dbus_message_unref (message);
+
+  if (base_service)
+    dbus_free (base_service);
   
   return retval;
 }
@@ -1162,7 +1435,7 @@ check_oom_check1_func (void *data)
   
   if (!check_no_leftovers (d->context))
     {
-      _dbus_warn ("Messages were left over, should be covered by test suite");
+      _dbus_warn ("Messages were left over, should be covered by test suite\n");
       return FALSE;
     }
 
index 31c279f..ded23ba 100644 (file)
@@ -297,13 +297,13 @@ bus_test_client_listed (DBusConnection *connection)
 }
 
 void
-bus_test_run_clients_loop (void)
+bus_test_run_clients_loop (dbus_bool_t block_once)
 {
   if (client_loop == NULL)
     return;
   
   /* Do one blocking wait, since we're expecting data */
-  _dbus_loop_iterate (client_loop, TRUE);
+  _dbus_loop_iterate (client_loop, block_once);
 
   /* Then mop everything up */
   while (_dbus_loop_iterate (client_loop, FALSE))
@@ -311,10 +311,11 @@ bus_test_run_clients_loop (void)
 }
 
 void
-bus_test_run_bus_loop (BusContext *context)
+bus_test_run_bus_loop (BusContext *context,
+                       dbus_bool_t block_once)
 {
   /* Do one blocking wait, since we're expecting data */
-  _dbus_loop_iterate (bus_context_get_loop (context), TRUE);
+  _dbus_loop_iterate (bus_context_get_loop (context), block_once);
 
   /* Then mop everything up */
   while (_dbus_loop_iterate (bus_context_get_loop (context), FALSE))
index 5606bb9..3d2a6fd 100644 (file)
@@ -39,8 +39,9 @@ dbus_bool_t bus_setup_debug_client    (DBusConnection               *connection)
 void        bus_test_clients_foreach  (BusConnectionForeachFunction  function,
                                        void                         *data);
 dbus_bool_t bus_test_client_listed    (DBusConnection               *connection);
-void        bus_test_run_bus_loop     (BusContext                   *context);
-void        bus_test_run_clients_loop (void);
+void        bus_test_run_bus_loop     (BusContext                   *context,
+                                       dbus_bool_t                   block);
+void        bus_test_run_clients_loop (dbus_bool_t                   block);
 void        bus_test_run_everything   (BusContext                   *context);
 BusContext* bus_context_new_test      (const DBusString             *test_data_dir,
                                        const char                   *filename);
index c16ceeb..7470386 100644 (file)
@@ -242,7 +242,7 @@ static void
 bus_data_free (void *data)
 {
   BusData *bd = data;
-
+  
   if (bd->is_well_known)
     {
       int i;
@@ -253,7 +253,7 @@ bus_data_free (void *data)
         {
           if (bus_connections[i] == bd->connection)
             bus_connections[i] = NULL;
-
+          
           ++i;
         }
       _DBUS_UNLOCK (bus);
index e28e45b..d92268b 100644 (file)
@@ -977,7 +977,7 @@ dbus_connection_unref (DBusConnection *connection)
   last_unref = (connection->refcount == 0);
 
 #if 0
-  _dbus_verbose ("unref() connection %p count = %d\n", connection, connection->refcount);
+  printf ("unref() connection %p count = %d\n", connection, connection->refcount);
 #endif
   
   dbus_mutex_unlock (connection->mutex);
index 3c41068..3bd49ac 100644 (file)
         applications.
       </para>
       <para>
-        [FIXME I think we should define the format of the base service name, 
-        and specify that a regular service name can never be in that 
-        format; this allows us to categorically prevent "spoofing" - for 
-        example perhaps the base service name starts with a certain 
-        character that no real service name can start with]
+        Ownership of the base service is a prerequisite for interaction with 
+        the message bus. It logically follows that the base service is always 
+        the first service that an application comes to own, and the last 
+        service that it loses ownership of.
+      </para>
+      <para>
+        Base service names must begin with the character ':' (ASCII colon
+        character); service names that are not base service names must not begin
+        with this character. (The bus must reject any attempt by an application
+        to manually create a service name beginning with ':'.) This restriction
+        categorically prevents "spoofing"; messages sent to a base service name
+        will always go to a single application instance and that instance only.
       </para>
       <para>
         An application can request additional service names to be associated
index a1f2ae3..a9a960a 100644 (file)
@@ -2,6 +2,17 @@
 #include "test-utils.h"
 
 static DBusLoop *loop;
+static dbus_bool_t already_quit;
+
+static void
+quit (void)
+{
+  if (!already_quit)
+    {
+      _dbus_loop_quit (loop);
+      already_quit = TRUE;
+    }
+}
 
 static void
 die (const char *message)
@@ -62,12 +73,14 @@ filter_func (DBusMessageHandler *handler,
              DBusConnection     *connection,
              DBusMessage        *message,
              void               *user_data)
-{
+{  
   if (dbus_message_name_is (message, "org.freedesktop.DBus.TestSuiteEcho"))
     return handle_echo (connection, message);
-  else if (dbus_message_name_is (message, DBUS_MESSAGE_LOCAL_DISCONNECT))
+  else if (dbus_message_name_is (message, "org.freedesktop.DBus.TestSuiteExit") ||
+           dbus_message_name_is (message, DBUS_MESSAGE_LOCAL_DISCONNECT))
     {
-      _dbus_loop_quit (loop);
+      dbus_connection_disconnect (connection);
+      quit ();
       return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
     }
   else
@@ -85,6 +98,7 @@ main (int    argc,
   DBusMessageHandler *handler;
   const char *to_handle[] = {
     "org.freedesktop.DBus.TestSuiteEcho",
+    "org.freedesktop.DBus.TestSuiteExit",
     DBUS_MESSAGE_LOCAL_DISCONNECT,
   };
   int result;
@@ -121,11 +135,13 @@ main (int    argc,
       fprintf (stderr, "Failed to acquire service: %s\n",
                error.message);
       dbus_error_free (&error);
-      return 1;
+      exit (1);
     }
   
   _dbus_loop_run (loop);
 
+  test_connection_shutdown (loop, connection);
+  
   dbus_connection_unref (connection);
   
   dbus_message_handler_unref (handler);
@@ -134,6 +150,8 @@ main (int    argc,
   loop = NULL;
   
   dbus_shutdown ();
+
+  printf ("*** Test service exiting\n");
   
   return 0;
 }
index d7ccd93..62963f3 100644 (file)
@@ -176,3 +176,23 @@ test_connection_setup (DBusLoop       *loop,
     cdata_free (cd);
   return FALSE;
 }
+
+void
+test_connection_shutdown (DBusLoop       *loop,
+                          DBusConnection *connection)
+{
+  if (!dbus_connection_set_watch_functions (connection,
+                                            NULL,
+                                            NULL,
+                                            NULL,
+                                            NULL, NULL))
+    _dbus_assert_not_reached ("setting watch functions to NULL failed");
+  
+  if (!dbus_connection_set_timeout_functions (connection,
+                                              NULL,
+                                              NULL,
+                                              NULL,
+                                              NULL, NULL))
+    _dbus_assert_not_reached ("setting timeout functions to NULL failed");
+
+}
index 2f115c7..f00a718 100644 (file)
 
 dbus_bool_t test_connection_setup                 (DBusLoop       *loop,
                                                    DBusConnection *connection);
+void        test_connection_shutdown              (DBusLoop       *loop,
+                                                   DBusConnection *connection);
 void        test_connection_dispatch_all_messages (DBusConnection *connection);
 dbus_bool_t test_connection_dispatch_one_message  (DBusConnection *connection);
 
+
 #endif