diff options
| author | Richard Hult <richard@imendio.com> | 2004-03-16 18:00:35 +0000 | 
|---|---|---|
| committer | Richard Hult <richard@imendio.com> | 2004-03-16 18:00:35 +0000 | 
| commit | 93f433a17a0aabff91a0384bf9c4f99c9cf30ae1 (patch) | |
| tree | be2ffbc0160abfb63808d994d076faa67e4ff81a | |
| parent | 24ffe79c80d376b058c2d154b2b5f0ef8fee1c36 (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-- | ChangeLog | 20 | ||||
| -rw-r--r-- | bus/activation.c | 101 | ||||
| -rw-r--r-- | bus/activation.h | 29 | ||||
| -rw-r--r-- | bus/dispatch.c | 564 | ||||
| -rw-r--r-- | bus/driver.c | 2 | ||||
| -rw-r--r-- | bus/services.c | 7 | ||||
| -rw-r--r-- | dbus/dbus-message.c | 29 | ||||
| -rw-r--r-- | dbus/dbus-message.h | 4 | ||||
| -rw-r--r-- | dbus/dbus-protocol.h | 1 | ||||
| -rw-r--r-- | doc/dbus-specification.xml | 13 | 
10 files changed, 738 insertions, 32 deletions
@@ -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>  | 
