X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fsession.c;h=a5db7ad9f842381e1e58c75a96a516c74657b27f;hb=9fcc640425c7dcaf4090a86ec3ce64d7eef6b347;hp=88998f6c086e240eabb485e2deb84863868a754c;hpb=f1054d95ee6860ee84db01550c35e8c82f80585d;p=framework%2Fconnectivity%2Fconnman.git diff --git a/src/session.c b/src/session.c index 88998f6..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) { @@ -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; } @@ -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,8 +989,8 @@ 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(""); @@ -792,19 +999,19 @@ static void deselect_service(struct session_info *info) 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->state = CONNMAN_SESSION_STATE_DISCONNECTED; info->entry->reason = CONNMAN_SESSION_REASON_UNKNOWN; - service = info->entry->service; + entry = info->entry; info->entry = NULL; - DBG("disconnect %d online %d", disconnect, online); + DBG("disconnect %d connected %d", disconnect, connected); - if (disconnect == TRUE && online == TRUE) - g_timeout_add_seconds(0, call_disconnect, service); + if (disconnect == TRUE && connected == TRUE) + pending_timeout_add(0, call_disconnect, entry); } static void deselect_and_disconnect(struct connman_session *session, @@ -817,10 +1024,16 @@ static void deselect_and_disconnect(struct connman_session *session, 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; @@ -837,13 +1050,13 @@ static void select_offline_service(struct session_info *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, @@ -851,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); } @@ -891,12 +1104,86 @@ 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 @@ -907,9 +1194,12 @@ static void session_changed(struct connman_session *session, reason2string(info->reason)); if (info->entry != NULL) { - info->online = is_online(info->entry->state); - if (info_last->online != info->online) - session->info_dirty = TRUE; + 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) { @@ -917,26 +1207,49 @@ static void session_changed(struct connman_session *session, 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); + service_iter = g_hash_table_lookup( + session->service_hash, info->entry->service); - if (iter == NULL) { + } + + 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, info->reason); } + + g_hash_table_remove_all(service_hash_last); + g_sequence_free(service_list_last); } - if (info->online == FALSE) { + 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->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; @@ -944,6 +1257,11 @@ 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); @@ -954,7 +1272,7 @@ static void session_changed(struct connman_session *session, 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; @@ -966,8 +1284,8 @@ 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; } @@ -980,7 +1298,8 @@ static void session_changed(struct connman_session *session, 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, info->reason); } @@ -988,9 +1307,6 @@ static void session_changed(struct connman_session *session, break; } - if (info->entry != info_last->entry) - session->info_dirty = TRUE; - session_notify(session); } @@ -1026,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; @@ -1117,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); } @@ -1147,7 +1387,6 @@ static void update_ecall(struct connman_session *session) update_ecall_sessions(session); - session->info_dirty = TRUE; return; err: @@ -1160,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); @@ -1190,8 +1429,6 @@ static DBusMessage *change_session(DBusConnection *conn, } info->allowed_bearers = allowed_bearers; - - update_allowed_bearers(session); } else { goto err; } @@ -1200,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); @@ -1228,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; } @@ -1258,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); @@ -1323,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) }, { }, }; @@ -1345,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 = @@ -1419,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 { @@ -1478,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; @@ -1525,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; @@ -1543,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); @@ -1604,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(); @@ -1721,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);