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

Reply via email to