containers: Convert out parameters into an a{sv}

This allows for potential future mechanisms where the caller, rather than
the message bus, is responsible for creating the socket, without needing
to have a "null-like" representation for the absence of a path and the
absence of an address (in practice the empty string).

I've left the per-container server object path as a top-level thing
rather than moving it into the a{sv}, because I don't see any reason
why we would want to crate a per-container server without having a way
to talk about it in future API calls.

Requested-by: Sebastian Wick
Signed-off-by: Simon McVittie <smcv@collabora.com>
This commit is contained in:
Simon McVittie 2023-11-30 16:56:09 +00:00
parent 70526a3381
commit 76380efdbd
4 changed files with 107 additions and 50 deletions

View file

@ -35,6 +35,7 @@
#include <sys/types.h>
#include "dbus/dbus-asv-util.h"
#include "dbus/dbus-hash.h"
#include "dbus/dbus-message-internal.h"
#include "dbus/dbus-sysdeps-unix.h"
@ -680,8 +681,8 @@ bus_containers_handle_add_server (DBusConnection *connection,
BusContainerCreatorData *creator_data;
DBusMessageIter iter;
DBusMessageIter dict_iter;
DBusMessageIter writer;
DBusMessageIter array_writer;
DBusMessageIter writer = DBUS_MESSAGE_ITER_INIT_CLOSED;
DBusMessageIter asv_writer = DBUS_MESSAGE_ITER_INIT_CLOSED;
const char *type;
const char *app_id;
const char *instance_id;
@ -952,27 +953,21 @@ bus_containers_handle_add_server (DBusConnection *connection,
dbus_message_iter_init_append (reply, &writer);
if (!dbus_message_iter_open_container (&writer, DBUS_TYPE_ARRAY,
DBUS_TYPE_BYTE_AS_STRING,
&array_writer))
if (!dbus_message_iter_open_container (&writer, DBUS_TYPE_ARRAY, "{sv}",
&asv_writer))
goto oom;
if (!dbus_message_iter_append_fixed_array (&array_writer, DBUS_TYPE_BYTE,
&path, strlen (path) + 1))
{
dbus_message_iter_abandon_container (&writer, &array_writer);
goto oom;
}
if (!dbus_message_iter_close_container (&writer, &array_writer))
if (!_dbus_asv_add_string (&asv_writer, "Address", address))
goto oom;
if (!dbus_message_append_args (reply,
DBUS_TYPE_STRING, &address,
DBUS_TYPE_INVALID))
if (!_dbus_asv_add_byte_array (&asv_writer, "SocketPath",
path, strlen (path) + 1))
goto oom;
_dbus_assert (dbus_message_has_signature (reply, "oays"));
if (!dbus_message_iter_close_container (&writer, &asv_writer))
goto oom;
_dbus_assert (dbus_message_has_signature (reply, "oa{sv}"));
if (! bus_transaction_send_from_driver (transaction, connection, reply))
goto oom;
@ -988,6 +983,8 @@ oom:
BUS_SET_OOM (error);
/* fall through */
fail:
dbus_message_iter_abandon_container_if_open (&writer, &asv_writer);
if (server != NULL)
bus_container_server_stop_listening (server);

View file

@ -2647,7 +2647,7 @@ static const MessageHandler introspectable_message_handlers[] = {
#ifdef DBUS_ENABLE_CONTAINERS
static const MessageHandler containers_message_handlers[] = {
{ "AddServer", "sssa{sv}a{sv}", "oays", bus_containers_handle_add_server,
{ "AddServer", "sssa{sv}a{sv}", "oa{sv}", bus_containers_handle_add_server,
METHOD_FLAG_NO_CONTAINERS },
{ "StopServer", "o", "", bus_containers_handle_stop_server,
METHOD_FLAG_NO_CONTAINERS },

View file

@ -7489,8 +7489,7 @@
in DICT&lt;STRING,VARIANT&gt; metadata,
in DICT&lt;STRING,VARIANT&gt; named_arguments,
out OBJECT_PATH server_path,
out ARRAY&lt;BYTE&gt; socket_path,
out STRING connectable_address)
out DICT&lt;STRING,VARIANT&gt; results)
</programlisting>
Message arguments:
<informaltable>
@ -7571,21 +7570,10 @@
</row>
<row>
<entry>6</entry>
<entry>ARRAY&lt;BYTE&gt;</entry>
<entry>DICT&lt;STRING,VARIANT&gt;</entry>
<entry>
The absolute filesystem path of the resulting
<literal>AF_UNIX</literal> socket, followed by a single
zero (nul) byte, for example
<literal>/run/user/1000/dbus-12345vwxyz\x00</literal>
where \x00 represents the terminating zero byte.
</entry>
</row>
<row>
<entry>7</entry>
<entry>STRING</entry>
<entry>
A connectable D-Bus address, for example
<literal>unix:path=/run/user/1000/dbus-12345vwxyz</literal>.
Details of the container-specific server that was
created (see below).
</entry>
</row>
</tbody>
@ -7642,14 +7630,65 @@
extension point.
</para>
<para>
Keys in the returned result dictionary not containing "." are defined
by this specification. Bus daemon implementors wishing to emit
information not mentioned in this document should use keys
containing "." and starting with a reversed domain name.
Additional keys may be added to the result at any time, and
callers must accept and ignore unknown keys in this dictionary.
</para>
<para>
The defined keys for the result dictionary are:
<informaltable>
<tgroup cols="3">
<thead>
<row>
<entry>Key</entry>
<entry>Value type</entry>
<entry>Value</entry>
</row>
</thead>
<tbody>
<row>
<entry>Address</entry>
<entry>STRING</entry>
<entry>
A connectable D-Bus address, for example
<literal>unix:path=/run/user/1000/dbus-12345vwxyz</literal>.
</entry>
</row>
<row>
<entry>SocketPath</entry>
<entry>ARRAY of BYTE</entry>
<entry>
The absolute filesystem path of the resulting
<literal>AF_UNIX</literal> socket, followed by a single
zero (nul) byte, for example
<literal>/run/user/1000/dbus-12345vwxyz\x00</literal>
where \x00 represents the terminating zero byte.
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</para>
<para>
In the most basic form of a call to this method, the new server
socket is an <literal>AF_UNIX</literal> socket at a path chosen
by the message bus and returned from the method. Future versions
of this specification are likely to provide a way for the
message bus implementation to receive a socket from the caller
and arrange for it to listen for connections, using the named
arguments dictionary.
by the message bus and returned from the method.
When operating in this way, each successful call will return a
result dictionary containing both <literal>Address</literal> and
<literal>SocketPath</literal>.
Callers may use whichever of those members is more convenient.
If a future version of this specification adds a mechanism to
request that the server listens in some way that makes these two
members inapplicable, for example receiving a socket from the
caller in the named arguments dictionary via file descriptor passing
and arranging for it to listen for connections, then those members
will be omitted from the result dictionary.
</para>
<para>

View file

@ -309,7 +309,9 @@ add_container_server (Fixture *f,
GVariant *parameters)
{
GVariant *tuple;
GVariant *named_results;
GStatBuf stat_buf;
gboolean found;
f->proxy = g_dbus_proxy_new_sync (f->unconfined_conn,
G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
@ -339,22 +341,30 @@ add_container_server (Fixture *f,
g_assert_no_error (f->error);
g_assert_nonnull (tuple);
g_assert_cmpstr (g_variant_get_type_string (tuple), ==, "(oays)");
g_variant_get (tuple, "(o^ays)", &f->server_path, &f->socket_path,
&f->socket_dbus_address);
g_assert_cmpstr (g_variant_get_type_string (tuple), ==, "(oa{sv})");
g_variant_get (tuple, "(o@a{sv})", &f->server_path, &named_results);
g_assert_nonnull (f->server_path);
g_assert_true (g_variant_is_object_path (f->server_path));
found = g_variant_lookup (named_results, "Address",
"s", &f->socket_dbus_address);
g_assert_true (found);
g_assert_nonnull (f->socket_dbus_address);
g_assert_true (g_str_has_prefix (f->socket_dbus_address, "unix:"));
g_assert_null (strchr (f->socket_dbus_address, ';'));
g_assert_null (strchr (f->socket_dbus_address + strlen ("unix:"), ':'));
g_clear_pointer (&tuple, g_variant_unref);
g_assert_nonnull (f->server_path);
g_assert_true (g_variant_is_object_path (f->server_path));
found = g_variant_lookup (named_results, "SocketPath",
"^ay", &f->socket_path);
g_assert_true (found);
g_assert_nonnull (f->socket_path);
g_assert_true (g_path_is_absolute (f->socket_path));
g_assert_nonnull (f->socket_dbus_address);
g_assert_cmpstr (g_stat (f->socket_path, &stat_buf) == 0 ? NULL :
g_strerror (errno), ==, NULL);
g_assert_cmpuint ((stat_buf.st_mode & S_IFMT), ==, S_IFSOCK);
g_clear_pointer (&named_results, g_variant_unref);
g_clear_pointer (&tuple, g_variant_unref);
return TRUE;
}
#endif
@ -1394,7 +1404,7 @@ test_max_containers (Fixture *f,
NULL, &f->error);
g_assert_no_error (f->error);
g_assert_nonnull (tuple);
g_variant_get (tuple, "(o^ays)", &placeholders[i], NULL, NULL);
g_variant_get (tuple, "(o@a{sv})", &placeholders[i], NULL);
g_variant_unref (tuple);
g_test_message ("Placeholder server at %s", placeholders[i]);
}
@ -1475,7 +1485,6 @@ test_max_connections_per_container (Fixture *f,
* limit-containers.conf */
GSocket *placeholders[G_N_ELEMENTS (socket_paths) * 3] = { NULL };
GVariant *parameters;
GVariant *tuple;
guint i;
if (f->skip)
@ -1499,13 +1508,25 @@ test_max_connections_per_container (Fixture *f,
for (i = 0; i < G_N_ELEMENTS (socket_paths); i++)
{
GVariant *tuple;
GVariant *named_results;
gboolean found;
tuple = g_dbus_proxy_call_sync (f->proxy, "AddServer",
parameters, G_DBUS_CALL_FLAGS_NONE, -1,
NULL, &f->error);
g_assert_no_error (f->error);
g_assert_nonnull (tuple);
g_variant_get (tuple, "(o^ays)", NULL, &socket_paths[i],
&dbus_addresses[i]);
g_variant_get (tuple, "(o@a{sv})", NULL, &named_results);
found = g_variant_lookup (named_results, "Address",
"s", &dbus_addresses[i]);
g_assert_true (found);
found = g_variant_lookup (named_results, "SocketPath",
"^ay", &socket_paths[i]);
g_assert_true (found);
g_variant_unref (named_results);
g_variant_unref (tuple);
socket_addresses[i] = g_unix_socket_address_new (socket_paths[i]);
g_test_message ("Server #%u at %s", i, socket_paths[i]);