summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn (J5) Palmieri <johnp@redhat.com>2006-07-14 01:17:59 +0000
committerJohn (J5) Palmieri <johnp@redhat.com>2006-07-14 01:17:59 +0000
commit7628b541258d906e27e2000a402ed2d02383479c (patch)
treea422ce5ba507acda462b26b09a79b751c4944841
parenta3e4cf7b3a37b18df1a1cc0aa1011ebb5be0c585 (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--ChangeLog13
-rw-r--r--bus/activation.c45
-rw-r--r--bus/activation.h3
-rw-r--r--bus/dispatch.c349
-rw-r--r--bus/driver.c100
-rw-r--r--doc/dbus-specification.xml31
6 files changed, 537 insertions, 4 deletions
diff --git a/ChangeLog b/ChangeLog
index 437ac04d..d9f45113 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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>