From: Daniel Wagner <[email protected]>
Pass the type of the trigger into session_changed. With this
additional information it's simpler to decide what to do and it allows
calling session_notify inside session_changed either directly or via
g_timeout_add_seconds.
---
doc/session-overview.txt | 4 +-
src/session.c | 265 +++++++++++++++++++++++++++++++++-------------
2 files changed, 193 insertions(+), 76 deletions(-)
diff --git a/doc/session-overview.txt b/doc/session-overview.txt
index f07eca2..b8d7315 100644
--- a/doc/session-overview.txt
+++ b/doc/session-overview.txt
@@ -31,7 +31,7 @@ Connect algorithm:
| Yes +------+-------+ No
+------+StayConnected?+------ Do nothing
| +--------------+
- |
+Session.Change() ------+
|
+------+-------+
+-----+EmergencyCall?+-----+
@@ -60,7 +60,7 @@ Disconnect algorithm:
Session.Disconnect()
IdleTimeout
|
- |
+ +--- Session.Change()
|
+-----------------+ Yes
|service not used +-------------+
diff --git a/src/session.c b/src/session.c
index 5cc85c4..2e1dcbb 100644
--- a/src/session.c
+++ b/src/session.c
@@ -42,12 +42,22 @@ enum connman_session_roaming_policy {
CONNMAN_SESSION_ROAMING_POLICY_INTERNATIONAL = 5,
};
+enum connman_session_trigger {
+ CONNMAN_SESSION_TRIGGER_UNKNOWN = 0,
+ CONNMAN_SESSION_TRIGGER_SETTING = 1,
+ CONNMAN_SESSION_TRIGGER_CONNECT = 2,
+ CONNMAN_SESSION_TRIGGER_DISCONNECT = 3,
+ CONNMAN_SESSION_TRIGGER_PERIODIC = 4,
+ CONNMAN_SESSION_TRIGGER_SERVICE = 5,
+ CONNMAN_SESSION_TRIGGER_ECALL = 6,
+};
+
struct session_info {
char *bearer;
const char *name;
char *ifname;
+ connman_bool_t online; /* caches the state of services */
connman_bool_t connect;
- connman_bool_t online;
connman_bool_t priority;
GSList *allowed_bearers;
connman_bool_t avoid_handover;
@@ -81,6 +91,28 @@ struct bearer_info {
enum connman_service_type service_type;
};
+static const char *trigger2string(enum connman_session_trigger trigger)
+{
+ switch (trigger) {
+ case CONNMAN_SESSION_TRIGGER_UNKNOWN:
+ break;
+ case CONNMAN_SESSION_TRIGGER_SETTING:
+ return "setting";
+ case CONNMAN_SESSION_TRIGGER_CONNECT:
+ return "connect";
+ case CONNMAN_SESSION_TRIGGER_DISCONNECT:
+ return "disconnect";
+ case CONNMAN_SESSION_TRIGGER_PERIODIC:
+ return "periodic";
+ case CONNMAN_SESSION_TRIGGER_SERVICE:
+ return "service";
+ case CONNMAN_SESSION_TRIGGER_ECALL:
+ return "ecall";
+ }
+
+ return NULL;
+}
+
static const char *roamingpolicy2string(enum connman_session_roaming_policy
policy)
{
switch (policy) {
@@ -401,8 +433,9 @@ static void append_notify(DBusMessageIter *dict,
session->info_dirty = FALSE;
}
-static int session_notify(struct connman_session *session)
+static gboolean session_notify(gpointer user_data)
{
+ struct connman_session *session = user_data;
DBusMessage *msg;
DBusMessageIter array, dict;
@@ -416,7 +449,7 @@ static int session_notify(struct connman_session *session)
CONNMAN_NOTIFICATION_INTERFACE,
"Update");
if (msg == NULL)
- return -ENOMEM;
+ return FALSE;
dbus_message_iter_init_append(msg, &array);
connman_dbus_dict_open(&array, &dict);
@@ -429,7 +462,7 @@ static int session_notify(struct connman_session *session)
session->info_dirty = FALSE;
- return 0;
+ return FALSE;
}
static void ipconfig_ipv4_changed(struct connman_session *session)
@@ -450,6 +483,28 @@ static void ipconfig_ipv6_changed(struct connman_session
*session)
info->service);
}
+static GSequenceIter *lookup_service(struct connman_session *session,
+ struct connman_service *service)
+{
+ GSequenceIter *iter;
+
+ if (service == NULL)
+ return NULL;
+
+ iter = g_sequence_get_begin_iter(session->service_list);
+
+ while (g_sequence_iter_is_end(iter) == FALSE) {
+ struct connman_service *service_iter = g_sequence_get(iter);
+
+ if (service_iter == service)
+ return iter;
+
+ iter = g_sequence_iter_next(iter);
+ }
+
+ return NULL;
+}
+
static connman_bool_t service_type_match(struct connman_session *session,
struct connman_service *service)
{
@@ -652,16 +707,6 @@ static DBusMessage *destroy_session(DBusConnection *conn,
return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
}
-static gboolean session_changed_connect(gpointer user_data)
-{
- struct connman_session *session = user_data;
- struct session_info *info = &session->info;
-
- __connman_service_connect(info->service);
-
- return FALSE;
-}
-
static void update_info(struct session_info *info)
{
enum connman_service_type type;
@@ -686,28 +731,26 @@ static void update_info(struct session_info *info)
}
}
-static void session_changed(struct connman_session *session)
+static void notify_service_changes(struct connman_session *session)
{
struct session_info *info = &session->info;
struct session_info *info_last = &session->info_last;
- struct connman_service *service = NULL;
- GSourceFunc callback = NULL;
- GSequenceIter *iter;
- /*
- * TODO: This only a placeholder for the 'real' algorithm to
- * play a bit around. So we are going to improve it step by step.
- */
+ if (info->service == info_last->service)
+ return;
- if (info->ecall == TRUE && session != ecall_session)
- goto out;
+ update_info(info);
+ session->info_dirty = TRUE;
+}
- if (info->connect == FALSE) {
- if (info->service != NULL)
- __connman_service_disconnect(info->service);
- info->service = NULL;
- goto out;
- }
+static void select_and_connect(struct connman_session *session,
+ connman_bool_t do_connect)
+{
+ struct session_info *info = &session->info;
+ struct connman_service *service = NULL;
+ GSequenceIter *iter;
+
+ DBG("session %p connect %d", session, do_connect);
iter = g_sequence_get_begin_iter(session->service_list);
@@ -720,8 +763,7 @@ static void session_changed(struct connman_session *session)
}
if (__connman_service_is_idle(service) == TRUE &&
- info->connect == TRUE) {
- callback = session_changed_connect;
+ do_connect == TRUE) {
break;
}
@@ -738,25 +780,112 @@ static void session_changed(struct connman_session
*session)
if (service != NULL) {
info->service = service;
- if (callback != NULL)
- callback(session);
+ if (do_connect == TRUE)
+ __connman_service_connect(info->service);
}
-out:
- if (info->service != info_last->service) {
- update_info(info);
- session->info_dirty = TRUE;
- }
+ notify_service_changes(session);
}
-static gboolean session_cb(gpointer user_data)
+static void session_changed(struct connman_session *session,
+ enum connman_session_trigger trigger)
{
- struct connman_session *session = user_data;
+ struct session_info *info = &session->info;
+ struct session_info *info_last = &session->info_last;
+ GSequenceIter *iter;
+
+ /*
+ * TODO: This only a placeholder for the 'real' algorithm to
+ * play a bit around. So we are going to improve it step by step.
+ */
- session_changed(session);
- session_notify(session);
+ DBG("session %p trigger %s", session, trigger2string(trigger));
- return FALSE;
+ switch (trigger) {
+ case CONNMAN_SESSION_TRIGGER_UNKNOWN:
+ DBG("ignore session changed event");
+ return;
+ case CONNMAN_SESSION_TRIGGER_SETTING:
+ if (info->service != NULL) {
+ iter = lookup_service(session, info->service);
+ if (iter == NULL) {
+ /* the service is not part of this session
anymore */
+
+ __connman_service_disconnect(info->service);
+
+ info->service = NULL;
+ notify_service_changes(session);
+
+ info_last->connect = info->connect;
+ }
+ }
+
+ /* Try to free ride */
+ if (info->online == FALSE)
+ select_and_connect(session, FALSE);
+
+ break;
+ case CONNMAN_SESSION_TRIGGER_CONNECT:
+ if (info->online == TRUE)
+ break;
+
+ select_and_connect(session, TRUE);
+ info_last->connect = info->connect;
+
+ break;
+ case CONNMAN_SESSION_TRIGGER_DISCONNECT:
+ if (info->online == FALSE)
+ break;
+
+ if (info->service != NULL)
+ __connman_service_disconnect(info->service);
+
+ info->service = NULL;
+ notify_service_changes(session);
+
+ info_last->connect = info->connect;
+
+ break;
+ case CONNMAN_SESSION_TRIGGER_PERIODIC:
+ select_and_connect(session, TRUE);
+
+ break;
+ case CONNMAN_SESSION_TRIGGER_SERVICE:
+ if (info->online == FALSE && info->stay_connected == TRUE) {
+ DBG("StayConnected");
+ select_and_connect(session, TRUE);
+
+ break;
+ }
+
+ /* Try to free ride */
+ if (info->online == FALSE)
+ select_and_connect(session, FALSE);
+
+ break;
+ case CONNMAN_SESSION_TRIGGER_ECALL:
+ if (info->online == FALSE && info->service != NULL)
+ info->service = NULL;
+
+ notify_service_changes(session);
+
+ break;
+ }
+
+ switch (trigger) {
+ case CONNMAN_SESSION_TRIGGER_UNKNOWN:
+ break;
+ case CONNMAN_SESSION_TRIGGER_CONNECT:
+ case CONNMAN_SESSION_TRIGGER_DISCONNECT:
+ case CONNMAN_SESSION_TRIGGER_ECALL:
+ g_timeout_add_seconds(0, session_notify, session);
+ break;
+ case CONNMAN_SESSION_TRIGGER_SETTING:
+ case CONNMAN_SESSION_TRIGGER_PERIODIC:
+ case CONNMAN_SESSION_TRIGGER_SERVICE:
+ session_notify(session);
+ break;
+ }
}
static DBusMessage *connect_session(DBusConnection *conn,
@@ -772,9 +901,7 @@ static DBusMessage *connect_session(DBusConnection *conn,
if (ecall_session != NULL && ecall_session != session)
return __connman_error_failed(msg, EBUSY);
- session->info_dirty = TRUE;
-
- g_timeout_add_seconds(0, session_cb, session);
+ session_changed(session, CONNMAN_SESSION_TRIGGER_CONNECT);
return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
}
@@ -792,9 +919,7 @@ static DBusMessage *disconnect_session(DBusConnection *conn,
if (ecall_session != NULL && ecall_session != session)
return __connman_error_failed(msg, EBUSY);
- session->info_dirty = TRUE;
-
- g_timeout_add_seconds(0, session_cb, session);
+ session_changed(session, CONNMAN_SESSION_TRIGGER_DISCONNECT);
return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
}
@@ -839,7 +964,7 @@ static void update_ecall_sessions(struct connman_session
*session)
session_iter->info.ecall = info->ecall;
session_iter->info_dirty = TRUE;
- g_timeout_add_seconds(0, session_cb, session_iter);
+ session_changed(session_iter, CONNMAN_SESSION_TRIGGER_ECALL);
}
}
@@ -848,8 +973,8 @@ static void update_ecall(struct connman_session *session)
struct session_info *info = &session->info;
struct session_info *info_last = &session->info_last;
- DBG("ecall_session %p ecall %d -> %d", ecall_session,
- info_last->ecall, info->ecall);
+ DBG("session %p ecall_session %p ecall %d -> %d", session,
+ ecall_session, info_last->ecall, info->ecall);
if (ecall_session == NULL) {
if (!(info_last->ecall == FALSE && info->ecall == TRUE))
@@ -979,7 +1104,7 @@ static DBusMessage *change_session(DBusConnection *conn,
}
if (session->info_dirty == TRUE)
- session_cb(session);
+ session_changed(session, CONNMAN_SESSION_TRIGGER_SETTING);
return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
@@ -1192,7 +1317,7 @@ int __connman_session_create(DBusMessage *msg)
session->info_dirty = TRUE;
session->append_all = TRUE;
- g_timeout_add_seconds(0, session_cb, session);
+ session_changed(session, CONNMAN_SESSION_TRIGGER_SETTING);
return 0;
@@ -1269,31 +1394,23 @@ static void service_add(struct connman_service *service)
g_sequence_insert_sorted(session->service_list, service,
sort_services, session);
- session_cb(session);
+ session_changed(session, CONNMAN_SESSION_TRIGGER_SERVICE);
}
}
-static connman_bool_t service_remove_from_session(
- struct connman_session *session,
+static int service_remove_from_session(struct connman_session *session,
struct connman_service *service)
{
GSequenceIter *iter;
- iter = g_sequence_get_begin_iter(session->service_list);
-
- while (g_sequence_iter_is_end(iter) == FALSE) {
- struct connman_service *service_iter = g_sequence_get(iter);
+ iter = lookup_service(session, service);
+ if (iter == NULL)
+ return -ENOENT;
- if (service_iter == service) {
- g_sequence_remove(iter);
+ session->info.online = FALSE;
+ g_sequence_remove(iter);
- return TRUE;
- }
-
- iter = g_sequence_iter_next(iter);
- }
-
- return FALSE;
+ return 0;
}
static void service_remove(struct connman_service *service)
@@ -1312,11 +1429,11 @@ static void service_remove(struct connman_service
*service)
session = value;
info = &session->info;
- if (service_remove_from_session(session, service) == FALSE)
+ if (service_remove_from_session(session, service) != 0)
continue;
info->service = NULL;
- session_cb(session);
+ session_changed(session, CONNMAN_SESSION_TRIGGER_SERVICE);
}
}
@@ -1344,7 +1461,7 @@ static void service_state_changed(struct connman_service
*service,
info->online = online;
session->info_dirty = TRUE;
- session_cb(session);
+ session_changed(session,
CONNMAN_SESSION_TRIGGER_SERVICE);
}
}
}
--
1.7.4.4
_______________________________________________
connman mailing list
[email protected]
http://lists.connman.net/listinfo/connman