qtmobility/src/bearer/qnetworksession_maemo.cpp
branchRCL_3
changeset 1 5822d84012fb
parent 0 cfcbf08528c4
child 3 eb34711bcc75
--- a/qtmobility/src/bearer/qnetworksession_maemo.cpp	Thu Apr 01 08:30:34 2010 +0300
+++ b/qtmobility/src/bearer/qnetworksession_maemo.cpp	Thu Apr 15 08:16:03 2010 +0300
@@ -42,16 +42,12 @@
 #include <QHash>
 
 #include "qnetworksession_maemo_p.h"
-#include <dbus/dbus.h>
-#include <dbus/dbus-glib-lowlevel.h>
 
 #include <maemo_icd.h>
 #include <iapconf.h>
 #include <proxyconf.h>
 
-#include <sys/types.h>
 #include <ifaddrs.h>
-#include <sys/socket.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 
@@ -60,262 +56,73 @@
 static QHash<QString, QVariant> properties;
 
 static QString get_network_interface();
-static DBusConnection *dbus_connection;
-static DBusHandlerResult signal_handler(DBusConnection *connection,
-					DBusMessage *message,
-					void *user_data);
 
-#define ICD_DBUS_MATCH		"type='signal'," \
-				"interface='" ICD_DBUS_INTERFACE "'," \
-				"path='" ICD_DBUS_PATH "'"
-
-
-static inline DBusConnection *get_dbus_conn(DBusError *error)
-{
-    DBusConnection *conn = dbus_bus_get(DBUS_BUS_SYSTEM, error);
-#ifdef BEARER_MANAGEMENT_DEBUG
-    qDebug() << "Listening to bus" << dbus_bus_get_unique_name(conn);
-#endif
-
-    return conn;
-}
-
-
-/* Helper class that monitors the Icd status messages and
- * can change the IAP status accordingly. This is a singleton.
- */
-class IcdListener : public QObject
+void QNetworkSessionPrivate::iapStateChanged(const QString& iapid, uint icd_connection_state)
 {
-    Q_OBJECT
-
-public:
-    IcdListener() : first_call(true) { }
-    friend DBusHandlerResult signal_handler(DBusConnection *connection,
-					    DBusMessage *message,
-					    void *user_data);
-    void setup(QNetworkSessionPrivate *d);
-    void cleanup();
-    void cleanupSession(QNetworkSessionPrivate *ptr);
-
-    enum IapConnectionStatus {
-	/* The IAP was connected */
-	CONNECTED = 0,
-	/* The IAP was disconnected */
-	DISCONNECTED,
-	/* The IAP is disconnecting */
-	DISCONNECTING,
-	/* The IAP has a network address, but is not yet fully connected */
-	NETWORK_UP
-    };
-
-private:
-    void icdSignalReceived(QString&, QString&, QString&);
-    bool first_call;
-    QHash<QString, QNetworkSessionPrivate* > sessions;
-};
-
-Q_GLOBAL_STATIC(IcdListener, icdListener);
- 
-
-static DBusHandlerResult signal_handler(DBusConnection *,
-					DBusMessage *message,
-					void *user_data)
-{
-    if (dbus_message_is_signal(message,
-				ICD_DBUS_INTERFACE,
-				ICD_STATUS_CHANGED_SIG)) {
-
-	IcdListener *icd = (IcdListener *)user_data;
-	DBusError error;
-	dbus_error_init(&error);
-
-	char *iap_id = 0;
-	char *network_type = 0;
-	char *state = 0;
-
-	if (dbus_message_get_args(message, &error,
-				    DBUS_TYPE_STRING, &iap_id,
-				    DBUS_TYPE_STRING, &network_type,
-				    DBUS_TYPE_STRING, &state,
-				    DBUS_TYPE_INVALID) == FALSE) {
-	    qWarning() << QString("Failed to parse icd status signal: %1").arg(error.message);
-        } else {
-	    QString _iap_id(iap_id);
-	    QString _network_type(network_type);
-	    QString _state(state);
-
-	    icd->icdSignalReceived(_iap_id, _network_type, _state);
-	}
-
-	dbus_error_free(&error);
-        return DBUS_HANDLER_RESULT_HANDLED;
+    if ((publicConfig.type() == QNetworkConfiguration::UserChoice) && opened) {
+        updateIdentifier(iapid);
     }
 
-    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-}
-
-
-void IcdListener::setup(QNetworkSessionPrivate *d)
-{
-    if (first_call) {
-	// We use the old Icd dbus interface like in ConIC
-	DBusError error;
-	dbus_error_init(&error);
-
-	dbus_connection = get_dbus_conn(&error);
-	if (dbus_error_is_set(&error)) {
-	    qWarning() << "Cannot get dbus connection.";
-	    dbus_error_free(&error);
-	    return;
-	}
-
-	static struct DBusObjectPathVTable icd_vtable;
-	icd_vtable.message_function = signal_handler;
-
-	dbus_bus_add_match(dbus_connection, ICD_DBUS_MATCH, &error);
-	if (dbus_error_is_set(&error)) {
-	    qWarning() << "Cannot add match" << ICD_DBUS_MATCH;
-	    dbus_error_free(&error);
-	    return;
-	}
-
-	if (dbus_connection_register_object_path(dbus_connection,
-						    ICD_DBUS_PATH,
-						    &icd_vtable,
-						    (void*)this) == FALSE) {
-	    qWarning() << "Cannot register dbus signal handler, interface"<< ICD_DBUS_INTERFACE << "path" << ICD_DBUS_PATH;
-	    dbus_error_free(&error);
-	    return;
-	}
-
-#ifdef BEARER_MANAGEMENT_DEBUG
-	qDebug() << "Listening" << ICD_STATUS_CHANGED_SIG << "signal from" << ICD_DBUS_SERVICE;
-#endif
-	first_call = false;
-	dbus_error_free(&error);
-    }
-
-    QString id = d->activeConfig.identifier();
-    if (!sessions.contains(id)) {
-	QNetworkSessionPrivate *ptr = d;
-	sessions.insert(id, ptr);
+    if (((publicConfig.type() == QNetworkConfiguration::UserChoice) && (activeConfig.d->id == iapid)) ||
+        (publicConfig.d->id == iapid)) {
+        switch (icd_connection_state) {
+        case ICD_STATE_CONNECTING:
+            updateState(QNetworkSession::Connecting);
+            break;
+        case ICD_STATE_CONNECTED:
+            updateState(QNetworkSession::Connected);
+            break;
+        case ICD_STATE_DISCONNECTING:
+            updateState(QNetworkSession::Closing);
+            break;
+        case ICD_STATE_DISCONNECTED:
+            updateState(QNetworkSession::Disconnected);
+            break;
+        default:
+            break;
+        }
     }
 }
 
-
-void IcdListener::icdSignalReceived(QString& iap_id,
-#ifdef BEARER_MANAGEMENT_DEBUG
-				    QString& network_type,
-#else
-				    QString&,
-#endif
-				    QString& state)
-{
-    if (iap_id == OSSO_IAP_SCAN) // icd sends scan status signals which we will ignore
-	return;
-
-#ifdef BEARER_MANAGEMENT_DEBUG
-    qDebug() << "Status received:" << iap_id << "type" << network_type << "state" << state;
-#endif
-
-    if (!sessions.contains(iap_id)) {
-#ifdef BEARER_MANAGEMENT_DEBUG
-	qDebug() << "No session for IAP" << iap_id;
-#endif
-	return;
-    }
-
-    QNetworkSessionPrivate *session = sessions.value(iap_id);
-    QNetworkConfiguration ap_conf = session->manager.configurationFromIdentifier(iap_id);
-    if (!ap_conf.isValid()) {
-#ifdef BEARER_MANAGEMENT_DEBUG
-	qDebug() << "Unknown IAP" << iap_id;
-#endif
-	return;
-    }
-
-    IapConnectionStatus status;
-
-    if (state == "IDLE") {
-	status = DISCONNECTED;
-    } else if (state == "CONNECTED") {
-	status = CONNECTED;
-    } else if (state == "NETWORKUP") {
-	status = NETWORK_UP;
-    } else {
-	//qDebug() << "Unknown state" << state;
-	return;
-    }
-
-    if (status == DISCONNECTED) {
-	if (ap_conf.state() == QNetworkConfiguration::Active) {
-	    /* The IAP was just disconnected by Icd */
-	    session->updateState(QNetworkSession::Disconnected);
-	} else {
-#ifdef BEARER_MANAGEMENT_DEBUG
-	    qDebug() << "Got a network disconnect when in state" << ap_conf.state();
-#endif
-	}
-    } else if (status == CONNECTED) {
-	/* The IAP was just connected by Icd */
-	session->updateState(QNetworkSession::Connected);
-	session->updateIdentifier(iap_id);
-
-	if (session->publicConfig.identifier() == OSSO_IAP_ANY) {
-#ifdef BEARER_MANAGEMENT_DEBUG
-	    qDebug() << "IAP" << iap_id << "connected when connecting to" << OSSO_IAP_ANY;
-#endif
-	} else {
-#ifdef BEARER_MANAGEMENT_DEBUG
-	    qDebug() << "IAP" << iap_id << "connected";
-#endif
-	}
-    }
-
-    return;
-}
-
-
-void IcdListener::cleanup()
-{
-    if (!first_call) {
-	dbus_bus_remove_match(dbus_connection, ICD_DBUS_MATCH, NULL);
-	dbus_connection_unref(dbus_connection);
-    }
-}
-
-
-void IcdListener::cleanupSession(QNetworkSessionPrivate *ptr)
-{
-    if (ptr->publicConfig.type() == QNetworkConfiguration::UserChoice)
-        (void)sessions.take(ptr->activeConfig.identifier());
-    else
-        (void)sessions.take(ptr->publicConfig.identifier());
-}
-
-
 void QNetworkSessionPrivate::cleanupSession(void)
 {
-    icdListener()->cleanupSession(this);
-
     QObject::disconnect(q, SIGNAL(stateChanged(QNetworkSession::State)), this, SLOT(updateProxies(QNetworkSession::State)));
 }
 
 
 void QNetworkSessionPrivate::updateState(QNetworkSession::State newState)
 {
-    if( newState != state) {
-        state = newState;
-
-	if (state == QNetworkSession::Disconnected) {
+    if (newState != state) {
+        if (newState == QNetworkSession::Disconnected) {
+            if (isOpen) {
+                // The Session was aborted by the user or system
+                lastError = QNetworkSession::SessionAbortedError;
+                emit q->error(lastError);
+                emit q->closed();
+            }
+            if (m_stopTimer.isActive()) {
+                // Session was closed by calling stop()
+                m_stopTimer.stop();
+            }
             isOpen = false;
+            opened = false;
 	    currentNetworkInterface.clear();
-	    if (publicConfig.type() == QNetworkConfiguration::UserChoice)
-		activeConfig.d->state = QNetworkConfiguration::Defined;
-	    publicConfig.d->state = QNetworkConfiguration::Defined;
-
-	} else if (state == QNetworkSession::Connected) {
-            isOpen = true;
+            if (publicConfig.type() == QNetworkConfiguration::UserChoice) {
+                copyConfig(publicConfig, activeConfig);
+                activeConfig.d->state = QNetworkConfiguration::Defined;
+            } else {
+                if (!activeConfig.isValid()) {
+                    // Active configuration (IAP) was removed from system
+                    // => Connection was disconnected and configuration became
+                    //    invalid
+                    // => Also Session state must be changed to invalid
+                    newState = QNetworkSession::Invalid;
+                }
+            }
+        } else if (newState == QNetworkSession::Connected) {
+            if (opened) {
+                isOpen = true;
+            }
 	    if (publicConfig.type() == QNetworkConfiguration::UserChoice) {
 		activeConfig.d->state = QNetworkConfiguration::Active;
 		activeConfig.d->type = QNetworkConfiguration::InternetAccessPoint;
@@ -323,12 +130,15 @@
 	    publicConfig.d->state = QNetworkConfiguration::Active;
 	}
 
-	emit q->stateChanged(newState);
+        if (newState != state) {
+            state = newState;
+            emit q->stateChanged(newState);
+        }
     }
 }
 
 
-void QNetworkSessionPrivate::updateIdentifier(QString &newId)
+void QNetworkSessionPrivate::updateIdentifier(const QString &newId)
 {
     if (publicConfig.type() == QNetworkConfiguration::UserChoice) {
 	activeConfig.d->network_attrs |= ICD_NW_ATTR_IAPNAME;
@@ -357,7 +167,7 @@
 	return 0;
     }
 
-    foreach (Maemo::IcdStatisticsResult res, stats_results) {
+    foreach (const Maemo::IcdStatisticsResult &res, stats_results) {
 	if (res.params.network_attrs & ICD_NW_ATTR_IAPNAME) {
 	    /* network_id is the IAP UUID */
 	    if (QString(res.params.network_id.data()) == activeConfig.identifier()) {
@@ -433,9 +243,6 @@
  */
 void QNetworkSessionPrivate::syncStateWithInterface()
 {
-    /* Start to listen Icd status messages. */
-    icdListener()->setup(this);
-
     /* Initially we are not active although the configuration might be in
      * connected state.
      */
@@ -447,10 +254,10 @@
     if (publicConfig.d.data()) {
 	QNetworkConfigurationManagerPrivate* mgr = (QNetworkConfigurationManagerPrivate*)publicConfig.d.data()->manager;
 	if (mgr) {
-	    QObject::connect(mgr, SIGNAL(configurationChanged(QNetworkConfiguration)),
-			    this, SLOT(configurationChanged(QNetworkConfiguration)));
+            connect(mgr, SIGNAL(iapStateChanged(const QString&, uint)),
+                    this, SLOT(iapStateChanged(const QString&, uint)));
 	} else {
-	    qWarning()<<"Manager object not set when trying to connect configurationChanged signal. Your configuration object is not correctly setup, did you remember to call manager.updateConfigurations() before creating session object?";
+            qWarning()<<"Manager object not set when trying to connect iapStateChanged signal. Your configuration object is not correctly setup, did you remember to call manager.updateConfigurations() before creating session object?";
 	    state = QNetworkSession::Invalid;
 	    lastError = QNetworkSession::UnknownSessionError;
 	    return;
@@ -464,14 +271,14 @@
 
     switch (publicConfig.type()) {
     case QNetworkConfiguration::InternetAccessPoint:
-	activeConfig = publicConfig;
+        activeConfig = publicConfig;
         break;
     case QNetworkConfiguration::ServiceNetwork:
-	serviceConfig = publicConfig;
+        serviceConfig = publicConfig;
 	break;
     case QNetworkConfiguration::UserChoice:
 	// active config will contain correct data after open() has succeeded
-	copyConfig(publicConfig, activeConfig);
+        copyConfig(publicConfig, activeConfig);
 
 	/* We create new configuration that holds the actual configuration
 	 * returned by icd. This way publicConfig still contains the
@@ -505,7 +312,6 @@
      * supports only one connection anyway.
      */
     if (icd.state(state_results) && !state_results.isEmpty()) {
-
 	/* If we did not get full state back, then we are not
 	 * connected and can skip the next part.
 	 */
@@ -518,46 +324,44 @@
 	     */
 	    if (publicConfig.type() == QNetworkConfiguration::UserChoice ||
 		    publicConfig.d->id == state_results.first().params.network_id) {
-
 		switch (state_results.first().state) {
 		case ICD_STATE_DISCONNECTED:
-		    state = QNetworkSession::Disconnected;
+                    state = QNetworkSession::Disconnected;
 		    if (activeConfig.d.data())
 			activeConfig.d->isValid = true;
 		    break;
 		case ICD_STATE_CONNECTING:
-		    state = QNetworkSession::Connecting;
+                    state = QNetworkSession::Connecting;
 		    if (activeConfig.d.data())
 			activeConfig.d->isValid = true;
 		    break;
 		case ICD_STATE_CONNECTED:
 		    {
-			if (!state_results.first().error.isEmpty())
+                        if (!state_results.first().error.isEmpty())
 			    break;
-                        
+
                         const QString id = state_results.first().params.network_id;
 
-			QNetworkConfigurationManagerPrivate *mgr = (QNetworkConfigurationManagerPrivate*)activeConfig.d.data()->manager;
+                        QNetworkConfigurationManagerPrivate *mgr = (QNetworkConfigurationManagerPrivate*)publicConfig.d.data()->manager;
 			if (mgr->accessPointConfigurations.contains(id)) {
                             //we don't want the copied data if the config is already known by the manager
                             //just reuse it so that existing references to the old data get the same update
-			    QExplicitlySharedDataPointer<QNetworkConfigurationPrivate> priv = mgr->accessPointConfigurations.value(activeConfig.d->id);
+                            QExplicitlySharedDataPointer<QNetworkConfigurationPrivate> priv = mgr->accessPointConfigurations.value(id);
                             activeConfig.d = priv;
                         }
 
-
 			state = QNetworkSession::Connected;
-			activeConfig.d->network_id = state_results.first().params.network_id;
-			activeConfig.d->id = activeConfig.d->network_id;
-			activeConfig.d->network_attrs = state_results.first().params.network_attrs;
-			activeConfig.d->iap_type = state_results.first().params.network_type;
-			activeConfig.d->service_type = state_results.first().params.service_type;
-			activeConfig.d->service_id = state_results.first().params.service_id;
-			activeConfig.d->service_attrs = state_results.first().params.service_attrs;
-			activeConfig.d->type = QNetworkConfiguration::InternetAccessPoint;
-			activeConfig.d->state = QNetworkConfiguration::Active;
-			activeConfig.d->isValid = true;
-			currentNetworkInterface = get_network_interface();
+                        activeConfig.d->network_id = state_results.first().params.network_id;
+                        activeConfig.d->id = activeConfig.d->network_id;
+                        activeConfig.d->network_attrs = state_results.first().params.network_attrs;
+                        activeConfig.d->iap_type = state_results.first().params.network_type;
+                        activeConfig.d->service_type = state_results.first().params.service_type;
+                        activeConfig.d->service_id = state_results.first().params.service_id;
+                        activeConfig.d->service_attrs = state_results.first().params.service_attrs;
+                        activeConfig.d->type = QNetworkConfiguration::InternetAccessPoint;
+                        activeConfig.d->state = QNetworkConfiguration::Active;
+                        activeConfig.d->isValid = true;
+                        currentNetworkInterface = get_network_interface();
 
 			Maemo::IAPConf iap_name(activeConfig.d->id);
 			QString name_value = iap_name.value("name").toString();
@@ -566,7 +370,6 @@
 			else
 			    activeConfig.d->name = activeConfig.d->id;
 
-
 			// Add the new active configuration to manager or update the old config
 			mgr = (QNetworkConfigurationManagerPrivate*)activeConfig.d.data()->manager;
 			if (!(mgr->accessPointConfigurations.contains(activeConfig.d->id))) {
@@ -581,23 +384,17 @@
 			    //qDebug()<<"New configuration"<<activeConfig.d->id<<"added to manager in sync";
 #endif
 
-			} else {
-			    mgr->configurationChanged((QNetworkConfigurationPrivate*)(activeConfig.d.data()));
-#ifdef BEARER_MANAGEMENT_DEBUG
-			    //qDebug()<<"Existing configuration"<<activeConfig.d->id<<"updated in manager in sync";
-#endif
-			}
-
+                        }
 		    }
 		    break;
 
 		case ICD_STATE_DISCONNECTING:
-		    state = QNetworkSession::Closing;
+                    state = QNetworkSession::Closing;
 		    if (activeConfig.d.data())
 			activeConfig.d->isValid = true;
 		    break;
 		default:
-		    break;
+                    break;
 		}
 	    }
 	} else {
@@ -686,7 +483,6 @@
         state = QNetworkSession::NotAvailable;
     } else if ((activeConfig.state() & QNetworkConfiguration::Undefined) == QNetworkConfiguration::Undefined) {
         state = QNetworkSession::NotAvailable;
-	clearConfiguration(activeConfig);
     }
 
     bool oldActive = isOpen;
@@ -701,7 +497,7 @@
     if (oldState != state) {
         emit q->stateChanged(state);
 
-	if (state == QNetworkSession::Disconnected) {
+        if (state == QNetworkSession::Disconnected && oldActive) {
 #ifdef BEARER_MANAGEMENT_DEBUG
 	    //qDebug()<<"session aborted error emitted for"<<activeConfig.identifier();
 #endif
@@ -715,16 +511,6 @@
 #endif
 }
 
-
-void QNetworkSessionPrivate::configurationChanged(const QNetworkConfiguration &config)
-{
-    if (serviceConfig.isValid() && (config == serviceConfig || config == activeConfig))
-        updateStateFromServiceNetwork();
-    else if (config == activeConfig)
-        updateStateFromActiveConfig();
-}
-
-
 static QString get_network_interface()
 {
     Maemo::Icd icd;
@@ -761,14 +547,16 @@
     }
 
     for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
-	family = ifa->ifa_addr->sa_family;
-	if (family != AF_INET) {
-	    continue; /* Currently only IPv4 is supported by icd dbus interface */
-	}
-	if (((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr == addr.s_addr) {
-	    iface = QString(ifa->ifa_name);
-	    break;
-	}
+        if (ifa->ifa_addr) {
+            family = ifa->ifa_addr->sa_family;
+            if (family != AF_INET) {
+                continue; /* Currently only IPv4 is supported by icd dbus interface */
+            }
+            if (((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr == addr.s_addr) {
+                iface = QString(ifa->ifa_name);
+                break;
+            }
+        }
     }
 
     freeifaddrs(ifaddr);
@@ -778,11 +566,18 @@
 
 void QNetworkSessionPrivate::open()
 {
+    if (m_stopTimer.isActive()) {
+        m_stopTimer.stop();
+    }
+    if (!publicConfig.isValid()) {
+        lastError = QNetworkSession::InvalidConfigurationError;
+        emit q->error(lastError);
+        return;
+    }
     if (serviceConfig.isValid()) {
         lastError = QNetworkSession::OperationNotSupportedError;
         emit q->error(lastError);
     } else if (!isOpen) {
-
 	if (publicConfig.type() == QNetworkConfiguration::UserChoice) {
 	    /* Caller is trying to connect to default IAP.
 	     * At this time we will not know the IAP details so we just
@@ -893,7 +688,7 @@
 	    updateState(QNetworkSession::Disconnected);
 	    emit q->error(QNetworkSession::InvalidConfigurationError);
 	    if (publicConfig.type() == QNetworkConfiguration::UserChoice)
-		cleanupAnyConfiguration();
+                copyConfig(publicConfig, activeConfig);
 	    return;
 	}
 
@@ -969,8 +764,7 @@
 	    }
 #endif
 #endif
-
-	    QNetworkConfigurationManagerPrivate *mgr = (QNetworkConfigurationManagerPrivate*)config.d.data()->manager;
+            QNetworkConfigurationManagerPrivate *mgr = (QNetworkConfigurationManagerPrivate*)publicConfig.d.data()->manager;
             if (!mgr->accessPointConfigurations.contains(result)) {
 		QExplicitlySharedDataPointer<QNetworkConfigurationPrivate> ptr = config.d;
 		mgr->accessPointConfigurations.insert(result, ptr);
@@ -984,13 +778,13 @@
 #endif
 
 	    } else {
-		QExplicitlySharedDataPointer<QNetworkConfigurationPrivate> priv = mgr->accessPointConfigurations.value(result);
+                QExplicitlySharedDataPointer<QNetworkConfigurationPrivate> priv = mgr->accessPointConfigurations.value(result);
 		QNetworkConfiguration reference;
 		reference.d = priv;
                 copyConfig(config, reference, false);
+                reference.d.data()->id = result; // Note: Id was not copied in copyConfig() function
                 config = reference;
                 activeConfig = reference;
-		mgr->configurationChanged((QNetworkConfigurationPrivate*)(config.d.data()));
 
 #ifdef BEARER_MANAGEMENT_DEBUG
 		//qDebug()<<"Existing configuration"<<result<<"updated in manager in open";
@@ -1006,21 +800,11 @@
 #endif
 	updateState(QNetworkSession::Disconnected);
 	if (publicConfig.type() == QNetworkConfiguration::UserChoice)
-	    cleanupAnyConfiguration();
+            copyConfig(publicConfig, activeConfig);
 	emit q->error(QNetworkSession::UnknownSessionError);
     }
 }
 
-
-void QNetworkSessionPrivate::cleanupAnyConfiguration()
-{
-#ifdef BEARER_MANAGEMENT_DEBUG
-    qDebug()<<"Removing configuration created for" << activeConfig.d->id;
-#endif
-    activeConfig = publicConfig;
-}
-
-
 void QNetworkSessionPrivate::close()
 {
     if (serviceConfig.isValid()) {
@@ -1041,28 +825,29 @@
         emit q->error(lastError);
     } else {
         if ((activeConfig.state() & QNetworkConfiguration::Active) == QNetworkConfiguration::Active) {
-            state = QNetworkSession::Closing;
-            emit q->stateChanged(state);
-
-	    Maemo::Icd icd;
+            if (!m_stopTimer.isActive()) {
+                Maemo::Icd icd;
 #ifdef BEARER_MANAGEMENT_DEBUG
-	    qDebug() << "stopping session" << publicConfig.identifier();
+                qDebug() << "stopping session" << publicConfig.identifier();
 #endif
-	    icd.disconnect(ICD_CONNECTION_FLAG_APPLICATION_EVENT);
-	    startTime = QDateTime();
+                state = QNetworkSession::Closing;
+                emit q->stateChanged(state);
+
+                opened = false;
+                isOpen = false;
 
-	    /* Note that the state will go disconnected in
-	     * updateStateFromActiveConfig() which gets called after
-	     * configurationChanged is emitted (below).
-	     */
+                icd.disconnect(ICD_CONNECTION_FLAG_APPLICATION_EVENT);
+                startTime = QDateTime();
 
-	    activeConfig.d->state = QNetworkConfiguration::Discovered;
-	    QNetworkConfigurationManagerPrivate *mgr = (QNetworkConfigurationManagerPrivate*)activeConfig.d.data()->manager;
-	    mgr->configurationChanged((QNetworkConfigurationPrivate*)activeConfig.d.data());
+                /* Note: Session state will change to disconnected
+                 *       as soon as QNetworkConfigurationManager sends
+                 *       corresponding iapStateChanged signal.
+                 */
 
-	    opened = false;
-	    isOpen = false;
-
+                // Make sure that this Session will send closed signal
+                // even though ICD connection will not ever get closed
+                m_stopTimer.start(ICD_SHORT_CONNECT_TIMEOUT); // 10 seconds wait
+            }
         } else {
 	    opened = false;
 	    isOpen = false;
@@ -1071,6 +856,14 @@
     }
 }
 
+void QNetworkSessionPrivate::finishStopBySendingClosedSignal()
+{
+    if ((activeConfig.state() & QNetworkConfiguration::Active) == QNetworkConfiguration::Active) {
+        state = QNetworkSession::Connected;
+        emit q->stateChanged(state);
+    }
+    emit q->closed();
+}
 
 void QNetworkSessionPrivate::migrate()
 {
@@ -1186,7 +979,6 @@
 }
 
 
-#include "qnetworksession_maemo.moc"
 #include "moc_qnetworksession_maemo_p.cpp"
 
 QTM_END_NAMESPACE