session: Move info->online update code to session_changed()
[framework/connectivity/connman.git] / src / session.c
index 91758e2..56682cf 100644 (file)
@@ -33,7 +33,7 @@
 static DBusConnection *connection;
 static GHashTable *session_hash;
 static connman_bool_t sessionmode;
-static struct connman_session *ecall_session;
+static struct session_info *ecall_info;
 
 enum connman_session_trigger {
        CONNMAN_SESSION_TRIGGER_UNKNOWN         = 0,
@@ -48,8 +48,9 @@ enum connman_session_trigger {
 enum connman_session_reason {
        CONNMAN_SESSION_REASON_UNKNOWN          = 0,
        CONNMAN_SESSION_REASON_CONNECT          = 1,
-       CONNMAN_SESSION_REASON_FREE_RIDE        = 2,
-       CONNMAN_SESSION_REASON_PERIODIC         = 3,
+       CONNMAN_SESSION_REASON_DISCONNECT       = 2,
+       CONNMAN_SESSION_REASON_FREE_RIDE        = 3,
+       CONNMAN_SESSION_REASON_PERIODIC         = 4,
 };
 
 enum connman_session_roaming_policy {
@@ -67,7 +68,7 @@ struct service_entry {
        enum connman_service_state state;
        const char *name;
        struct connman_service *service;
-       const char *ifname;
+       char *ifname;
        const char *bearer;
 };
 
@@ -84,6 +85,7 @@ struct session_info {
        unsigned int marker;
 
        struct service_entry *entry;
+       enum connman_session_reason reason;
 };
 
 struct connman_session {
@@ -133,9 +135,11 @@ static const char *reason2string(enum connman_session_reason reason)
 {
        switch (reason) {
        case CONNMAN_SESSION_REASON_UNKNOWN:
-               break;
+               return "unknown";
        case CONNMAN_SESSION_REASON_CONNECT:
                return "connect";
+       case CONNMAN_SESSION_REASON_DISCONNECT:
+               return "disconnect";
        case CONNMAN_SESSION_REASON_FREE_RIDE:
                return "free-ride";
        case CONNMAN_SESSION_REASON_PERIODIC:
@@ -196,6 +200,8 @@ static enum connman_service_type bearer2service(const char *bearer)
                return CONNMAN_SERVICE_TYPE_BLUETOOTH;
        else if (g_strcmp0(bearer, "3g") == 0)
                return CONNMAN_SERVICE_TYPE_CELLULAR;
+       else if (g_strcmp0(bearer, "vpn") == 0)
+               return CONNMAN_SERVICE_TYPE_VPN;
        else
                return CONNMAN_SERVICE_TYPE_UNKNOWN;
 }
@@ -213,10 +219,11 @@ static char *service2bearer(enum connman_service_type type)
                return "bluetooth";
        case CONNMAN_SERVICE_TYPE_CELLULAR:
                return "3g";
+       case CONNMAN_SERVICE_TYPE_VPN:
+               return "vpn";
        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 "";
        }
@@ -637,11 +644,12 @@ static gint sort_allowed_bearers(struct connman_service *service_a,
 
 static gint sort_services(gconstpointer a, gconstpointer b, gpointer user_data)
 {
-       struct connman_service *service_a = (void *)a;
-       struct connman_service *service_b = (void *)b;
+       struct service_entry *entry_a = (void *)a;
+       struct service_entry *entry_b = (void *)b;
        struct connman_session *session = user_data;
 
-       return sort_allowed_bearers(service_a, service_b, session);
+       return sort_allowed_bearers(entry_a->service, entry_b->service,
+                               session);
 }
 
 static void cleanup_session(gpointer user_data)
@@ -671,78 +679,38 @@ static void cleanup_session(gpointer user_data)
        g_free(session);
 }
 
-static void release_session(gpointer key, gpointer value, gpointer user_data)
-{
-       struct connman_session *session = value;
-       DBusMessage *message;
-
-       DBG("owner %s path %s", session->owner, session->notify_path);
-
-       if (session->notify_watch > 0)
-               g_dbus_remove_watch(connection, session->notify_watch);
-
-       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;
-
-       dbus_message_set_no_reply(message, TRUE);
-
-       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 *conn, void *user_data)
+static connman_bool_t is_online(enum connman_service_state state)
 {
-       struct connman_session *session = user_data;
-
-       DBG("session %p, %s died", session, session->owner);
-
-       session_disconnect(session);
-}
-
-static DBusMessage *destroy_session(DBusConnection *conn,
-                                       DBusMessage *msg, void *user_data)
-{
-       struct connman_session *session = user_data;
-
-       DBG("session %p", session);
+       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:
+       case CONNMAN_SERVICE_STATE_READY:
+               break;
+       case CONNMAN_SERVICE_STATE_ONLINE:
+               return TRUE;
+       }
 
-       return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+       return FALSE;
 }
 
-static connman_bool_t is_connected(enum connman_service_state state)
+static connman_bool_t is_connecting(enum connman_service_state state)
 {
        switch (state) {
        case CONNMAN_SERVICE_STATE_UNKNOWN:
        case CONNMAN_SERVICE_STATE_IDLE:
+               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:
-               break;
-       case CONNMAN_SERVICE_STATE_READY:
        case CONNMAN_SERVICE_STATE_ONLINE:
-               return TRUE;
+               break;
        }
 
        return FALSE;
@@ -753,6 +721,7 @@ static connman_bool_t explicit_connect(enum connman_session_reason reason)
        switch (reason) {
        case CONNMAN_SESSION_REASON_UNKNOWN:
        case CONNMAN_SESSION_REASON_FREE_RIDE:
+       case CONNMAN_SESSION_REASON_DISCONNECT:
                break;
        case CONNMAN_SESSION_REASON_CONNECT:
        case CONNMAN_SESSION_REASON_PERIODIC:
@@ -762,37 +731,130 @@ static connman_bool_t explicit_connect(enum connman_session_reason reason)
        return FALSE;
 }
 
-static void test_and_disconnect(struct connman_session *session)
+static connman_bool_t explicit_disconnect(struct session_info *info)
 {
-       struct session_info *info = session->info;
-
        if (info->entry == NULL)
-               return;
+               return FALSE;
 
-       DBG("session %p reason %s service %p state %d",
-               session, reason2string(info->entry->reason),
+       DBG("reason %s service %p state %d",
+               reason2string(info->entry->reason),
                info->entry->service, info->entry->state);
 
+       if (info->entry->reason == CONNMAN_SESSION_REASON_UNKNOWN)
+               return FALSE;
+
        if (explicit_connect(info->entry->reason) == FALSE)
-               goto out;
+               return FALSE;
+
+       if (__connman_service_session_dec(info->entry->service) == FALSE)
+               return FALSE;
 
-       if (__connman_service_session_dec(info->entry->service) == TRUE)
-               goto out;
+       if (ecall_info != NULL && ecall_info != info)
+               return FALSE;
 
-       if (ecall_session != NULL && ecall_session != session)
-               goto out;
+       return TRUE;
+}
 
-       __connman_service_disconnect(info->entry->service);
+static gboolean call_disconnect(gpointer user_data)
+{
+       struct connman_service *service = user_data;
 
        /*
         * TODO: We should mark this entry as pending work. In case
         * disconnect fails we just unassign this session from the
         * service and can't do anything later on it
         */
+       DBG("disconnect service %p", service);
+       __connman_service_disconnect(service);
+
+       return FALSE;
+}
+
+static gboolean call_connect(gpointer user_data)
+{
+       struct connman_service *service = user_data;
+
+       DBG("connect service %p", service);
+       __connman_service_connect(service);
+
+       return FALSE;
+}
+
+static void deselect_service(struct session_info *info)
+{
+       struct connman_service *service;
+       connman_bool_t disconnect, online;
+
+       DBG("");
+
+       if (info->entry == NULL)
+               return;
+
+       disconnect = explicit_disconnect(info);
+
+       online = is_connecting(info->entry->state) == TRUE ||
+                       is_online(info->entry->state) == TRUE;
 
-out:
        info->online = FALSE;
+       info->entry->reason = CONNMAN_SESSION_REASON_UNKNOWN;
+
+       service = info->entry->service;
        info->entry = NULL;
+
+       DBG("disconnect %d online %d", disconnect, online);
+
+       if (disconnect == TRUE && online == TRUE)
+               g_timeout_add_seconds(0, call_disconnect, service);
+}
+
+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,
+                                       struct service_entry *entry)
+{
+       info->online = TRUE;
+
+       info->entry = entry;
+       info->entry->reason = info->reason;
+
+       if (explicit_connect(info->reason) == FALSE)
+               return;
+
+       __connman_service_session_inc(info->entry->service);
+}
+
+static void select_offline_service(struct session_info *info,
+                                       struct service_entry *entry)
+{
+       if (explicit_connect(info->reason) == FALSE)
+               return;
+
+       info->online = FALSE;
+
+       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);
+}
+
+static void select_service(struct session_info *info,
+                               struct service_entry *entry)
+{
+       DBG("service %p", entry->service);
+
+       if (is_online(entry->state) == TRUE)
+               select_online_service(info, entry);
+       else
+               select_offline_service(info, entry);
 }
 
 static void select_and_connect(struct connman_session *session,
@@ -801,10 +863,11 @@ static void select_and_connect(struct connman_session *session,
        struct session_info *info = session->info;
        struct service_entry *entry = NULL;
        GSequenceIter *iter;
-       connman_bool_t do_connect = FALSE;
 
        DBG("session %p reason %s", session, reason2string(reason));
 
+       info->reason = reason;
+
        iter = g_sequence_get_begin_iter(session->service_list);
 
        while (g_sequence_iter_is_end(iter) == FALSE) {
@@ -815,40 +878,17 @@ static void select_and_connect(struct connman_session *session,
                case CONNMAN_SERVICE_STATE_CONFIGURATION:
                case CONNMAN_SERVICE_STATE_READY:
                case CONNMAN_SERVICE_STATE_ONLINE:
-                       /* connecting or connected */
-                       break;
                case CONNMAN_SERVICE_STATE_IDLE:
                case CONNMAN_SERVICE_STATE_DISCONNECT:
-                       if (explicit_connect(reason) == TRUE)
-                               do_connect = TRUE;
-                       break;
+                       select_service(info, entry);
+                       return;
                case CONNMAN_SERVICE_STATE_UNKNOWN:
                case CONNMAN_SERVICE_STATE_FAILURE:
-                       entry = NULL;
                        break;
                }
 
-               if (entry != NULL)
-                       break;
-
                iter = g_sequence_iter_next(iter);
        }
-
-       if (info->entry != NULL && info->entry != entry)
-               test_and_disconnect(session);
-
-       if (entry != NULL) {
-               info->entry = entry;
-               info->entry->reason = reason;
-
-               if (explicit_connect(reason) == TRUE)
-                       __connman_service_session_inc(info->entry->service);
-
-               if (do_connect == TRUE)
-                       __connman_service_connect(info->entry->service);
-               else
-                       info->online = is_connected(entry->state);
-       }
 }
 
 static void session_changed(struct connman_session *session,
@@ -863,7 +903,14 @@ static void session_changed(struct connman_session *session,
         * 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) {
+               info->online = is_online(info->entry->state);
+               if (info_last->online != info->online)
+                       session->info_dirty = TRUE;
+       }
 
        switch (trigger) {
        case CONNMAN_SESSION_TRIGGER_UNKNOWN:
@@ -878,7 +925,7 @@ static void session_changed(struct connman_session *session,
                                 * This service is not part of this
                                 * session anymore.
                                 */
-                               test_and_disconnect(session);
+                               deselect_and_disconnect(session, info->reason);
                        }
                }
 
@@ -890,6 +937,8 @@ static void session_changed(struct connman_session *session,
                break;
        case CONNMAN_SESSION_TRIGGER_CONNECT:
                if (info->online == TRUE) {
+                       if (info->entry->reason == CONNMAN_SESSION_REASON_CONNECT)
+                               break;
                        info->entry->reason = CONNMAN_SESSION_REASON_CONNECT;
                        __connman_service_session_inc(info->entry->service);
                        break;
@@ -900,7 +949,8 @@ static void session_changed(struct connman_session *session,
 
                break;
        case CONNMAN_SESSION_TRIGGER_DISCONNECT:
-               test_and_disconnect(session);
+               deselect_and_disconnect(session,
+                                       CONNMAN_SESSION_REASON_DISCONNECT);
 
                break;
        case CONNMAN_SESSION_TRIGGER_PERIODIC:
@@ -915,24 +965,25 @@ static void session_changed(struct connman_session *session,
 
                break;
        case CONNMAN_SESSION_TRIGGER_SERVICE:
-               if (info->online == TRUE)
+               if (info->entry != NULL &&
+                               (is_connecting(info->entry->state) == TRUE ||
+                                       is_online(info->entry->state) == TRUE)) {
                        break;
+               }
 
-               if (info->stay_connected == TRUE) {
-                       DBG("StayConnected");
-                       select_and_connect(session,
-                                       CONNMAN_SESSION_REASON_CONNECT);
+               deselect_and_disconnect(session, info->reason);
 
-                       break;
+               if (info->reason == CONNMAN_SESSION_REASON_FREE_RIDE ||
+                               info->stay_connected == TRUE) {
+                       select_and_connect(session, info->reason);
                }
 
-               select_and_connect(session,
-                               CONNMAN_SESSION_REASON_FREE_RIDE);
-
                break;
        case CONNMAN_SESSION_TRIGGER_ECALL:
-               if (info->online == FALSE && info->entry->service != NULL)
-                       test_and_disconnect(session);
+               if (info->online == FALSE && info->entry != NULL &&
+                               info->entry->service != NULL) {
+                       deselect_and_disconnect(session, info->reason);
+               }
 
                break;
        }
@@ -947,10 +998,11 @@ static DBusMessage *connect_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_session != NULL && ecall_session != session)
+       if (ecall_info != NULL && ecall_info != info)
                return __connman_error_failed(msg, EBUSY);
 
        session_changed(session, CONNMAN_SESSION_TRIGGER_CONNECT);
@@ -962,10 +1014,11 @@ static DBusMessage *disconnect_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_session != NULL && ecall_session != session)
+       if (ecall_info != NULL && ecall_info != info)
                return __connman_error_failed(msg, EBUSY);
 
        session_changed(session, CONNMAN_SESSION_TRIGGER_DISCONNECT);
@@ -987,13 +1040,16 @@ static struct service_entry *create_service_entry(struct connman_service *servic
 
        entry->reason = CONNMAN_SESSION_REASON_UNKNOWN;
        entry->state = state;
-       entry->name = name;
+       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 = "";
+               entry->ifname = g_strdup("");
 
        type = connman_service_get_type(entry->service);
        entry->bearer = service2bearer(type);
@@ -1005,6 +1061,8 @@ static void destroy_service_entry(gpointer data)
 {
        struct service_entry *entry = data;
 
+       g_free(entry->ifname);
+
        g_free(entry);
 }
 
@@ -1070,19 +1128,19 @@ static void update_ecall(struct connman_session *session)
        struct session_info *info = session->info;
        struct session_info *info_last = session->info_last;
 
-       DBG("session %p ecall_session %p ecall %d -> %d", session,
-               ecall_session, info_last->ecall, info->ecall);
+       DBG("session %p ecall_info %p ecall %d -> %d", session,
+               ecall_info, info_last->ecall, info->ecall);
 
-       if (ecall_session == NULL) {
+       if (ecall_info == NULL) {
                if (!(info_last->ecall == FALSE && info->ecall == TRUE))
                        goto err;
 
-               ecall_session = session;
-       } else if (ecall_session == session) {
+               ecall_info = info;
+       } else if (ecall_info == info) {
                if (!(info_last->ecall == TRUE && info->ecall == FALSE))
                        goto err;
 
-               ecall_session = NULL;
+               ecall_info = NULL;
        } else {
                goto err;
        }
@@ -1209,6 +1267,68 @@ err:
        return __connman_error_invalid_arguments(msg);
 }
 
+static void release_session(gpointer key, gpointer value, gpointer user_data)
+{
+       struct connman_session *session = value;
+       DBusMessage *message;
+
+       DBG("owner %s path %s", session->owner, session->notify_path);
+
+       if (session->notify_watch > 0)
+               g_dbus_remove_watch(connection, session->notify_watch);
+
+       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;
+
+       dbus_message_set_no_reply(message, TRUE);
+
+       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);
+
+       deselect_and_disconnect(session,
+                               CONNMAN_SESSION_REASON_DISCONNECT);
+
+       g_hash_table_remove(session_hash, session->session_path);
+
+       return 0;
+}
+
+static void owner_disconnect(DBusConnection *conn, void *user_data)
+{
+       struct connman_session *session = user_data;
+
+       DBG("session %p, %s died", session, session->owner);
+
+       session_disconnect(session);
+}
+
+static DBusMessage *destroy_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 GDBusMethodTable session_methods[] = {
        { "Destroy",    "",   "", destroy_session    },
        { "Connect",    "",   "", connect_session    },
@@ -1239,7 +1359,7 @@ int __connman_session_create(DBusMessage *msg)
 
        DBG("owner %s", owner);
 
-       if (ecall_session != NULL) {
+       if (ecall_info != NULL) {
                /*
                 * If there is an emergency call already going on,
                 * ignore session creation attempt
@@ -1358,7 +1478,7 @@ 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_str_hash, g_str_equal,
+       session->service_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal,
                                                NULL, NULL);
 
        info->online = FALSE;
@@ -1407,7 +1527,7 @@ int __connman_session_create(DBusMessage *msg)
 
        update_allowed_bearers(session);
        if (info->ecall == TRUE) {
-               ecall_session = session;
+               ecall_info = info;
                update_ecall_sessions(session);
        }
 
@@ -1484,21 +1604,20 @@ void __connman_session_set_mode(connman_bool_t enable)
 {
        DBG("enable %d", enable);
 
-       if (sessionmode == enable)
-               return;
-
        sessionmode = enable;
 
        if (sessionmode == TRUE)
                __connman_service_disconnect_all();
 }
 
-static void service_add(struct connman_service *service)
+static void service_add(struct connman_service *service,
+                       const char *name)
 {
        GHashTableIter iter;
        GSequenceIter *iter_service_list;
        gpointer key, value;
        struct connman_session *session;
+       struct service_entry *entry;
 
        DBG("service %p", service);
 
@@ -1510,9 +1629,14 @@ static void service_add(struct connman_service *service)
                if (service_match(session, service) == FALSE)
                        continue;
 
+               entry = create_service_entry(service, name,
+                                               CONNMAN_SERVICE_STATE_IDLE);
+               if (entry == NULL)
+                       continue;
+
                iter_service_list =
                        g_sequence_insert_sorted(session->service_list,
-                                                       service, sort_services,
+                                                       entry, sort_services,
                                                        session);
 
                g_hash_table_replace(session->service_hash, service,
@@ -1545,7 +1669,8 @@ static void service_remove(struct connman_service *service)
 
                g_sequence_remove(iter);
 
-               info->entry = NULL;
+               if (info->entry != NULL && info->entry->service == service)
+                       info->entry = NULL;
                session_changed(session, CONNMAN_SESSION_TRIGGER_SERVICE);
        }
 }
@@ -1555,23 +1680,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) {
-               session = value;
-               info = session->info;
-               info_last = session->info_last;
+               struct connman_session *session = value;
+               GSequenceIter *service_iter;
 
-               if (info->entry != NULL && info->entry->service == service) {
-                       info->entry->state = state;
-                       info->online = is_connected(info->entry->state);
-                       if (info_last->online != info->online)
-                               session->info_dirty = TRUE;
+               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;
                }
 
                session_changed(session,
@@ -1649,6 +1772,7 @@ void __connman_session_cleanup(void)
 
        g_hash_table_foreach(session_hash, release_session, NULL);
        g_hash_table_destroy(session_hash);
+       session_hash = NULL;
 
        dbus_connection_unref(connection);
 }