session: Refactor session API
authorDaniel Wagner <daniel.wagner@bmw-carit.de>
Thu, 31 Mar 2011 10:36:12 +0000 (12:36 +0200)
committerSamuel Ortiz <sameo@linux.intel.com>
Thu, 31 Mar 2011 10:36:12 +0000 (12:36 +0200)
Refactor the D-Bus API of the session according the documentation.
All function and properties are only empty stubs.

include/dbus.h
src/connman-dbus.conf
src/connman.h
src/manager.c
src/session.c

index 9be76b2..83f3d30 100644 (file)
@@ -44,6 +44,8 @@ extern "C" {
 #define CONNMAN_SERVICE_INTERFACE      CONNMAN_SERVICE ".Service"
 #define CONNMAN_PROVIDER_INTERFACE     CONNMAN_SERVICE ".Provider"
 #define CONNMAN_TECHNOLOGY_INTERFACE   CONNMAN_SERVICE ".Technology"
+#define CONNMAN_SESSION_INTERFACE      CONNMAN_SERVICE ".Session"
+#define CONNMAN_NOTIFICATION_INTERFACE CONNMAN_SERVICE ".Notification"
 
 #define CONNMAN_PRIVILEGE_MODIFY       1
 #define CONNMAN_PRIVILEGE_SECRET       2
index 311f28c..98a773e 100644 (file)
@@ -6,6 +6,7 @@
         <allow send_destination="net.connman"/>
         <allow send_interface="net.connman.Agent"/>
         <allow send_interface="net.connman.Counter"/>
+        <allow send_interface="net.connman.Notification"/>
     </policy>
     <policy at_console="true">
         <allow send_destination="net.connman"/>
index 4196127..bb08267 100644 (file)
@@ -610,8 +610,10 @@ int __connman_rtnl_send(const void *buf, size_t len);
 
 connman_bool_t __connman_session_mode();
 void __connman_session_set_mode(connman_bool_t enable);
-int __connman_session_release(const char *owner);
-struct connman_service *__connman_session_request(const char *bearer, const char *owner);
+
+int __connman_session_create(DBusMessage *msg);
+int __connman_session_destroy(DBusMessage *msg);
+
 int __connman_session_init(void);
 void __connman_session_cleanup(void);
 
index 198875d..349ddb4 100644 (file)
@@ -589,40 +589,28 @@ static DBusMessage *unregister_counter(DBusConnection *conn,
        return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
 }
 
-static DBusMessage *request_session(DBusConnection *conn,
+static DBusMessage *create_session(DBusConnection *conn,
                                        DBusMessage *msg, void *data)
 {
-       const char *bearer, *sender, *service_path;
-       struct connman_service *service;
+       int err;
 
        DBG("conn %p", conn);
 
-       sender = dbus_message_get_sender(msg);
-
-       dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &bearer,
-                                                       DBUS_TYPE_INVALID);
-
-       service = __connman_session_request(bearer, sender);
-       if (service == NULL)
-               return __connman_error_failed(msg, EINVAL);
-
-       service_path = __connman_service_get_path(service);
+       err = __connman_session_create(msg);
+       if (err < 0)
+               return __connman_error_failed(msg, -err);
 
-       return g_dbus_create_reply(msg, DBUS_TYPE_OBJECT_PATH, &service_path,
-                                               DBUS_TYPE_INVALID);
+       return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
 }
 
-static DBusMessage *release_session(DBusConnection *conn,
+static DBusMessage *destroy_session(DBusConnection *conn,
                                        DBusMessage *msg, void *data)
 {
-       const char *sender;
        int err;
 
        DBG("conn %p", conn);
 
-       sender = dbus_message_get_sender(msg);
-
-       err = __connman_session_release(sender);
+       err = __connman_session_destroy(msg);
        if (err < 0)
                return __connman_error_failed(msg, -err);
 
@@ -651,8 +639,8 @@ static GDBusMethodTable manager_methods[] = {
        { "UnregisterAgent",   "o",     "",      unregister_agent   },
        { "RegisterCounter",   "ouu",   "",      register_counter   },
        { "UnregisterCounter", "o",     "",      unregister_counter },
-       { "RequestSession",    "s",     "o",     request_session    },
-       { "ReleaseSession",    "s",     "",      release_session    },
+       { "CreateSession",     "a{sv}o", "o",    create_session     },
+       { "DestroySession",    "o",     "",      destroy_session    },
        { },
 };
 
index 391899f..1540d6b 100644 (file)
@@ -3,6 +3,7 @@
  *  Connection Manager
  *
  *  Copyright (C) 2007-2010  Intel Corporation. All rights reserved.
+ *  Copyright (C) 2011  BWM CarIT GmbH. All rights reserved.
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License version 2 as
 #include <config.h>
 #endif
 
-#include <string.h>
-
 #include <gdbus.h>
 
 #include "connman.h"
 
 static DBusConnection *connection;
 static GHashTable *session_hash;
-static GHashTable *bearer_hash;
 static connman_bool_t sessionmode;
 
-struct connman_bearer {
-       gint refcount;
-       char *name;
-};
-
 struct connman_session {
-       gint refcount;
        char *owner;
-       guint watch;
-       struct connman_bearer *bearer;
-       struct connman_service *service;
+       char *session_path;
+       char *notify_path;
+       guint notify_watch;
 };
 
-static enum connman_service_type bearer2service(const char *bearer)
-{
-       if (bearer == NULL)
-               return CONNMAN_SERVICE_TYPE_UNKNOWN;
-
-       DBG("%s", bearer);
-
-       if (g_strcmp0(bearer, "ethernet") == 0)
-               return CONNMAN_SERVICE_TYPE_ETHERNET;
-       else if (g_strcmp0(bearer, "wifi") == 0)
-               return CONNMAN_SERVICE_TYPE_WIFI;
-       else if (g_strcmp0(bearer, "wimax") == 0)
-               return CONNMAN_SERVICE_TYPE_WIMAX;
-       else if (g_strcmp0(bearer, "bluetooth") == 0)
-               return CONNMAN_SERVICE_TYPE_BLUETOOTH;
-       else if (g_strcmp0(bearer, "3g") == 0)
-               return CONNMAN_SERVICE_TYPE_CELLULAR;
-       else
-               return CONNMAN_SERVICE_TYPE_UNKNOWN;
-}
-
-static char *service2bearer(enum connman_service_type type)
+static gboolean session_notify_all(gpointer user_data)
 {
-       DBG("%d", type);
-
-       switch (type) {
-       case CONNMAN_SERVICE_TYPE_ETHERNET:
-               return "ethernet";
-       case CONNMAN_SERVICE_TYPE_WIFI:
-               return "wifi";
-       case CONNMAN_SERVICE_TYPE_WIMAX:
-               return "wimax";
-       case CONNMAN_SERVICE_TYPE_BLUETOOTH:
-               return "bluetooth";
-       case CONNMAN_SERVICE_TYPE_CELLULAR:
-               return "3g";
-       case CONNMAN_SERVICE_TYPE_UNKNOWN:
-       case CONNMAN_SERVICE_TYPE_SYSTEM:
-       case CONNMAN_SERVICE_TYPE_GPS:
-       case CONNMAN_SERVICE_TYPE_VPN:
-       case CONNMAN_SERVICE_TYPE_GADGET:
-               return NULL;
+       struct connman_session *session = user_data;
+       DBusMessage *msg;
+       DBusMessageIter array, dict;
+
+       DBG("session %p owner %s notify_path %s", session,
+               session->owner, session->notify_path);
+
+       msg = dbus_message_new_method_call(session->owner, session->notify_path,
+                                               CONNMAN_NOTIFICATION_INTERFACE,
+                                               "Update");
+       if (msg == NULL) {
+               connman_error("Could not create notification message");
+               return FALSE;
        }
 
-       return NULL;
-}
+       dbus_message_iter_init_append(msg, &array);
 
-static void remove_bearer(gpointer user_data)
-{
-       struct connman_bearer *bearer = user_data;
+       connman_dbus_dict_open(&array, &dict);
+
+       /* append settings */
 
-       g_free(bearer->name);
-       g_free(bearer);
+       connman_dbus_dict_close(&array, &dict);
+
+       g_dbus_send_message(connection, msg);
+
+       return FALSE;
 }
 
-static void remove_session(gpointer user_data)
+static void cleanup_session(gpointer user_data)
 {
        struct connman_session *session = user_data;
 
-       session->bearer = NULL;
-       if (session->service)
-               connman_service_unref(session->service);
+       DBG("remove %s", session->session_path);
+
        g_free(session->owner);
+       g_free(session->session_path);
+       g_free(session->notify_path);
+
        g_free(session);
 }
 
-static int session_disconnect(struct connman_session *session)
+static void release_session(gpointer key, gpointer value, gpointer user_data)
 {
-       struct connman_bearer *bearer = session->bearer;
+       struct connman_session *session = value;
+       DBusMessage *message;
 
-       DBG("%s", session->owner);
+       DBG("owner %s path %s", session->owner, session->notify_path);
 
-       if (session == NULL)
-               return -EINVAL;
+       if (session->notify_watch > 0)
+               g_dbus_remove_watch(connection, session->notify_watch);
 
-       /*
-        * Once a bearer is no longer referenced we actually disconnect
-        * the corresponding service.
-        */
-       if (bearer == NULL || g_atomic_int_dec_and_test(&bearer->refcount)) {
-               struct connman_network *network;
-               struct connman_device *device;
-
-               /*
-                * We toggle the reconnect flag to false when releasing a
-                * session. This way a previously connected service will
-                * not autoconnect once we've completely release a session.
-                */
-               network = __connman_service_get_network(session->service);
-               if (network == NULL)
-                       return -EINVAL;
-
-               device = connman_network_get_device(network);
-               if (device == NULL)
-                       return -EINVAL;
-
-               __connman_device_set_reconnect(device, FALSE);
-
-               __connman_service_disconnect(session->service);
-               connman_service_unref(session->service);
-
-               g_hash_table_remove(bearer_hash, bearer);
-       }
+       g_dbus_unregister_interface(connection, session->session_path,
+                                               CONNMAN_SESSION_INTERFACE);
+
+       message = dbus_message_new_method_call(session->owner,
+                                               session->notify_path,
+                                               CONNMAN_NOTIFICATION_INTERFACE,
+                                               "Release");
+       if (message == NULL)
+               return;
 
-       if (session->watch > 0)
-               g_dbus_remove_watch(connection, session->watch);
+       dbus_message_set_no_reply(message, TRUE);
 
-       g_hash_table_remove(session_hash, session);
+       g_dbus_send_message(connection, message);
+}
+
+static int session_disconnect(struct connman_session *session)
+{
+       DBG("session %p, %s", session, session->owner);
+
+       if (session->notify_watch > 0)
+               g_dbus_remove_watch(connection, session->notify_watch);
+
+       g_dbus_unregister_interface(connection, session->session_path,
+                                               CONNMAN_SESSION_INTERFACE);
+
+       g_hash_table_remove(session_hash, session->session_path);
 
        return 0;
 }
 
-static void owner_disconnect(DBusConnection *connection, void *user_data)
+static void owner_disconnect(DBusConnection *conn, void *user_data)
 {
        struct connman_session *session = user_data;
 
-       DBG("%s died", session->owner);
+       DBG("session %p, %s died", session, session->owner);
 
        session_disconnect(session);
 }
 
-int __connman_session_release(const char *owner)
+static DBusMessage *destroy_session(DBusConnection *conn,
+                                       DBusMessage *msg, void *user_data)
 {
-       struct connman_session *session;
+       struct connman_session *session = user_data;
 
-       DBG("owner %s", owner);
+       DBG("session %p", session);
 
-       session = g_hash_table_lookup(session_hash, owner);
-       if (session == NULL)
-               return -EINVAL;
+       return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static DBusMessage *connect_session(DBusConnection *conn,
+                                       DBusMessage *msg, void *user_data)
+{
+       struct connman_session *session = user_data;
 
-       if (g_atomic_int_dec_and_test(&session->refcount))
-               return session_disconnect(session);
+       DBG("session %p", session);
 
-       return 0;
+       return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static DBusMessage *disconnect_session(DBusConnection *conn,
+                                       DBusMessage *msg, void *user_data)
+{
+       struct connman_session *session = user_data;
+
+       DBG("session %p", session);
+
+       return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static DBusMessage *change_session(DBusConnection *conn,
+                                       DBusMessage *msg, void *user_data)
+{
+       struct connman_session *session = user_data;
+
+       DBG("session %p", session);
+
+       return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
 }
 
-struct connman_service *__connman_session_request(const char *bearer_name,
-                                                       const char *owner)
+static GDBusMethodTable session_methods[] = {
+       { "Destroy",    "",   "", destroy_session    },
+       { "Connect",    "",   "", connect_session    },
+       { "Disconnect", "",   "", disconnect_session },
+       { "Change",     "sv", "", change_session     },
+       { },
+};
+
+int __connman_session_create(DBusMessage *msg)
 {
+       const char *owner, *notify_path;
+       char *session_path;
+       DBusMessageIter iter, array;
        struct connman_session *session;
-       struct connman_bearer *bearer;
-       enum connman_service_type service_type;
-       const char *bearer_name_new;
-       size_t bearer_name_len;
+       int err;
+
+       owner = dbus_message_get_sender(msg);
 
-       if (bearer_name == NULL)
-               return NULL;
+       DBG("owner %s", owner);
 
-       DBG("owner %s bearer %s", owner, bearer_name);
+       dbus_message_iter_init(msg, &iter);
+       dbus_message_iter_recurse(&iter, &array);
 
-       bearer_name_len = strlen(bearer_name);
+       while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_DICT_ENTRY)
+               dbus_message_iter_next(&array);
 
-       session = g_hash_table_lookup(session_hash, owner);
-       if (session) {
-               /* we only support one bearer per process */
-               if (bearer_name_len &&
-                       g_strcmp0(session->bearer->name, bearer_name))
-                               return NULL;
+       dbus_message_iter_next(&iter);
+       dbus_message_iter_get_basic(&iter, &notify_path);
+
+       if (notify_path == NULL) {
+               session_path = NULL;
+               err = -EINVAL;
+               goto err;
+       }
 
-               g_atomic_int_inc(&session->refcount);
+       session_path = g_strdup_printf("/sessions%s", notify_path);
+       if (session_path == NULL) {
+               err = -ENOMEM;
+               goto err;
+       }
 
-               return session->service;
+       session = g_hash_table_lookup(session_hash, session_path);
+       if (session != NULL) {
+               err = -EEXIST;
+               goto err;
        }
 
        session = g_try_new0(struct connman_session, 1);
-       if (session == NULL)
-               return NULL;
+       if (session == NULL) {
+               err = -ENOMEM;
+               goto err;
+       }
 
-       session->refcount = 1;
        session->owner = g_strdup(owner);
-       session->service = NULL;
-       g_hash_table_replace(session_hash, session->owner, session);
+       session->session_path = session_path;
+       session->notify_path = g_strdup(notify_path);
+       session->notify_watch =
+               g_dbus_add_disconnect_watch(connection, session->owner,
+                                       owner_disconnect, session, NULL);
+
+       g_hash_table_replace(session_hash, session->session_path, session);
 
-       /* Find and connect service */
-       service_type = bearer2service(bearer_name);
+       DBG("add %s", session->session_path);
 
-       session->service = __connman_service_connect_type(service_type);
-       if (session->service == NULL)
-               goto failed_connect;
+       if (g_dbus_register_interface(connection, session->session_path,
+                                       CONNMAN_SESSION_INTERFACE,
+                                       session_methods, NULL,
+                                       NULL, session, NULL) == FALSE) {
+               connman_error("Failed to register %s", session->session_path);
+               g_hash_table_remove(session_hash, session->session_path);
+               session = NULL;
 
-       connman_service_ref(session->service);
+               err = -EINVAL;
+               goto err;
+       }
 
-       service_type = connman_service_get_type(session->service);
+       g_dbus_send_reply(connection, msg,
+                               DBUS_TYPE_OBJECT_PATH, &session->session_path,
+                               DBUS_TYPE_INVALID);
 
-       /* We might get a different bearer from the one we requested */
-       bearer_name_new = service2bearer(service_type);
+       g_timeout_add_seconds(0, session_notify_all, session);
 
-       /* Refcount the exisiting bearer, or create one */
-       bearer = g_hash_table_lookup(bearer_hash, bearer_name_new);
-       if (bearer == NULL) {
-               bearer = g_try_new0(struct connman_bearer, 1);
-               if (bearer == NULL)
-                       goto failed_bearer;
+       return 0;
 
-               bearer->refcount = 0;
-               bearer->name = g_strdup(bearer_name_new);
-               g_hash_table_replace(bearer_hash, bearer->name, bearer);
-       }
+err:
+       connman_error("Failed to create session");
+       g_free(session_path);
 
-       g_atomic_int_inc(&bearer->refcount);
-       session->bearer = bearer;
+       return err;
+}
 
-       session->watch = g_dbus_add_disconnect_watch(connection, session->owner,
-                                       owner_disconnect, session, NULL);
-       return session->service;
+int __connman_session_destroy(DBusMessage *msg)
+{
+       const char *owner, *session_path;
+       struct connman_session *session;
 
-failed_bearer:
-       session_disconnect(session);
+       owner = dbus_message_get_sender(msg);
+
+       DBG("owner %s", owner);
 
-failed_connect:
-       g_hash_table_remove(session_hash, session);
+       dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &session_path,
+                                                       DBUS_TYPE_INVALID);
+       if (session_path == NULL)
+               return -EINVAL;
+
+       session = g_hash_table_lookup(session_hash, session_path);
+       if (session == NULL)
+               return -EINVAL;
+
+       if (g_strcmp0(owner, session->owner) != 0)
+               return -EACCES;
 
-       return NULL;
+       session_disconnect(session);
+
+       return 0;
 }
 
 connman_bool_t __connman_session_mode()
@@ -290,10 +315,7 @@ int __connman_session_init(void)
                return -1;
 
        session_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
-                                               NULL, remove_session);
-
-       bearer_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
-                                               NULL, remove_bearer);
+                                               NULL, cleanup_session);
 
        sessionmode = FALSE;
        return 0;
@@ -306,7 +328,8 @@ void __connman_session_cleanup(void)
        if (connection == NULL)
                return;
 
-       g_hash_table_destroy(bearer_hash);
+       g_hash_table_foreach(session_hash, release_session, NULL);
        g_hash_table_destroy(session_hash);
+
        dbus_connection_unref(connection);
 }