summaryrefslogtreecommitdiff
path: root/src/daemon/dbus/gsignond-dbus-server.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/daemon/dbus/gsignond-dbus-server.c')
-rw-r--r--src/daemon/dbus/gsignond-dbus-server.c411
1 files changed, 411 insertions, 0 deletions
diff --git a/src/daemon/dbus/gsignond-dbus-server.c b/src/daemon/dbus/gsignond-dbus-server.c
new file mode 100644
index 0000000..b5d2b1d
--- /dev/null
+++ b/src/daemon/dbus/gsignond-dbus-server.c
@@ -0,0 +1,411 @@
+/* vi: set et sw=4 ts=4 cino=t0,(0: */
+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of gsignond
+ *
+ * Copyright (C) 2012 Intel Corporation.
+ *
+ * Contact: Amarnath Valluri <amarnath.valluri@linux.intel.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+#include <errno.h>
+#include <string.h>
+#include <glib/gstdio.h>
+
+#include "config.h"
+
+#include "gsignond-dbus-server.h"
+#include "gsignond-dbus-auth-service-adapter.h"
+#include "gsignond-dbus.h"
+#include "gsignond/gsignond-log.h"
+#include <daemon/gsignond-daemon.h>
+
+enum
+{
+ PROP_0,
+
+ PROP_ADDRESS,
+ N_PROPERTIES
+};
+
+static GParamSpec *properties[N_PROPERTIES];
+
+struct _GSignondDbusServerPrivate
+{
+ GSignondDaemon *daemon;
+ GHashTable *auth_services;
+#ifdef USE_P2P
+ GDBusServer *bus_server;
+ gchar *address;
+#else
+ guint name_owner_id;
+#endif
+};
+
+G_DEFINE_TYPE (GSignondDbusServer, gsignond_dbus_server, G_TYPE_OBJECT)
+
+
+#define GSIGNOND_DBUS_SERVER_GET_PRIV(obj) \
+ G_TYPE_INSTANCE_GET_PRIVATE ((obj), GSIGNOND_TYPE_DBUS_SERVER, GSignondDbusServerPrivate)
+
+#ifdef USE_P2P
+static void _on_connection_closed (GDBusConnection *connection,
+ gboolean remote_peer_vanished,
+ GError *error,
+ gpointer user_data);
+#endif
+
+static void
+_set_property (GObject *object,
+ guint property_id,
+ const GValue *value, GParamSpec *pspec)
+{
+ GSignondDbusServer *self = GSIGNOND_DBUS_SERVER (object);
+
+ switch (property_id) {
+ case PROP_ADDRESS: {
+#ifdef USE_P2P
+ self->priv->address = g_value_dup_string (value);
+#else
+ (void)self;
+#endif
+ break;
+ }
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
+static void
+_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GSignondDbusServer *self = GSIGNOND_DBUS_SERVER (object);
+
+ switch (property_id) {
+ case PROP_ADDRESS: {
+#ifdef USE_P2P
+ g_value_set_string (value, g_dbus_server_get_client_address (
+ self->priv->bus_server));
+#else
+ (void) self;
+ g_value_set_string (value, NULL);
+#endif
+ break;
+ }
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
+#ifdef USE_P2P
+static void
+_clear_connection (gpointer connection, gpointer value, gpointer userdata)
+{
+ (void) value;
+ g_signal_handlers_disconnect_by_func (connection, _on_connection_closed, userdata);
+}
+#endif
+
+static void
+_dispose (GObject *object)
+{
+ GSignondDbusServer *self = GSIGNOND_DBUS_SERVER (object);
+
+ if (self->priv->auth_services) {
+#ifdef USE_P2P
+ g_hash_table_foreach (self->priv->auth_services, _clear_connection, self);
+#endif
+ g_hash_table_unref (self->priv->auth_services);
+ self->priv->auth_services = NULL;
+ }
+#ifdef USE_P2P
+ if (self->priv->bus_server) {
+ if (g_dbus_server_is_active (self->priv->bus_server))
+ g_dbus_server_stop (self->priv->bus_server);
+ g_object_unref (self->priv->bus_server);
+ self->priv->bus_server = NULL;
+ }
+#else
+ if (self->priv->name_owner_id) {
+ g_bus_unown_name (self->priv->name_owner_id);
+ self->priv->name_owner_id = 0;
+ }
+#endif
+
+ if (self->priv->daemon) {
+ g_object_unref (self->priv->daemon);
+ self->priv->daemon = NULL;
+ }
+
+ G_OBJECT_CLASS (gsignond_dbus_server_parent_class)->dispose (object);
+}
+
+static void
+_finalize (GObject *object)
+{
+#ifdef USE_P2P
+ GSignondDbusServer *self = GSIGNOND_DBUS_SERVER (object);
+ if (self->priv->address && g_str_has_prefix (self->priv->address, "unix:path=")) {
+ const gchar *path = g_strstr_len(self->priv->address, -1, "unix:path=") + 10;
+ if (path) {
+ g_unlink (path);
+ }
+ g_free (self->priv->address);
+ self->priv->address = NULL;
+ }
+#endif
+ G_OBJECT_CLASS (gsignond_dbus_server_parent_class)->finalize (object);
+}
+
+static void
+gsignond_dbus_server_class_init (GSignondDbusServerClass *klass)
+{
+ GObjectClass* object_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (object_class, sizeof (GSignondDbusServerPrivate));
+
+ object_class->get_property = _get_property;
+ object_class->set_property = _set_property;
+ object_class->dispose = _dispose;
+ object_class->finalize = _finalize;
+
+ properties[PROP_ADDRESS] = g_param_spec_string ("address",
+ "server address",
+ "Server socket address",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, N_PROPERTIES, properties);
+}
+
+static void
+gsignond_dbus_server_init (GSignondDbusServer *self)
+{
+ self->priv = GSIGNOND_DBUS_SERVER_GET_PRIV(self);
+#ifdef USE_P2P
+ self->priv->bus_server = NULL;
+ self->priv->address = NULL;
+#else
+ self->priv->name_owner_id = 0;
+#endif
+ self->priv->daemon = gsignond_daemon_new ();
+ self->priv->auth_services = g_hash_table_new_full (
+ g_direct_hash, g_direct_equal, NULL, g_object_unref);
+}
+
+const gchar *
+gsignond_dbus_server_get_address (GSignondDbusServer *server)
+{
+ g_return_val_if_fail (server || GSIGNOND_IS_DBUS_SERVER (server), NULL);
+#ifdef USE_P2P
+ return g_dbus_server_get_client_address (server->priv->bus_server);
+#else
+ return NULL;
+#endif
+}
+
+static gboolean
+_compare_auth_service_by_pointer (gpointer key, gpointer value, gpointer dead_object)
+{
+ return value == dead_object;
+}
+
+#ifdef USE_P2P
+static void
+_on_connection_closed (GDBusConnection *connection,
+ gboolean remote_peer_vanished,
+ GError *error,
+ gpointer user_data)
+{
+ GSignondDbusServer *server = GSIGNOND_DBUS_SERVER (user_data);
+
+ g_signal_handlers_disconnect_by_func (connection, _on_connection_closed, user_data);
+ DBG("dbus connection(%p) closed (peer vanished : %d)", connection, remote_peer_vanished);
+ if (error) {
+ DBG("...reason : %s", error->message);
+ }
+ g_hash_table_remove (server->priv->auth_services, connection);
+}
+#else
+
+static gboolean
+_close_server (gpointer data)
+{
+ g_object_unref (data);
+ return FALSE;
+}
+#endif
+
+static void
+_on_auth_service_dispose (gpointer data, GObject *dead_service)
+{
+ GSignondDbusServer *server = GSIGNOND_DBUS_SERVER (data);
+
+ g_return_if_fail (server);
+
+ g_hash_table_foreach_steal (server->priv->auth_services,
+ _compare_auth_service_by_pointer, dead_service);
+#ifndef USE_P2P
+ /* close server if using message bus */
+ if (g_hash_table_size(server->priv->auth_services) == 0)
+ g_idle_add (_close_server, data);
+#endif
+}
+
+void
+gsignond_dbus_server_start_auth_service (GSignondDbusServer *server, GDBusConnection *connection)
+{
+ GSignondDbusAuthServiceAdapter *auth_service = NULL;
+
+ DBG("Starting authentication service on connection %p", connection);
+
+ auth_service = gsignond_dbus_auth_service_adapter_new_with_connection (
+ g_object_ref (connection), g_object_ref (server->priv->daemon));
+
+ g_hash_table_insert (server->priv->auth_services, connection, auth_service);
+#ifdef USE_P2P
+ g_signal_connect (connection, "closed", G_CALLBACK(_on_connection_closed), server);
+#endif
+ g_object_weak_ref (G_OBJECT (auth_service), _on_auth_service_dispose, server);
+}
+
+#ifdef USE_P2P
+static gboolean
+_on_client_request (GDBusServer *dbus_server, GDBusConnection *connection, gpointer userdata)
+{
+ GSignondDbusServer *server = GSIGNOND_DBUS_SERVER(userdata);
+
+ if (!server) {
+ ERR ("memory corruption");
+ return TRUE;
+ }
+
+ gsignond_dbus_server_start_auth_service (server, connection);
+
+ return TRUE;
+}
+
+GSignondDbusServer * gsignond_dbus_server_new_with_address (const gchar *address)
+{
+ GError *err = NULL;
+ gchar *guid = 0;
+ const gchar *file_path = NULL;
+ GSignondDbusServer *server = GSIGNOND_DBUS_SERVER (
+ g_object_new (GSIGNOND_TYPE_DBUS_SERVER, "address", address, NULL));
+
+ if (!server) return NULL;
+
+ if (g_str_has_prefix(address, "unix:path=")) {
+ file_path = g_strstr_len (address, -1, "unix:path=") + 10;
+
+ if (g_file_test(file_path, G_FILE_TEST_EXISTS)) {
+ g_unlink (file_path);
+ }
+ else {
+ gchar *base_path = g_path_get_dirname (file_path);
+ if (g_mkdir_with_parents (base_path, S_IRUSR | S_IWUSR | S_IXUSR) == -1) {
+ WARN ("Could not create '%s', error: %s", base_path, strerror(errno));
+ }
+ g_free (base_path);
+ }
+ }
+
+ guid = g_dbus_generate_guid ();
+
+ server->priv->bus_server = g_dbus_server_new_sync (server->priv->address,
+ G_DBUS_SERVER_FLAGS_NONE, guid, NULL, NULL, &err);
+
+ g_free (guid);
+
+ if (!server->priv->bus_server) {
+ ERR ("failed to start server at address '%s':%s", server->priv->address,
+ err->message);
+ g_error_free (err);
+
+ g_object_unref (server);
+
+ return NULL;
+ }
+
+ g_signal_connect (server->priv->bus_server, "new-connection", G_CALLBACK(_on_client_request), server);
+
+ g_dbus_server_start (server->priv->bus_server);
+
+ if (file_path)
+ g_chmod (file_path, S_IRUSR | S_IWUSR);
+
+ return server;
+}
+
+GSignondDbusServer * gsignond_dbus_server_new () {
+ GSignondDbusServer *server = NULL;
+ gchar *address = g_strdup_printf (GSIGNOND_DBUS_ADDRESS, g_get_user_runtime_dir());
+
+ server = gsignond_dbus_server_new_with_address (address);
+ g_free (address);
+
+ return server ;
+}
+#else
+
+static void
+_on_bus_acquired (GDBusConnection *connection,
+ const gchar *name,
+ gpointer user_data)
+{
+ INFO ("bus aquired on connection '%p'", connection);
+}
+
+static void
+_on_name_lost (GDBusConnection *connection,
+ const gchar *name,
+ gpointer user_data)
+{
+ INFO ("Lost (or failed to acquire) the name '%s' on the on bus connection '%p'", name, connection);
+ if (user_data) g_object_unref (G_OBJECT (user_data));
+}
+
+static void
+_on_name_acquired (GDBusConnection *connection,
+ const gchar *name,
+ gpointer user_data)
+{
+ GSignondDbusServer *server = GSIGNOND_DBUS_SERVER (user_data);
+ INFO ("Acquired the name %s on connection '%p'", name, connection);
+ gsignond_dbus_server_start_auth_service (server, connection);
+}
+
+GSignondDbusServer * gsignond_dbus_server_new () {
+ GSignondDbusServer *server = GSIGNOND_DBUS_SERVER (
+ g_object_new (GSIGNOND_TYPE_DBUS_SERVER, NULL));
+
+ server->priv->name_owner_id = g_bus_own_name (GSIGNOND_BUS_TYPE,
+ GSIGNOND_SERVICE,
+ G_BUS_NAME_OWNER_FLAGS_REPLACE,
+ _on_bus_acquired,
+ _on_name_acquired,
+ _on_name_lost,
+ server, NULL);
+
+ return server;
+}
+#endif