diff options
| author | John (J5) Palmieri <johnp@redhat.com> | 2006-07-14 01:17:59 +0000 | 
|---|---|---|
| committer | John (J5) Palmieri <johnp@redhat.com> | 2006-07-14 01:17:59 +0000 | 
| commit | 7628b541258d906e27e2000a402ed2d02383479c (patch) | |
| tree | a422ce5ba507acda462b26b09a79b751c4944841 | |
| parent | a3e4cf7b3a37b18df1a1cc0aa1011ebb5be0c585 (diff) | |
* bus/activation.[ch] (bus_activation_list_services): new function to
  get the list of services that can be activated
* bus/dispatch.c: test coverage for the new bus method
  ListActivatableNames
* bus/driver.c: new bus method ListActivatableNames to get the list of
  services that can be activated
* doc/dbus-specification.xml: ListActivatableNames method documentation
| -rw-r--r-- | ChangeLog | 13 | ||||
| -rw-r--r-- | bus/activation.c | 45 | ||||
| -rw-r--r-- | bus/activation.h | 3 | ||||
| -rw-r--r-- | bus/dispatch.c | 349 | ||||
| -rw-r--r-- | bus/driver.c | 100 | ||||
| -rw-r--r-- | doc/dbus-specification.xml | 31 | 
6 files changed, 537 insertions, 4 deletions
@@ -1,3 +1,16 @@ +2006-07-13  Carlos Garcia Campos  <carlosgc@gnome.org> + +	* bus/activation.[ch] (bus_activation_list_services): new function to  +	get the list of services that can be activated + +	* bus/dispatch.c: test coverage for the new bus method +	ListActivatableNames + +	* bus/driver.c: new bus method ListActivatableNames to get the list of +	services that can be activated + +	* doc/dbus-specification.xml: ListActivatableNames method documentation +  2006-07-12  John (J5) Palmieri  <johnp@redhat.com>  	* dbus/Makefile.am: add dbus-pending-call-internal.h to the list of  	source files diff --git a/bus/activation.c b/bus/activation.c index 1cdedb9f..40221938 100644 --- a/bus/activation.c +++ b/bus/activation.c @@ -1565,6 +1565,51 @@ bus_activation_activate_service (BusActivation  *activation,    return TRUE;  } +dbus_bool_t +bus_activation_list_services (BusActivation *activation, +			      char        ***listp, +			      int           *array_len) +{ +  int i, j, len; +  char **retval; +  DBusHashIter iter; + +  len = _dbus_hash_table_get_n_entries (activation->entries); +  retval = dbus_new (char *, len + 1); + +  if (retval == NULL) +    return FALSE; + +  _dbus_hash_iter_init (activation->entries, &iter); +  i = 0; +  while (_dbus_hash_iter_next (&iter)) +    { +      BusActivationEntry *entry = _dbus_hash_iter_get_value (&iter); + +      retval[i] = _dbus_strdup (entry->name); +      if (retval[i] == NULL) +	goto error; + +      i++; +    } + +  retval[i] = NULL; + +  if (array_len) +    *array_len = len; + +  *listp = retval; +  return TRUE; + + error: +  for (j = 0; j < i; j++) +    dbus_free (retval[i]); +  dbus_free (retval); + +  return FALSE; +} +   +  #ifdef DBUS_BUILD_TESTS  #include <stdio.h> diff --git a/bus/activation.h b/bus/activation.h index d12d8718..88d5bbce 100644 --- a/bus/activation.h +++ b/bus/activation.h @@ -45,6 +45,9 @@ dbus_bool_t    bus_activation_service_created  (BusActivation     *activation,  						const char        *service_name,  						BusTransaction    *transaction,  						DBusError         *error); +dbus_bool_t    bus_activation_list_services    (BusActivation     *registry, +						char            ***listp, +						int               *array_len);  dbus_bool_t    bus_activation_send_pending_auto_activation_messages (BusActivation     *activation,  								     BusService        *service, diff --git a/bus/dispatch.c b/bus/dispatch.c index 526c0182..e1dd001f 100644 --- a/bus/dispatch.c +++ b/bus/dispatch.c @@ -2590,9 +2590,9 @@ check_existent_service_no_auto_start (BusContext     *context,                goto out;              } -          if (!check_send_exit_to_service (context, connection, +	  if (!check_send_exit_to_service (context, connection,                                             EXISTENT_SERVICE_NAME, base_service)) -            goto out; +	    goto out;            break;          } @@ -3512,6 +3512,348 @@ check1_try_iterations (BusContext *context,      _dbus_assert_not_reached ("test failed");  } +static dbus_bool_t +check_get_services (BusContext     *context, +		    DBusConnection *connection, +		    const char     *method, +		    char         ***services, +		    int            *len) +{ +  DBusMessage *message; +  dbus_uint32_t serial; +  dbus_bool_t retval; +  DBusError error; +  char **srvs; +  int l; + +  retval = FALSE; +  dbus_error_init (&error); +  message = NULL; + +  message = dbus_message_new_method_call (DBUS_SERVICE_DBUS, +					  DBUS_PATH_DBUS, +					  DBUS_INTERFACE_DBUS, +					  method); + +  if (message == NULL) +    return TRUE; + +  if (!dbus_connection_send (connection, message, &serial)) +    { +      dbus_message_unref (message); +      return TRUE; +    } + +  /* send our message */ +  bus_test_run_clients_loop (SEND_PENDING (connection)); + +  dbus_message_unref (message); +  message = NULL; + +  dbus_connection_ref (connection); /* because we may get disconnected */ +  block_connection_until_message_from_bus (context, connection, "reply to ListActivatableNames/ListNames"); + +  if (!dbus_connection_get_is_connected (connection)) +    { +      _dbus_verbose ("connection was disconnected: %s %d\n", _DBUS_FUNCTION_NAME, __LINE__); + +      dbus_connection_unref (connection); + +      return TRUE; +    } + +  dbus_connection_unref (connection); + +  message = pop_message_waiting_for_memory (connection); +  if (message == NULL) +    { +      _dbus_warn ("Did not receive a reply to %s %d on %p\n", +		  method, serial, connection); +      goto out; +    } + +  verbose_message_received (connection, message); + +  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) +	{ +	  ; /* good, expected */ +	} +      else +	{ +	  warn_unexpected (connection, message, +			   "method_return for ListActivatableNames/ListNames"); + +	  goto out; +	} + +    retry_get_property: + +      if (!dbus_message_get_args (message, &error, +				  DBUS_TYPE_ARRAY, +				  DBUS_TYPE_STRING, +				  &srvs, &l, +				  DBUS_TYPE_INVALID)) +	{ +	  if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY)) +	    { +	      _dbus_verbose ("no memory to list services by %s\n", method); +	      dbus_error_free (&error); +	      _dbus_wait_for_memory (); +	      goto retry_get_property; +	    } +	  else +	    { +	      _dbus_assert (dbus_error_is_set (&error)); +	      _dbus_warn ("Did not get the expected DBUS_TYPE_ARRAY from %s\n", method); +	      goto out; +	    } +	} else { +	  *services = srvs; +	  *len = l; +	} +    } +   +  if (!check_no_leftovers (context)) +    goto out; +   +  retval = TRUE; +   + out: +  dbus_error_free (&error); +   +  if (message) +    dbus_message_unref (message); + +  return retval; +} + +/* returns TRUE if the correct thing happens, + * but the correct thing may include OOM errors. + */ +static dbus_bool_t +check_list_services (BusContext     *context, +		     DBusConnection *connection) +{ +  DBusMessage  *message; +  DBusMessage  *base_service_message; +  const char   *base_service; +  dbus_uint32_t serial; +  dbus_bool_t   retval; +  const char   *existent = EXISTENT_SERVICE_NAME; +  dbus_uint32_t flags; +  char        **services; +  int           len; + +  _dbus_verbose ("check_list_services for %p\n", connection); + +  if (!check_get_services (context, connection, "ListActivatableNames", &services, &len)) +    { +      return TRUE; +    } + +  if (!_dbus_string_array_contains ((const char **)services, existent)) +    { +      _dbus_warn ("Did not get the expected %s from ListActivatableNames\n", existent); +      return FALSE; +    } + +  dbus_free_string_array (services); + +  base_service_message = NULL; + +  message = dbus_message_new_method_call (DBUS_SERVICE_DBUS, +					  DBUS_PATH_DBUS, +					  DBUS_INTERFACE_DBUS, +					  "StartServiceByName"); + +  if (message == NULL) +    return TRUE; + +  dbus_message_set_auto_start (message, FALSE); + +  flags = 0; +  if (!dbus_message_append_args (message, +				 DBUS_TYPE_STRING, &existent, +				 DBUS_TYPE_UINT32, &flags, +				 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, "activated service to connect"); + +  bus_test_run_everything (context); + +  if (!dbus_connection_get_is_connected (connection)) +    { +      _dbus_verbose ("connection was disconnected: %s %d\n", _DBUS_FUNCTION_NAME, __LINE__); +      return TRUE; +    } + +  retval = FALSE; + +  message = pop_message_waiting_for_memory (connection); +  if (message == NULL) +    { +      _dbus_warn ("Did not receive any messages after %s %d on %p\n", +		  "StartServiceByName", serial, connection); +      goto out; +    } + +  verbose_message_received (connection, message); +  _dbus_verbose ("  (after sending %s)\n", "StartServiceByName"); + +  if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR) +    { +      if (!dbus_message_has_sender (message, DBUS_SERVICE_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_EXITED) || +	       dbus_message_is_error (message, +				      DBUS_ERROR_SPAWN_CHILD_SIGNALED) || +	       dbus_message_is_error (message, +				      DBUS_ERROR_SPAWN_EXEC_FAILED)) +	{ +	  ; /* good, this is expected also */ +	} +      else +	{ +	  _dbus_warn ("Did not expect error %s\n", +		      dbus_message_get_error_name (message)); +	  goto out; +	} +    } +  else +    { +      GotServiceInfo message_kind; + +      if (!check_base_service_activated (context, connection, +					 message, &base_service)) +	goto out; + +      base_service_message = 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, "test service to exit or finish up"); + +      message = dbus_connection_borrow_message (connection); +      if (message == NULL) +	{ +	  _dbus_warn ("Did not receive any messages after base service creation notification\n"); +	  goto out; +	} + +      message_kind = check_got_service_info (message); + +      dbus_connection_return_message (connection, message); +      message = NULL; + +      switch (message_kind) +	{ +	case GOT_SOMETHING_ELSE: +	case GOT_ERROR: +	case GOT_SERVICE_DELETED: +	  _dbus_warn ("Unexpected message after ActivateService " +		      "(should be an error or a service announcement"); +	  goto out; + +	case GOT_SERVICE_CREATED: +	  message = pop_message_waiting_for_memory (connection); +	  if (message == NULL) +	    { +	      _dbus_warn ("Failed to pop message we just put back! " +			  "should have been a NameOwnerChanged (creation)\n"); +	      goto out; +	    } +	   +	  if (!check_service_activated (context, connection, EXISTENT_SERVICE_NAME, +					base_service, message)) +	    goto out; + +	  dbus_message_unref (message); +	  message = NULL; + +	  if (!check_no_leftovers (context)) +	    { +	      _dbus_warn ("Messages were left over after successful activation\n"); +	      goto out; +	    } + +	  break; +	} +    } +   +  if (!check_get_services (context, connection, "ListNames", &services, &len)) +    { +      return TRUE; +    } + +  if (!_dbus_string_array_contains ((const char **)services, existent)) +    { +      _dbus_warn ("Did not get the expected %s from ListNames\n", existent); +      goto out; +    } + +  dbus_free_string_array (services); + +  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_message) +    dbus_message_unref (base_service_message); + +  return retval; +} +  typedef struct  {    Check2Func func; @@ -3625,6 +3967,9 @@ bus_dispatch_test (const DBusString *test_data_dir)    if (!check_get_connection_unix_process_id (context, baz))      _dbus_assert_not_reached ("GetConnectionUnixProcessID message failed"); + +  if (!check_list_services (context, baz)) +    _dbus_assert_not_reached ("ListActivatableNames message failed");    if (!check_no_leftovers (context))      { diff --git a/bus/driver.c b/bus/driver.c index 10f37bd2..636c8cad 100644 --- a/bus/driver.c +++ b/bus/driver.c @@ -436,16 +436,108 @@ bus_driver_handle_list_services (DBusConnection *connection,        ++i;      } +  dbus_free_string_array (services); +    if (!dbus_message_iter_close_container (&iter, &sub))      { -      dbus_free_string_array (services);        dbus_message_unref (reply);        BUS_SET_OOM (error);        return FALSE;      } +  if (!bus_transaction_send_from_driver (transaction, connection, reply)) +    { +      dbus_message_unref (reply); +      BUS_SET_OOM (error); +      return FALSE; +    } +  else +    { +      dbus_message_unref (reply); +      return TRUE; +    } +} + +static dbus_bool_t +bus_driver_handle_list_activatable_services (DBusConnection *connection, +					     BusTransaction *transaction, +					     DBusMessage    *message, +					     DBusError      *error) +{ +  DBusMessage *reply; +  int len; +  char **services; +  BusActivation *activation; +  int i; +  DBusMessageIter iter; +  DBusMessageIter sub; + +  _DBUS_ASSERT_ERROR_IS_CLEAR (error); + +  activation = bus_connection_get_activation (connection); + +  reply = dbus_message_new_method_return (message); +  if (reply == NULL) +    { +      BUS_SET_OOM (error); +      return FALSE; +    } + +  if (!bus_activation_list_services (activation, &services, &len)) +    { +      dbus_message_unref (reply); +      BUS_SET_OOM (error); +      return FALSE; +    } + +  dbus_message_iter_init_append (reply, &iter); + +  if (!dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, +					 DBUS_TYPE_STRING_AS_STRING, +					 &sub)) +    { +      dbus_free_string_array (services); +      dbus_message_unref (reply); +      BUS_SET_OOM (error); +      return FALSE; +    } + +  { +    /* Include the bus driver in the list */ +    const char *v_STRING = DBUS_SERVICE_DBUS; +    if (!dbus_message_iter_append_basic (&sub, DBUS_TYPE_STRING, +					 &v_STRING)) +      { +	dbus_free_string_array (services); +	dbus_message_unref (reply); +	BUS_SET_OOM (error); +	return FALSE; +      } +  } + +  i = 0; +  while (i < len) +    { +      if (!dbus_message_iter_append_basic (&sub, DBUS_TYPE_STRING, +					   &services[i])) +	{ +	  dbus_free_string_array (services); +	  dbus_message_unref (reply); +	  BUS_SET_OOM (error); +	  return FALSE; +	} +      ++i; +    } +    dbus_free_string_array (services); -   + +  if (!dbus_message_iter_close_container (&iter, &sub)) +    { +      dbus_message_unref (reply); +      BUS_SET_OOM (error); +      return FALSE; +    } +    if (!bus_transaction_send_from_driver (transaction, connection, reply))      {        dbus_message_unref (reply); @@ -1328,6 +1420,10 @@ struct      "",      DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING,      bus_driver_handle_list_services }, +  { "ListActivatableNames", +    "", +    DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING, +    bus_driver_handle_list_activatable_services },    { "AddMatch",      DBUS_TYPE_STRING_AS_STRING,      "", diff --git a/doc/dbus-specification.xml b/doc/dbus-specification.xml index 52422277..05f6ad1c 100644 --- a/doc/dbus-specification.xml +++ b/doc/dbus-specification.xml @@ -3267,6 +3267,37 @@            Returns a list of all currently-owned names on the bus.          </para>        </sect3> +      <sect3 id="bus-messages-list-activatable-names"> +        <title><literal>org.freedesktop.DBus.ListActivatableNames</literal></title> +        <para> +          As a method: +          <programlisting> +            ARRAY of STRING ListActivatableNames () +          </programlisting> +          Reply arguments: +          <informaltable> +            <tgroup cols="3"> +              <thead> +                <row> +                  <entry>Argument</entry> +                  <entry>Type</entry> +                  <entry>Description</entry> +                </row> +              </thead> +              <tbody> +                <row> +                  <entry>0</entry> +                  <entry>ARRAY of STRING</entry> +                  <entry>Array of strings where each string is a bus name</entry> +                </row> +              </tbody> +            </tgroup> +          </informaltable> +        </para> +        <para> +          Returns a list of all names that can be activated on the bus. +        </para> +      </sect3>        <sect3 id="bus-messages-name-exists">          <title><literal>org.freedesktop.DBus.NameHasOwner</literal></title>          <para>  | 
