diff options
-rw-r--r-- | include/dbus.h | 2 | ||||
-rw-r--r-- | src/connman-dbus.conf | 1 | ||||
-rw-r--r-- | src/connman.h | 6 | ||||
-rw-r--r-- | src/manager.c | 32 | ||||
-rw-r--r-- | src/session.c | 359 |
5 files changed, 208 insertions, 192 deletions
diff --git a/include/dbus.h b/include/dbus.h index 9be76b2f..83f3d30c 100644 --- a/include/dbus.h +++ b/include/dbus.h @@ -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 diff --git a/src/connman-dbus.conf b/src/connman-dbus.conf index 311f28c7..98a773ea 100644 --- a/src/connman-dbus.conf +++ b/src/connman-dbus.conf @@ -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"/> diff --git a/src/connman.h b/src/connman.h index 4196127e..bb08267e 100644 --- a/src/connman.h +++ b/src/connman.h @@ -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); diff --git a/src/manager.c b/src/manager.c index 198875da..349ddb41 100644 --- a/src/manager.c +++ b/src/manager.c @@ -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 }, { }, }; diff --git a/src/session.c b/src/session.c index 391899fb..1540d6b9 100644 --- a/src/session.c +++ b/src/session.c @@ -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 @@ -23,244 +24,268 @@ #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, ¬ify_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); } |