summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon McVittie <smcv@collabora.com>2017-06-20 12:31:18 +0100
committerSimon McVittie <smcv@collabora.com>2017-12-11 15:58:19 +0000
commit7cd2354b993366f0b45b19cced9d220d9f336c39 (patch)
tree16f327d3da20d6ece00169eb7e2a02b96fc4c6cb
parente65d6cf1ef74969b72ec3a4363aba1545109f409 (diff)
bus/containers: Build a global data structure for container instances
We still don't actually create a DBusServer for incoming connections at this point, much less accept incoming connections. Signed-off-by: Simon McVittie <smcv@collabora.com> Reviewed-by: Philip Withnall <withnall@endlessm.com> Bug: https://bugs.freedesktop.org/show_bug.cgi?id=101354
-rw-r--r--bus/bus.c17
-rw-r--r--bus/bus.h2
-rw-r--r--bus/containers.c240
-rw-r--r--bus/containers.h12
4 files changed, 268 insertions, 3 deletions
diff --git a/bus/bus.c b/bus/bus.c
index 295dc7b5..8b08b8ea 100644
--- a/bus/bus.c
+++ b/bus/bus.c
@@ -29,6 +29,7 @@
#include "activation.h"
#include "connection.h"
+#include "containers.h"
#include "services.h"
#include "utils.h"
#include "policy.h"
@@ -69,6 +70,7 @@ struct BusContext
BusMatchmaker *matchmaker;
BusLimits limits;
DBusRLimit *initial_fd_limit;
+ BusContainers *containers;
unsigned int fork : 1;
unsigned int syslog : 1;
unsigned int keep_umask : 1;
@@ -887,6 +889,14 @@ bus_context_new (const DBusString *config_file,
goto failed;
}
+ context->containers = bus_containers_new ();
+
+ if (context->containers == NULL)
+ {
+ BUS_SET_OOM (error);
+ goto failed;
+ }
+
/* check user before we fork */
if (context->user != NULL)
{
@@ -1172,6 +1182,7 @@ bus_context_unref (BusContext *context)
context->matchmaker = NULL;
}
+ bus_clear_containers (&context->containers);
dbus_free (context->config_file);
dbus_free (context->log_prefix);
dbus_free (context->type);
@@ -1282,6 +1293,12 @@ bus_context_get_policy (BusContext *context)
return context->policy;
}
+BusContainers *
+bus_context_get_containers (BusContext *context)
+{
+ return context->containers;
+}
+
BusClientPolicy*
bus_context_create_client_policy (BusContext *context,
DBusConnection *connection,
diff --git a/bus/bus.h b/bus/bus.h
index 647f9988..edc95773 100644
--- a/bus/bus.h
+++ b/bus/bus.h
@@ -45,6 +45,7 @@ typedef struct BusTransaction BusTransaction;
typedef struct BusMatchmaker BusMatchmaker;
typedef struct BusMatchRule BusMatchRule;
typedef struct BusActivationEntry BusActivationEntry;
+typedef struct BusContainers BusContainers;
typedef struct
{
@@ -106,6 +107,7 @@ dbus_bool_t bus_context_allow_unix_user (BusContext
dbus_bool_t bus_context_allow_windows_user (BusContext *context,
const char *windows_sid);
BusPolicy* bus_context_get_policy (BusContext *context);
+BusContainers *bus_context_get_containers (BusContext *context);
BusClientPolicy* bus_context_create_client_policy (BusContext *context,
DBusConnection *connection,
diff --git a/bus/containers.c b/bus/containers.c
index cf9156f4..1c922952 100644
--- a/bus/containers.c
+++ b/bus/containers.c
@@ -23,15 +23,185 @@
#include <config.h>
#include "containers.h"
+#include "dbus/dbus-internals.h"
+
#ifdef DBUS_ENABLE_CONTAINERS
#ifndef DBUS_UNIX
# error DBUS_ENABLE_CONTAINERS requires DBUS_UNIX
#endif
-#include "dbus/dbus-internals.h"
+#include "dbus/dbus-hash.h"
+#include "dbus/dbus-message-internal.h"
#include "dbus/dbus-sysdeps-unix.h"
+#include "connection.h"
+#include "utils.h"
+
+/*
+ * A container instance groups together a per-app-container server with
+ * all the connections for which it is responsible.
+ */
+typedef struct
+{
+ int refcount;
+ char *path;
+ char *type;
+ char *name;
+ DBusVariant *metadata;
+ BusContext *context;
+ BusContainers *containers;
+} BusContainerInstance;
+
+/*
+ * Singleton data structure encapsulating the container-related parts of
+ * a BusContext.
+ */
+struct BusContainers
+{
+ int refcount;
+ /* path borrowed from BusContainerInstance => unowned BusContainerInstance
+ * The BusContainerInstance removes itself from here on destruction. */
+ DBusHashTable *instances_by_path;
+ dbus_uint64_t next_container_id;
+};
+
+BusContainers *
+bus_containers_new (void)
+{
+ /* We allocate the hash table lazily, expecting that the common case will
+ * be a connection where this feature is never used */
+ BusContainers *self = dbus_new0 (BusContainers, 1);
+
+ if (self == NULL)
+ return NULL;
+
+ self->refcount = 1;
+ self->instances_by_path = NULL;
+ self->next_container_id = DBUS_UINT64_CONSTANT (0);
+ return self;
+}
+
+BusContainers *
+bus_containers_ref (BusContainers *self)
+{
+ _dbus_assert (self->refcount > 0);
+ _dbus_assert (self->refcount < _DBUS_INT_MAX);
+
+ self->refcount++;
+ return self;
+}
+
+void
+bus_containers_unref (BusContainers *self)
+{
+ _dbus_assert (self != NULL);
+ _dbus_assert (self->refcount > 0);
+
+ if (--self->refcount == 0)
+ {
+ _dbus_clear_hash_table (&self->instances_by_path);
+ dbus_free (self);
+ }
+}
+
+static void
+bus_container_instance_unref (BusContainerInstance *self)
+{
+ _dbus_assert (self->refcount > 0);
+
+ if (--self->refcount == 0)
+ {
+ /* It's OK to do this even if we were never added to instances_by_path,
+ * because the paths are globally unique. */
+ if (self->path != NULL && self->containers->instances_by_path != NULL)
+ _dbus_hash_table_remove_string (self->containers->instances_by_path,
+ self->path);
+
+ _dbus_clear_variant (&self->metadata);
+ bus_context_unref (self->context);
+ bus_containers_unref (self->containers);
+ dbus_free (self->path);
+ dbus_free (self->type);
+ dbus_free (self->name);
+ dbus_free (self);
+ }
+}
+
+static inline void
+bus_clear_container_instance (BusContainerInstance **instance_p)
+{
+ _dbus_clear_pointer_impl (BusContainerInstance, instance_p,
+ bus_container_instance_unref);
+}
+
+static BusContainerInstance *
+bus_container_instance_new (BusContext *context,
+ BusContainers *containers,
+ DBusError *error)
+{
+ BusContainerInstance *self = NULL;
+ DBusString path = _DBUS_STRING_INIT_INVALID;
+
+ _dbus_assert (context != NULL);
+ _dbus_assert (containers != NULL);
+ _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+
+ if (!_dbus_string_init (&path))
+ {
+ BUS_SET_OOM (error);
+ goto fail;
+ }
+
+ self = dbus_new0 (BusContainerInstance, 1);
+
+ if (self == NULL)
+ {
+ BUS_SET_OOM (error);
+ goto fail;
+ }
+
+ self->refcount = 1;
+ self->type = NULL;
+ self->name = NULL;
+ self->metadata = NULL;
+ self->context = bus_context_ref (context);
+ self->containers = bus_containers_ref (containers);
+
+ if (containers->next_container_id >=
+ DBUS_UINT64_CONSTANT (0xFFFFFFFFFFFFFFFF))
+ {
+ /* We can't increment it any further without wrapping around */
+ dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
+ "Too many containers created during the lifetime of "
+ "this bus");
+ goto fail;
+ }
+
+ /* We assume PRIu64 exists on all Unix platforms: it's ISO C99, and the
+ * only non-C99 platform we support is MSVC on Windows. */
+ if (!_dbus_string_append_printf (&path,
+ "/org/freedesktop/DBus/Containers1/c%" PRIu64,
+ containers->next_container_id++))
+ {
+ BUS_SET_OOM (error);
+ goto fail;
+ }
+
+ if (!_dbus_string_steal_data (&path, &self->path))
+ goto fail;
+
+ return self;
+
+fail:
+ _dbus_string_free (&path);
+
+ if (self != NULL)
+ bus_container_instance_unref (self);
+
+ return NULL;
+}
+
dbus_bool_t
bus_containers_handle_add_server (DBusConnection *connection,
BusTransaction *transaction,
@@ -42,6 +212,17 @@ bus_containers_handle_add_server (DBusConnection *connection,
DBusMessageIter dict_iter;
const char *type;
const char *name;
+ BusContainerInstance *instance = NULL;
+ BusContext *context;
+ BusContainers *containers;
+
+ context = bus_transaction_get_context (transaction);
+ containers = bus_context_get_containers (context);
+
+ instance = bus_container_instance_new (context, containers, error);
+
+ if (instance == NULL)
+ goto fail;
/* We already checked this in bus_driver_handle_message() */
_dbus_assert (dbus_message_has_signature (message, "ssa{sv}a{sv}"));
@@ -52,6 +233,10 @@ bus_containers_handle_add_server (DBusConnection *connection,
_dbus_assert (dbus_message_iter_get_arg_type (&iter) == DBUS_TYPE_STRING);
dbus_message_iter_get_basic (&iter, &type);
+ instance->type = _dbus_strdup (type);
+
+ if (instance->type == NULL)
+ goto oom;
if (!dbus_validate_interface (type, NULL))
{
@@ -67,13 +252,19 @@ bus_containers_handle_add_server (DBusConnection *connection,
_dbus_assert (dbus_message_iter_get_arg_type (&iter) == DBUS_TYPE_STRING);
dbus_message_iter_get_basic (&iter, &name);
+ instance->name = _dbus_strdup (name);
+
+ if (instance->name == NULL)
+ goto oom;
/* Argument 2: Metadata as defined by container manager */
if (!dbus_message_iter_next (&iter))
_dbus_assert_not_reached ("Message type was already checked");
_dbus_assert (dbus_message_iter_get_arg_type (&iter) == DBUS_TYPE_ARRAY);
- /* TODO: Copy the metadata */
+ instance->metadata = _dbus_variant_read (&iter);
+ _dbus_assert (strcmp (_dbus_variant_get_signature (instance->metadata),
+ "a{sv}") == 0);
/* Argument 3: Named parameters */
if (!dbus_message_iter_next (&iter))
@@ -95,7 +286,7 @@ bus_containers_handle_add_server (DBusConnection *connection,
DBUS_TYPE_STRING);
dbus_message_iter_get_basic (&pair_iter, &param_name);
- /* If we supported any named parameters, we'd copy them into a data
+ /* If we supported any named parameters, we'd copy them into the data
* structure here; but we don't, so fail instead. */
dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
"Named parameter %s is not understood", param_name);
@@ -105,10 +296,29 @@ bus_containers_handle_add_server (DBusConnection *connection,
/* End of arguments */
_dbus_assert (!dbus_message_iter_has_next (&iter));
+ if (containers->instances_by_path == NULL)
+ {
+ containers->instances_by_path = _dbus_hash_table_new (DBUS_HASH_STRING,
+ NULL, NULL);
+
+ if (containers->instances_by_path == NULL)
+ goto oom;
+ }
+
+ if (!_dbus_hash_table_insert_string (containers->instances_by_path,
+ instance->path, instance))
+ goto oom;
+
/* TODO: Actually implement the method */
dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED, "Not yet implemented");
+ goto fail;
+oom:
+ BUS_SET_OOM (error);
+ /* fall through */
fail:
+
+ bus_clear_container_instance (&instance);
return FALSE;
}
@@ -125,4 +335,28 @@ bus_containers_supported_arguments_getter (BusContext *context,
dbus_message_iter_close_container (var_iter, &arr_iter);
}
+#else
+
+BusContainers *
+bus_containers_new (void)
+{
+ /* Return an arbitrary non-NULL pointer just to indicate that we didn't
+ * fail. There is no valid operation to do with it on this platform,
+ * other than unreffing it, which does nothing. */
+ return (BusContainers *) 1;
+}
+
+BusContainers *
+bus_containers_ref (BusContainers *self)
+{
+ _dbus_assert (self == (BusContainers *) 1);
+ return self;
+}
+
+void
+bus_containers_unref (BusContainers *self)
+{
+ _dbus_assert (self == (BusContainers *) 1);
+}
+
#endif /* DBUS_ENABLE_CONTAINERS */
diff --git a/bus/containers.h b/bus/containers.h
index 3564bbd2..bda0a879 100644
--- a/bus/containers.h
+++ b/bus/containers.h
@@ -25,6 +25,12 @@
#include "bus.h"
+#include <dbus/dbus-macros.h>
+
+BusContainers *bus_containers_new (void);
+BusContainers *bus_containers_ref (BusContainers *self);
+void bus_containers_unref (BusContainers *self);
+
dbus_bool_t bus_containers_handle_add_server (DBusConnection *connection,
BusTransaction *transaction,
DBusMessage *message,
@@ -32,4 +38,10 @@ dbus_bool_t bus_containers_handle_add_server (DBusConnection *connecti
dbus_bool_t bus_containers_supported_arguments_getter (BusContext *context,
DBusMessageIter *var_iter);
+static inline void
+bus_clear_containers (BusContainers **containers_p)
+{
+ _dbus_clear_pointer_impl (BusContainers, containers_p, bus_containers_unref);
+}
+
#endif /* multiple-inclusion guard */