X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fsession.c;h=a5db7ad9f842381e1e58c75a96a516c74657b27f;hb=4884c249bf7f098bbffd1a704a0a5ade573bee54;hp=3f66951e0187c3b42ad5baa96960b1ea7d51f509;hpb=79ed8fbfe4fb427b0e3bb86cfdd029434dd2f9c8;p=framework%2Fconnectivity%2Fconnman.git diff --git a/src/session.c b/src/session.c index 3f66951..a5db7ad 100644 --- a/src/session.c +++ b/src/session.c @@ -2,7 +2,7 @@ * * Connection Manager * - * Copyright (C) 2007-2010 Intel Corporation. All rights reserved. + * Copyright (C) 2007-2012 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 @@ -53,6 +53,18 @@ enum connman_session_reason { CONNMAN_SESSION_REASON_PERIODIC = 4, }; +enum connman_session_state { + CONNMAN_SESSION_STATE_DISCONNECTED = 0, + CONNMAN_SESSION_STATE_CONNECTED = 1, + CONNMAN_SESSION_STATE_ONLINE = 2, +}; + +enum connman_session_type { + CONNMAN_SESSION_TYPE_ANY = 0, + CONNMAN_SESSION_TYPE_LOCAL = 1, + CONNMAN_SESSION_TYPE_INTERNET = 2, +}; + enum connman_session_roaming_policy { CONNMAN_SESSION_ROAMING_POLICY_UNKNOWN = 0, CONNMAN_SESSION_ROAMING_POLICY_DEFAULT = 1, @@ -70,10 +82,12 @@ struct service_entry { struct connman_service *service; char *ifname; const char *bearer; + GSList *pending_timeouts; }; struct session_info { - connman_bool_t online; + enum connman_session_state state; + enum connman_session_type type; connman_bool_t priority; GSList *allowed_bearers; connman_bool_t avoid_handover; @@ -95,7 +109,6 @@ struct connman_session { guint notify_watch; connman_bool_t append_all; - connman_bool_t info_dirty; struct session_info *info; struct session_info *info_last; @@ -149,6 +162,44 @@ static const char *reason2string(enum connman_session_reason reason) return NULL; } +static const char *state2string(enum connman_session_state state) +{ + switch (state) { + case CONNMAN_SESSION_STATE_DISCONNECTED: + return "disconnected"; + case CONNMAN_SESSION_STATE_CONNECTED: + return "connected"; + case CONNMAN_SESSION_STATE_ONLINE: + return "online"; + } + + return NULL; +} + +static const char *type2string(enum connman_session_type type) +{ + switch (type) { + case CONNMAN_SESSION_TYPE_ANY: + return ""; + case CONNMAN_SESSION_TYPE_LOCAL: + return "local"; + case CONNMAN_SESSION_TYPE_INTERNET: + return "internet"; + } + + return NULL; +} + +static enum connman_session_type string2type(const char *type) +{ + if (g_strcmp0(type, "local") == 0) + return CONNMAN_SESSION_TYPE_LOCAL; + else if (g_strcmp0(type, "internet") == 0) + return CONNMAN_SESSION_TYPE_INTERNET; + + return CONNMAN_SESSION_TYPE_ANY; +} + static const char *roamingpolicy2string(enum connman_session_roaming_policy policy) { switch (policy) { @@ -198,7 +249,7 @@ static enum connman_service_type bearer2service(const char *bearer) return CONNMAN_SERVICE_TYPE_WIMAX; else if (g_strcmp0(bearer, "bluetooth") == 0) return CONNMAN_SERVICE_TYPE_BLUETOOTH; - else if (g_strcmp0(bearer, "3g") == 0) + else if (g_strcmp0(bearer, "cellular") == 0) return CONNMAN_SERVICE_TYPE_CELLULAR; else if (g_strcmp0(bearer, "vpn") == 0) return CONNMAN_SERVICE_TYPE_VPN; @@ -218,7 +269,7 @@ static char *service2bearer(enum connman_service_type type) case CONNMAN_SERVICE_TYPE_BLUETOOTH: return "bluetooth"; case CONNMAN_SERVICE_TYPE_CELLULAR: - return "3g"; + return "cellular"; case CONNMAN_SERVICE_TYPE_VPN: return "vpn"; case CONNMAN_SERVICE_TYPE_UNKNOWN: @@ -321,6 +372,11 @@ static void append_ipconfig_ipv4(DBusMessageIter *iter, void *user_data) if (service == NULL) return; + if (__connman_service_is_connected_state(service, + CONNMAN_IPCONFIG_TYPE_IPV4) == FALSE) { + return; + } + ipconfig_ipv4 = __connman_service_get_ip4config(service); if (ipconfig_ipv4 == NULL) return; @@ -336,6 +392,11 @@ static void append_ipconfig_ipv6(DBusMessageIter *iter, void *user_data) if (service == NULL) return; + if (__connman_service_is_connected_state(service, + CONNMAN_IPCONFIG_TYPE_IPV6) == FALSE) { + return; + } + ipconfig_ipv4 = __connman_service_get_ip4config(service); ipconfig_ipv6 = __connman_service_get_ip6config(service); if (ipconfig_ipv6 == NULL) @@ -354,11 +415,13 @@ static void append_notify(DBusMessageIter *dict, const char *name, *ifname, *bearer; if (session->append_all == TRUE || - info->online != info_last->online) { - connman_dbus_dict_append_basic(dict, "Online", - DBUS_TYPE_BOOLEAN, - &info->online); - info_last->online = info->online; + info->state != info_last->state) { + const char *state = state2string(info->state); + + connman_dbus_dict_append_basic(dict, "State", + DBUS_TYPE_STRING, + &state); + info_last->state = info->state; } if (session->append_all == TRUE || @@ -398,6 +461,14 @@ static void append_notify(DBusMessageIter *dict, info_last->entry = info->entry; } + if (session->append_all == TRUE || info->type != info_last->type) { + const char *type = type2string(info->type); + + connman_dbus_dict_append_basic(dict, "ConnectionType", + DBUS_TYPE_STRING, + &type); + info_last->type = info->type; + } if (session->append_all == TRUE || info->priority != info_last->priority) { @@ -474,7 +545,58 @@ static void append_notify(DBusMessageIter *dict, } session->append_all = FALSE; - session->info_dirty = FALSE; +} + +static connman_bool_t is_type_matching_state(enum connman_session_state *state, + enum connman_session_type type) +{ + switch (type) { + case CONNMAN_SESSION_TYPE_ANY: + return TRUE; + case CONNMAN_SESSION_TYPE_LOCAL: + if (*state >= CONNMAN_SESSION_STATE_CONNECTED) { + *state = CONNMAN_SESSION_STATE_CONNECTED; + return TRUE; + } + + break; + case CONNMAN_SESSION_TYPE_INTERNET: + if (*state == CONNMAN_SESSION_STATE_ONLINE) + return TRUE; + break; + } + + return FALSE; +} + +static connman_bool_t compute_notifiable_changes(struct connman_session *session) +{ + struct session_info *info_last = session->info_last; + struct session_info *info = session->info; + + if (session->append_all == TRUE) + return TRUE; + + if (info->state != info_last->state) + return TRUE; + + if (info->entry != info_last->entry && + info->state >= CONNMAN_SESSION_STATE_CONNECTED) + return TRUE; + + if (info->periodic_connect != info_last->periodic_connect || + info->allowed_bearers != info_last->allowed_bearers || + info->avoid_handover != info_last->avoid_handover || + info->stay_connected != info_last->stay_connected || + info->roaming_policy != info_last->roaming_policy || + info->idle_timeout != info_last->idle_timeout || + info->priority != info_last->priority || + info->marker != info_last->marker || + info->ecall != info_last->ecall || + info->type != info_last->type) + return TRUE; + + return FALSE; } static gboolean session_notify(gpointer user_data) @@ -483,8 +605,8 @@ static gboolean session_notify(gpointer user_data) DBusMessage *msg; DBusMessageIter array, dict; - if (session->info_dirty == FALSE) - return 0; + if (compute_notifiable_changes(session) == FALSE) + return FALSE; DBG("session %p owner %s notify_path %s", session, session->owner, session->notify_path); @@ -504,8 +626,6 @@ static gboolean session_notify(gpointer user_data) g_dbus_send_message(connection, msg); - session->info_dirty = FALSE; - return FALSE; } @@ -568,7 +688,7 @@ static int service_type_weight(enum connman_service_type type) * 1. Ethernet * 2. Bluetooth * 3. WiFi/WiMAX - * 4. GSM/UTMS/3G + * 4. Cellular */ switch (type) { @@ -679,7 +799,7 @@ static void cleanup_session(gpointer user_data) g_free(session); } -static connman_bool_t is_online(enum connman_service_state state) +static enum connman_session_state service_to_session_state(enum connman_service_state state) { switch (state) { case CONNMAN_SERVICE_STATE_UNKNOWN: @@ -688,8 +808,27 @@ static connman_bool_t is_online(enum connman_service_state state) case CONNMAN_SERVICE_STATE_CONFIGURATION: case CONNMAN_SERVICE_STATE_DISCONNECT: case CONNMAN_SERVICE_STATE_FAILURE: + break; case CONNMAN_SERVICE_STATE_READY: + return CONNMAN_SESSION_STATE_CONNECTED; + case CONNMAN_SERVICE_STATE_ONLINE: + return CONNMAN_SESSION_STATE_ONLINE; + } + + return CONNMAN_SESSION_STATE_DISCONNECTED; +} + +static connman_bool_t is_connected(enum connman_service_state state) +{ + switch (state) { + case CONNMAN_SERVICE_STATE_UNKNOWN: + case CONNMAN_SERVICE_STATE_IDLE: + case CONNMAN_SERVICE_STATE_ASSOCIATION: + case CONNMAN_SERVICE_STATE_CONFIGURATION: + case CONNMAN_SERVICE_STATE_DISCONNECT: + case CONNMAN_SERVICE_STATE_FAILURE: break; + case CONNMAN_SERVICE_STATE_READY: case CONNMAN_SERVICE_STATE_ONLINE: return TRUE; } @@ -705,10 +844,10 @@ static connman_bool_t is_connecting(enum connman_service_state state) break; case CONNMAN_SERVICE_STATE_ASSOCIATION: case CONNMAN_SERVICE_STATE_CONFIGURATION: - case CONNMAN_SERVICE_STATE_READY: return TRUE; case CONNMAN_SERVICE_STATE_DISCONNECT: case CONNMAN_SERVICE_STATE_FAILURE: + case CONNMAN_SERVICE_STATE_READY: case CONNMAN_SERVICE_STATE_ONLINE: break; } @@ -755,9 +894,76 @@ static connman_bool_t explicit_disconnect(struct session_info *info) return TRUE; } +struct pending_data { + unsigned int timeout; + struct service_entry *entry; + gboolean (*cb)(gpointer); +}; + +static void pending_timeout_free(gpointer data, gpointer user_data) +{ + struct pending_data *pending = data; + + DBG("pending %p timeout %d", pending, pending->timeout); + g_source_remove(pending->timeout); + g_free(pending); +} + +static void pending_timeout_remove_all(struct service_entry *entry) +{ + DBG(""); + + g_slist_foreach(entry->pending_timeouts, pending_timeout_free, NULL); + g_slist_free(entry->pending_timeouts); + entry->pending_timeouts = NULL; +} + +static gboolean pending_timeout_cb(gpointer data) +{ + struct pending_data *pending = data; + struct service_entry *entry = pending->entry; + gboolean ret; + + DBG("pending %p timeout %d", pending, pending->timeout); + + ret = pending->cb(pending->entry); + if (ret == FALSE) { + entry->pending_timeouts = + g_slist_remove(entry->pending_timeouts, + pending); + g_free(pending); + } + return ret; +} + +static connman_bool_t pending_timeout_add(unsigned int seconds, + gboolean (*cb)(gpointer), + struct service_entry *entry) +{ + struct pending_data *pending = g_try_new0(struct pending_data, 1); + + if (pending == NULL || cb == NULL || entry == NULL) { + g_free(pending); + return FALSE; + } + + pending->cb = cb; + pending->entry = entry; + pending->timeout = g_timeout_add_seconds(seconds, pending_timeout_cb, + pending); + entry->pending_timeouts = g_slist_prepend(entry->pending_timeouts, + pending); + + DBG("pending %p entry %p timeout id %d", pending, entry, + pending->timeout); + + return TRUE; +} + static gboolean call_disconnect(gpointer user_data) { - struct connman_service *service = user_data; + struct service_entry *entry = user_data; + struct connman_service *service = entry->service; /* * TODO: We should mark this entry as pending work. In case @@ -772,7 +978,8 @@ static gboolean call_disconnect(gpointer user_data) static gboolean call_connect(gpointer user_data) { - struct connman_service *service = user_data; + struct service_entry *entry = user_data; + struct connman_service *service = entry->service; DBG("connect service %p", service); __connman_service_connect(service); @@ -782,39 +989,51 @@ static gboolean call_connect(gpointer user_data) static void deselect_service(struct session_info *info) { - struct connman_service *service; - connman_bool_t disconnect, online; + struct service_entry *entry; + connman_bool_t disconnect, connected; + + DBG(""); if (info->entry == NULL) return; disconnect = explicit_disconnect(info); - online = is_connecting(info->entry->state) == TRUE || - is_online(info->entry->state) == TRUE; + connected = is_connecting(info->entry->state) == TRUE || + is_connected(info->entry->state) == TRUE; - info->online = FALSE; - info->reason = CONNMAN_SESSION_REASON_UNKNOWN; + info->state = CONNMAN_SESSION_STATE_DISCONNECTED; info->entry->reason = CONNMAN_SESSION_REASON_UNKNOWN; - service = info->entry->service; + entry = info->entry; info->entry = NULL; - if (disconnect == TRUE && online == TRUE) - g_timeout_add_seconds(0, call_disconnect, service); + DBG("disconnect %d connected %d", disconnect, connected); + + if (disconnect == TRUE && connected == TRUE) + pending_timeout_add(0, call_disconnect, entry); } -static void deselect_and_disconnect(struct connman_session *session) +static void deselect_and_disconnect(struct connman_session *session, + enum connman_session_reason reason) { struct session_info *info = session->info; deselect_service(info); + + info->reason = reason; } -static void select_online_service(struct session_info *info, +static void select_connected_service(struct session_info *info, struct service_entry *entry) { - info->online = TRUE; + enum connman_session_state state; + + state = service_to_session_state(entry->state); + if (is_type_matching_state(&state, info->type) == FALSE) + return; + + info->state = state; info->entry = entry; info->entry->reason = info->reason; @@ -828,23 +1047,16 @@ static void select_online_service(struct session_info *info, static void select_offline_service(struct session_info *info, struct service_entry *entry) { - if (explicit_connect(info->reason) == FALSE) { - /* Don't select this service. It is not online and we - * don't call connect on it. This happends for example - * when the system is idle and we create a new session - * which is in free ride mode. - */ - deselect_service(info); + if (explicit_connect(info->reason) == FALSE) return; - } - info->online = FALSE; + info->state = service_to_session_state(entry->state); info->entry = entry; info->entry->reason = info->reason; __connman_service_session_inc(info->entry->service); - g_timeout_add_seconds(0, call_connect, info->entry->service); + pending_timeout_add(0, call_connect, entry); } static void select_service(struct session_info *info, @@ -852,8 +1064,8 @@ static void select_service(struct session_info *info, { DBG("service %p", entry->service); - if (is_online(entry->state) == TRUE) - select_online_service(info, entry); + if (is_connected(entry->state) == TRUE) + select_connected_service(info, entry); else select_offline_service(info, entry); } @@ -892,45 +1104,152 @@ static void select_and_connect(struct connman_session *session, } } +static struct service_entry *create_service_entry(struct connman_service *service, + const char *name, + enum connman_service_state state) +{ + struct service_entry *entry; + enum connman_service_type type; + int idx; + + entry = g_try_new0(struct service_entry, 1); + if (entry == NULL) + return entry; + + entry->reason = CONNMAN_SESSION_REASON_UNKNOWN; + entry->state = state; + if (name != NULL) + entry->name = name; + else + entry->name = ""; + entry->service = service; + + idx = __connman_service_get_index(entry->service); + entry->ifname = connman_inet_ifname(idx); + if (entry->ifname == NULL) + entry->ifname = g_strdup(""); + + type = connman_service_get_type(entry->service); + entry->bearer = service2bearer(type); + + return entry; +} + +static void destroy_service_entry(gpointer data) +{ + struct service_entry *entry = data; + + pending_timeout_remove_all(entry); + g_free(entry->ifname); + + g_free(entry); +} + +static void populate_service_list(struct connman_session *session) +{ + struct service_entry *entry; + GSequenceIter *iter; + + session->service_hash = + g_hash_table_new_full(g_direct_hash, g_direct_equal, + NULL, NULL); + session->service_list = __connman_service_get_list(session, + service_match, + create_service_entry, + destroy_service_entry); + + g_sequence_sort(session->service_list, sort_services, session); + + iter = g_sequence_get_begin_iter(session->service_list); + + while (g_sequence_iter_is_end(iter) == FALSE) { + entry = g_sequence_get(iter); + + DBG("service %p type %s name %s", entry->service, + service2bearer(connman_service_get_type(entry->service)), + entry->name); + + g_hash_table_replace(session->service_hash, + entry->service, iter); + + iter = g_sequence_iter_next(iter); + } +} + static void session_changed(struct connman_session *session, enum connman_session_trigger trigger) { struct session_info *info = session->info; struct session_info *info_last = session->info_last; - GSequenceIter *iter; + GSequenceIter *service_iter = NULL, *service_iter_last = NULL; + GSequence *service_list_last; + GHashTable *service_hash_last; /* * TODO: This only a placeholder for the 'real' algorithm to * play a bit around. So we are going to improve it step by step. */ - DBG("session %p trigger %s", session, trigger2string(trigger)); + DBG("session %p trigger %s reason %s", session, trigger2string(trigger), + reason2string(info->reason)); + + if (info->entry != NULL) { + enum connman_session_state state; + + state = service_to_session_state(info->entry->state); + + if (is_type_matching_state(&state, info->type) == TRUE) + info->state = state; + } switch (trigger) { case CONNMAN_SESSION_TRIGGER_UNKNOWN: DBG("ignore session changed event"); return; case CONNMAN_SESSION_TRIGGER_SETTING: - if (info->entry != NULL) { - iter = g_hash_table_lookup(session->service_hash, + if (info->allowed_bearers != info_last->allowed_bearers) { + + service_hash_last = session->service_hash; + service_list_last = session->service_list; + + populate_service_list(session); + + if (info->entry != NULL) { + service_iter_last = g_hash_table_lookup( + service_hash_last, info->entry->service); - if (iter == NULL) { + service_iter = g_hash_table_lookup( + session->service_hash, + info->entry->service); + } + + if (service_iter == NULL && service_iter_last != NULL) { /* - * This service is not part of this - * session anymore. + * The currently selected service is + * not part of this session anymore. */ - deselect_and_disconnect(session); + deselect_and_disconnect(session, info->reason); } + + g_hash_table_remove_all(service_hash_last); + g_sequence_free(service_list_last); + } + + if (info->type != info_last->type) { + if (info->state >= CONNMAN_SESSION_STATE_CONNECTED && + is_type_matching_state(&info->state, + info->type) == FALSE) + deselect_and_disconnect(session, info->reason); } - if (info->online == FALSE) { + if (info->state == CONNMAN_SESSION_STATE_DISCONNECTED) { select_and_connect(session, CONNMAN_SESSION_REASON_FREE_RIDE); } break; case CONNMAN_SESSION_TRIGGER_CONNECT: - if (info->online == TRUE) { + if (info->state >= CONNMAN_SESSION_STATE_CONNECTED) { if (info->entry->reason == CONNMAN_SESSION_REASON_CONNECT) break; info->entry->reason = CONNMAN_SESSION_REASON_CONNECT; @@ -938,16 +1257,22 @@ static void session_changed(struct connman_session *session, break; } + if (info->entry != NULL && + is_connecting(info->entry->state) == TRUE) { + break; + } + select_and_connect(session, CONNMAN_SESSION_REASON_CONNECT); break; case CONNMAN_SESSION_TRIGGER_DISCONNECT: - deselect_and_disconnect(session); + deselect_and_disconnect(session, + CONNMAN_SESSION_REASON_DISCONNECT); break; case CONNMAN_SESSION_TRIGGER_PERIODIC: - if (info->online == TRUE) { + if (info->state >= CONNMAN_SESSION_STATE_CONNECTED) { info->entry->reason = CONNMAN_SESSION_REASON_PERIODIC; __connman_service_session_inc(info->entry->service); break; @@ -959,61 +1284,29 @@ static void session_changed(struct connman_session *session, break; case CONNMAN_SESSION_TRIGGER_SERVICE: if (info->entry != NULL && - (is_connecting(info->entry->state) == TRUE || - is_online(info->entry->state) == TRUE)) { + (is_connecting(info->entry->state) == TRUE || + is_connected(info->entry->state) == TRUE)) { break; } - switch (info->reason) { - case CONNMAN_SESSION_REASON_CONNECT: - /* - * We are not online, we are not connecting, that - * means we could still have a valid info->entry. - * Though something has changed from the service layer. - * Therefore we want to restart the algorithm. Before we - * can do that we have to cleanup a potientional old entry. - */ - deselect_and_disconnect(session); - info->reason = CONNMAN_SESSION_REASON_CONNECT; /* restore value */ - - DBG("Retry to find a matching session"); - /* - * The user called Connect() but there was no - * matching session available at this point. - * Now there might be a new one. Let's retry - * to select and connect - */ - select_and_connect(session, - CONNMAN_SESSION_REASON_CONNECT); - break; - case CONNMAN_SESSION_REASON_PERIODIC: - case CONNMAN_SESSION_REASON_FREE_RIDE: - if (info->stay_connected == TRUE) { - DBG("StayConnected"); - select_and_connect(session, - CONNMAN_SESSION_REASON_CONNECT); - } else { - select_and_connect(session, - CONNMAN_SESSION_REASON_FREE_RIDE); - } - break; - case CONNMAN_SESSION_REASON_DISCONNECT: - case CONNMAN_SESSION_REASON_UNKNOWN: - break; + deselect_and_disconnect(session, info->reason); + + if (info->reason == CONNMAN_SESSION_REASON_FREE_RIDE || + info->stay_connected == TRUE) { + select_and_connect(session, info->reason); } + break; case CONNMAN_SESSION_TRIGGER_ECALL: - if (info->online == FALSE && info->entry != NULL && + if (info->state == CONNMAN_SESSION_STATE_DISCONNECTED && + info->entry != NULL && info->entry->service != NULL) { - deselect_and_disconnect(session); + deselect_and_disconnect(session, info->reason); } break; } - if (info->entry != info_last->entry) - session->info_dirty = TRUE; - session_notify(session); } @@ -1049,81 +1342,6 @@ static DBusMessage *disconnect_session(DBusConnection *conn, return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); } -static struct service_entry *create_service_entry(struct connman_service *service, - const char *name, - enum connman_service_state state) -{ - struct service_entry *entry; - enum connman_service_type type; - int idx; - - entry = g_try_new0(struct service_entry, 1); - if (entry == NULL) - return entry; - - entry->reason = CONNMAN_SESSION_REASON_UNKNOWN; - entry->state = state; - if (name != NULL) - entry->name = name; - else - entry->name = ""; - entry->service = service; - - idx = __connman_service_get_index(entry->service); - entry->ifname = connman_inet_ifname(idx); - if (entry->ifname == NULL) - entry->ifname = g_strdup(""); - - type = connman_service_get_type(entry->service); - entry->bearer = service2bearer(type); - - return entry; -} - -static void destroy_service_entry(gpointer data) -{ - struct service_entry *entry = data; - - g_free(entry->ifname); - - g_free(entry); -} - -static void update_allowed_bearers(struct connman_session *session) -{ - struct service_entry *entry; - GSequenceIter *iter; - - if (session->service_list != NULL) { - g_hash_table_remove_all(session->service_hash); - g_sequence_free(session->service_list); - } - - session->service_list = __connman_service_get_list(session, - service_match, - create_service_entry, - destroy_service_entry); - - g_sequence_sort(session->service_list, sort_services, session); - - iter = g_sequence_get_begin_iter(session->service_list); - - while (g_sequence_iter_is_end(iter) == FALSE) { - entry = g_sequence_get(iter); - - DBG("service %p type %s name %s", entry->service, - service2bearer(connman_service_get_type(entry->service)), - entry->name); - - g_hash_table_replace(session->service_hash, - entry->service, iter); - - iter = g_sequence_iter_next(iter); - } - - session->info_dirty = TRUE; -} - static void update_ecall_sessions(struct connman_session *session) { struct session_info *info = session->info; @@ -1140,7 +1358,6 @@ static void update_ecall_sessions(struct connman_session *session) continue; session_iter->info->ecall = info->ecall; - session_iter->info_dirty = TRUE; session_changed(session_iter, CONNMAN_SESSION_TRIGGER_ECALL); } @@ -1170,7 +1387,6 @@ static void update_ecall(struct connman_session *session) update_ecall_sessions(session); - session->info_dirty = TRUE; return; err: @@ -1183,9 +1399,9 @@ static DBusMessage *change_session(DBusConnection *conn, { struct connman_session *session = user_data; struct session_info *info = session->info; - struct session_info *info_last = session->info_last; DBusMessageIter iter, value; const char *name; + const char *val; GSList *allowed_bearers; DBG("session %p", session); @@ -1213,8 +1429,6 @@ static DBusMessage *change_session(DBusConnection *conn, } info->allowed_bearers = allowed_bearers; - - update_allowed_bearers(session); } else { goto err; } @@ -1223,21 +1437,12 @@ static DBusMessage *change_session(DBusConnection *conn, if (g_str_equal(name, "Priority") == TRUE) { dbus_message_iter_get_basic(&value, &info->priority); - - if (info_last->priority != info->priority) - session->info_dirty = TRUE; } else if (g_str_equal(name, "AvoidHandover") == TRUE) { dbus_message_iter_get_basic(&value, &info->avoid_handover); - - if (info_last->avoid_handover != info->avoid_handover) - session->info_dirty = TRUE; } else if (g_str_equal(name, "StayConnected") == TRUE) { dbus_message_iter_get_basic(&value, &info->stay_connected); - - if (info_last->stay_connected != info->stay_connected) - session->info_dirty = TRUE; } else if (g_str_equal(name, "EmergencyCall") == TRUE) { dbus_message_iter_get_basic(&value, &info->ecall); @@ -1251,28 +1456,21 @@ static DBusMessage *change_session(DBusConnection *conn, if (g_str_equal(name, "PeriodicConnect") == TRUE) { dbus_message_iter_get_basic(&value, &info->periodic_connect); - - if (info_last->periodic_connect != info->periodic_connect) - session->info_dirty = TRUE; } else if (g_str_equal(name, "IdleTimeout") == TRUE) { dbus_message_iter_get_basic(&value, &info->idle_timeout); - - if (info_last->idle_timeout != info->idle_timeout) - session->info_dirty = TRUE; } else { goto err; } break; case DBUS_TYPE_STRING: - if (g_str_equal(name, "RoamingPolicy") == TRUE) { - const char *val; + if (g_str_equal(name, "ConnectionType") == TRUE) { + dbus_message_iter_get_basic(&value, &val); + info->type = string2type(val); + } else if (g_str_equal(name, "RoamingPolicy") == TRUE) { dbus_message_iter_get_basic(&value, &val); info->roaming_policy = string2roamingpolicy(val); - - if (info_last->roaming_policy != info->roaming_policy) - session->info_dirty = TRUE; } else { goto err; } @@ -1281,8 +1479,7 @@ static DBusMessage *change_session(DBusConnection *conn, goto err; } - if (session->info_dirty == TRUE) - session_changed(session, CONNMAN_SESSION_TRIGGER_SETTING); + session_changed(session, CONNMAN_SESSION_TRIGGER_SETTING); return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); @@ -1325,7 +1522,8 @@ static int session_disconnect(struct connman_session *session) g_dbus_unregister_interface(connection, session->session_path, CONNMAN_SESSION_INTERFACE); - deselect_and_disconnect(session); + deselect_and_disconnect(session, + CONNMAN_SESSION_REASON_DISCONNECT); g_hash_table_remove(session_hash, session->session_path); @@ -1345,17 +1543,26 @@ static DBusMessage *destroy_session(DBusConnection *conn, DBusMessage *msg, void *user_data) { struct connman_session *session = user_data; + struct session_info *info = session->info; DBG("session %p", session); + if (ecall_info != NULL && ecall_info != info) + return __connman_error_failed(msg, EBUSY); + + session_disconnect(session); + return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); } -static GDBusMethodTable session_methods[] = { - { "Destroy", "", "", destroy_session }, - { "Connect", "", "", connect_session }, - { "Disconnect", "", "", disconnect_session }, - { "Change", "sv", "", change_session }, +static const GDBusMethodTable session_methods[] = { + { GDBUS_METHOD("Destroy", NULL, NULL, destroy_session) }, + { GDBUS_METHOD("Connect", NULL, NULL, connect_session) }, + { GDBUS_METHOD("Disconnect", NULL, NULL, + disconnect_session ) }, + { GDBUS_METHOD("Change", + GDBUS_ARGS({ "name", "s" }, { "value", "v" }), + NULL, change_session) }, { }, }; @@ -1367,6 +1574,7 @@ int __connman_session_create(DBusMessage *msg) struct connman_session *session = NULL; struct session_info *info, *info_last; + enum connman_session_type type = CONNMAN_SESSION_TYPE_ANY; connman_bool_t priority = FALSE, avoid_handover = FALSE; connman_bool_t stay_connected = FALSE, ecall = FALSE; enum connman_session_roaming_policy roaming_policy = @@ -1441,7 +1649,10 @@ int __connman_session_create(DBusMessage *msg) } break; case DBUS_TYPE_STRING: - if (g_str_equal(key, "RoamingPolicy") == TRUE) { + if (g_str_equal(key, "ConnectionType") == TRUE) { + dbus_message_iter_get_basic(&value, &val); + type = string2type(val); + } else if (g_str_equal(key, "RoamingPolicy") == TRUE) { dbus_message_iter_get_basic(&value, &val); roaming_policy = string2roamingpolicy(val); } else { @@ -1500,10 +1711,8 @@ int __connman_session_create(DBusMessage *msg) g_dbus_add_disconnect_watch(connection, session->owner, owner_disconnect, session, NULL); - session->service_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal, - NULL, NULL); - - info->online = FALSE; + info->state = CONNMAN_SESSION_STATE_DISCONNECTED; + info->type = type; info->priority = priority; info->avoid_handover = avoid_handover; info->stay_connected = stay_connected; @@ -1547,13 +1756,13 @@ int __connman_session_create(DBusMessage *msg) DBUS_TYPE_INVALID); - update_allowed_bearers(session); + populate_service_list(session); if (info->ecall == TRUE) { ecall_info = info; update_ecall_sessions(session); } - info_last->online = info->online; + info_last->state = info->state; info_last->priority = info->priority; info_last->avoid_handover = info->avoid_handover; info_last->stay_connected = info->stay_connected; @@ -1565,7 +1774,6 @@ int __connman_session_create(DBusMessage *msg) info_last->marker = info->marker; info_last->allowed_bearers = info->allowed_bearers; - session->info_dirty = TRUE; session->append_all = TRUE; session_changed(session, CONNMAN_SESSION_TRIGGER_SETTING); @@ -1626,7 +1834,13 @@ void __connman_session_set_mode(connman_bool_t enable) { DBG("enable %d", enable); - sessionmode = enable; + if (sessionmode != enable) { + sessionmode = enable; + + connman_dbus_property_changed_basic(CONNMAN_MANAGER_PATH, + CONNMAN_MANAGER_INTERFACE, "SessionMode", + DBUS_TYPE_BOOLEAN, &sessionmode); + } if (sessionmode == TRUE) __connman_service_disconnect_all(); @@ -1702,32 +1916,21 @@ static void service_state_changed(struct connman_service *service, { GHashTableIter iter; gpointer key, value; - struct connman_session *session; - struct session_info *info, *info_last; DBG("service %p state %d", service, state); g_hash_table_iter_init(&iter, session_hash); while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) { + struct connman_session *session = value; GSequenceIter *service_iter; - session = value; - info = session->info; - info_last = session->info_last; - service_iter = g_hash_table_lookup(session->service_hash, service); if (service_iter != NULL) { struct service_entry *entry; entry = g_sequence_get(service_iter); entry->state = state; - - if (info->entry == entry) { - info->online = is_online(entry->state); - if (info_last->online != info->online) - session->info_dirty = TRUE; - } } session_changed(session, @@ -1754,6 +1957,9 @@ static void ipconfig_changed(struct connman_service *service, session = value; info = session->info; + if (info->state == CONNMAN_SESSION_STATE_DISCONNECTED) + continue; + if (info->entry != NULL && info->entry->service == service) { if (type == CONNMAN_IPCONFIG_TYPE_IPV4) ipconfig_ipv4_changed(session);