qtmobility/src/bearer/qnetworksession_s60_p.cpp
branchRCL_3
changeset 13 4203353e74ea
parent 10 4ea83c148e84
child 21 885c2596c964
--- a/qtmobility/src/bearer/qnetworksession_s60_p.cpp	Wed Jun 09 10:36:00 2010 +0300
+++ b/qtmobility/src/bearer/qnetworksession_s60_p.cpp	Mon Jun 21 16:36:26 2010 +0300
@@ -1,6 +1,6 @@
 /****************************************************************************
 **
-** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
 ** All rights reserved.
 ** Contact: Nokia Corporation (qt-info@nokia.com)
 **
@@ -53,15 +53,29 @@
 
 QNetworkSessionPrivate::QNetworkSessionPrivate()
     : CActive(CActive::EPriorityUserInput), state(QNetworkSession::Invalid),
-      isOpen(false), ipConnectionNotifier(0), iHandleStateNotificationsFromManager(false),
-      iFirstSync(true), iStoppedByUser(false), iClosedByUser(false), iDeprecatedConnectionId(0),
-      iError(QNetworkSession::UnknownSessionError), iALREnabled(0), iConnectInBackground(false)
+      isOpen(false), iDynamicUnSetdefaultif(0), ipConnectionNotifier(0),
+      iHandleStateNotificationsFromManager(false), iFirstSync(true), iStoppedByUser(false),
+      iClosedByUser(false), iDeprecatedConnectionId(0), iError(QNetworkSession::UnknownSessionError),
+      iALREnabled(0), iConnectInBackground(false)
 {
     CActiveScheduler::Add(this);
 
 #ifdef SNAP_FUNCTIONALITY_AVAILABLE
     iMobility = NULL;
 #endif
+    // Try to load "Open C" dll dynamically and
+    // try to attach to unsetdefaultif function dynamically.
+    // This is to avoid build breaks with old OpenC versions.
+    if (iOpenCLibrary.Load(_L("libc")) == KErrNone) {
+        iDynamicUnSetdefaultif = (TOpenCUnSetdefaultifFunction)iOpenCLibrary.Lookup(597);
+    }
+#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
+    qDebug() << "QNS this : " << QString::number((uint)this) << " - ";
+    if (iDynamicUnSetdefaultif)
+        qDebug() << "dynamic setdefaultif() resolution succeeded. ";
+    else
+        qDebug() << "dynamic setdefaultif() resolution failed. ";
+#endif
 
     TRAP_IGNORE(iConnectionMonitor.ConnectL());
 }
@@ -76,9 +90,6 @@
     delete ipConnectionNotifier;
     ipConnectionNotifier = NULL;
 
-    // Cancel possible RConnection::Start()
-    Cancel();
-    
 #ifdef SNAP_FUNCTIONALITY_AVAILABLE
     if (iMobility) {
         delete iMobility;
@@ -86,13 +97,16 @@
     }
 #endif
 
-    iConnection.Close();
+    // Cancel possible RConnection::Start()
+    Cancel();
     iSocketServ.Close();
     
     // Close global 'Open C' RConnection
+    // Clears also possible unsetdefaultif() flags.
     setdefaultif(0);
     
     iConnectionMonitor.Close();
+    iOpenCLibrary.Close();
 }
 
 void QNetworkSessionPrivate::configurationStateChanged(TUint32 accessPointId, TUint32 connMonId, QNetworkSession::State newState)
@@ -352,39 +366,6 @@
     }
     
     if (publicConfig.type() == QNetworkConfiguration::InternetAccessPoint) {
-        // Search through existing connections.
-        // If there is already connection which matches to given IAP
-        // try to attach to existing connection.
-        TBool connected(EFalse);
-        TConnectionInfoBuf connInfo;
-        TUint count;
-        if (iConnection.EnumerateConnections(count) == KErrNone) {
-            for (TUint i=1; i<=count; i++) {
-                // Note: GetConnectionInfo expects 1-based index.
-                if (iConnection.GetConnectionInfo(i, connInfo) == KErrNone) {
-                    if (connInfo().iIapId == publicConfig.d.data()->numericId) {
-                        if (iConnection.Attach(connInfo, RConnection::EAttachTypeNormal) == KErrNone) {
-                            activeConfig = publicConfig;
-                            activeInterface = interface(activeConfig.d.data()->numericId);
-                            connected = ETrue;
-                            startTime = QDateTime::currentDateTime();
-                            // Use name of the IAP to open global 'Open C' RConnection
-                            QByteArray nameAsByteArray = publicConfig.name().toUtf8();
-                            ifreq ifr;
-                            memset(&ifr, 0, sizeof(struct ifreq));
-                            strcpy(ifr.ifr_name, nameAsByteArray.constData());
-                            error = setdefaultif(&ifr);
-                            isOpen = true;
-                            // Make sure that state will be Connected
-                            newState(QNetworkSession::Connected);
-                            emit quitPendingWaitsForOpened();
-                            break;
-                        }
-                    }
-                }
-            }
-        }
-        if (!connected) {
 #ifdef OCC_FUNCTIONALITY_AVAILABLE
             // With One Click Connectivity (Symbian^3 onwards) it is possible
             // to connect silently, without any popups.
@@ -405,9 +386,12 @@
                 SetActive();
             }
             newState(QNetworkSession::Connecting);
-        }
     } else if (publicConfig.type() == QNetworkConfiguration::ServiceNetwork) {
 #ifdef OCC_FUNCTIONALITY_AVAILABLE
+        // On Symbian^3 if service network is not reachable, it triggers a UI (aka EasyWLAN) where
+        // user can create new IAPs. To detect this, we need to store the number of IAPs
+        // there was before connection was started.
+        iKnownConfigsBeforeConnectionStart = ((QNetworkConfigurationManagerPrivate*)publicConfig.d.data()->manager)->accessPointConfigurations.keys();
         TConnPrefList snapPref;
         TExtendedConnPref prefs;
         prefs.SetSnapId(publicConfig.d.data()->numericId);
@@ -477,19 +461,23 @@
             << "close() called, session state is: " << state << " and isOpen is : "
             << isOpen;
 #endif
-    if (!isOpen) {
+
+    if (!isOpen && state != QNetworkSession::Connecting) {
         return;
     }
     // Mark this session as closed-by-user so that we are able to report
     // distinguish between stop() and close() state transitions
     // when reporting.
     iClosedByUser = true;
+    isOpen = false;
 
-    isOpen = false;
+#ifndef OCC_FUNCTIONALITY_AVAILABLE
+    // On Symbian^3 we need to keep track of active configuration longer
+    // in case of empty-SNAP-triggered EasyWLAN.
     activeConfig = QNetworkConfiguration();
+#endif
     serviceConfig = QNetworkConfiguration();
     
-    Cancel();
 #ifdef SNAP_FUNCTIONALITY_AVAILABLE
     if (iMobility) {
         delete iMobility;
@@ -503,17 +491,39 @@
         iHandleStateNotificationsFromManager = true;
     }
     
-    iConnection.Close();
+    Cancel(); // closes iConnection
     iSocketServ.Close();
     
-    // Close global 'Open C' RConnection
-    setdefaultif(0);
+    // Close global 'Open C' RConnection. If OpenC supports,
+    // close the defaultif for good to avoid difficult timing
+    // and bouncing issues of network going immediately back up
+    //  because of e.g. select() thread etc.
+    if (iDynamicUnSetdefaultif) {
+        iDynamicUnSetdefaultif();
+    } else {
+        setdefaultif(0);
+    }
 
-    if (publicConfig.type() == QNetworkConfiguration::UserChoice) {
+    // If UserChoice, go down immediately. If some other configuration,
+    // go down immediately if there is no reports expected from the platform;
+    // in practice Connection Monitor is aware of connections only after
+    // KFinishedSelection event, and hence reports only after that event, but
+    // that does not seem to be trusted on all Symbian versions --> safest
+    // to go down.
+    if (publicConfig.type() == QNetworkConfiguration::UserChoice || state == QNetworkSession::Connecting) {
+#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
+    qDebug() << "QNS this : " << QString::number((uint)this) << " - "
+            << "going Disconnected right away. Deprecating connection monitor ID: " << publicConfig.d.data()->connectionId;
+#endif
+
+        // The connection has gone down, and processing of status updates must be
+        // stopped. Depending on platform, there may come 'connecting/connected' states
+        // considerably later (almost a second). Connection id is an increasing
+        // number, so this does not affect next _real_ 'conneting/connected' states.
+        iDeprecatedConnectionId = publicConfig.d.data()->connectionId;
         newState(QNetworkSession::Closing);
         newState(QNetworkSession::Disconnected);
     }
-    
     if (allowSignals) {
         emit q->closed();
     }
@@ -589,8 +599,13 @@
 {
 #ifdef SNAP_FUNCTIONALITY_AVAILABLE
     if (iMobility) {
-        // Close global 'Open C' RConnection
-        setdefaultif(0);
+        // Close global 'Open C' RConnection. If openC supports, use the 'heavy'
+        // version to block all subsequent requests.
+        if (iDynamicUnSetdefaultif) {
+            iDynamicUnSetdefaultif();
+        } else {
+            setdefaultif(0);
+        }
         // Start migrating to new IAP
         iMobility->MigrateToPreferredCarrier();
     }
@@ -702,7 +717,7 @@
 {
 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
     qDebug() << "QNS this : " << QString::number((uint)this) << " - "
-            << "roaming Error() occured";
+            << "roaming Error() occured, isOpen is: " << isOpen;
 #endif
     if (isOpen) {
         isOpen = false;
@@ -856,7 +871,7 @@
         _LIT(KSetting, "IAP\\Id");
         iConnection.GetIntSetting(KSetting, iapId);
     }
- 
+
 #ifdef SNAP_FUNCTIONALITY_AVAILABLE
     if (publicConfig.type() == QNetworkConfiguration::ServiceNetwork) {
         // Try to search IAP from the used SNAP using IAP Id
@@ -877,7 +892,7 @@
         //              clone of the one of the IAPs of the used SNAP
         //              => If mappingName matches, clone has been found
         QNetworkConfiguration pt;
-        pt.d = ((QNetworkConfigurationManagerPrivate*)publicConfig.d.data()->manager)->accessPointConfigurations.value(QString::number(qHash(iapId)));
+        pt.d = ((QNetworkConfigurationManagerPrivate*)publicConfig.d.data()->manager)->accessPointConfigurations.value(QT_BEARERMGMT_CONFIGURATION_IAP_PREFIX+QString::number(qHash(iapId)));
         if (pt.d) {
             for (int i=0; i < children.count(); i++) {
                 if (children[i].d.data()->mappingName == pt.d.data()->mappingName) {
@@ -885,22 +900,59 @@
                 }
             }
         } else {
+#ifdef OCC_FUNCTIONALITY_AVAILABLE
+            // On Symbian^3 (only, not earlier or Symbian^4) if the SNAP was not reachable, it triggers
+            // user choice type of activity (EasyWLAN). As a result, a new IAP may be created, and
+            // hence if was not found yet. Therefore update configurations and see if there is something new.
+            // 1. Update knowledge from the databases.
+            ((QNetworkConfigurationManagerPrivate*)publicConfig.d.data()->manager)->updateConfigurations();
+            // 2. Check if new configuration was created during connection creation
+            QList<QString> knownConfigs = ((QNetworkConfigurationManagerPrivate*)publicConfig.d.data()->manager)->accessPointConfigurations.keys();
+#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
+            qDebug() << "QNS this : " << QString::number((uint)this) << " - "
+                    << "opened configuration was not known beforehand, looking for new.";
+#endif
+            if (knownConfigs.count() > iKnownConfigsBeforeConnectionStart.count()) {
+                // Configuration count increased => new configuration was created
+                // => Search new, created configuration
+                QString newIapId;
+                for (int i=0; i < iKnownConfigsBeforeConnectionStart.count(); i++) {
+                    if (knownConfigs[i] != iKnownConfigsBeforeConnectionStart[i]) {
+                        newIapId = knownConfigs[i];
+                        break;
+                    }
+                }
+                if (newIapId.isEmpty()) {
+                    newIapId = knownConfigs[knownConfigs.count()-1];
+                }
+                pt.d = ((QNetworkConfigurationManagerPrivate*)publicConfig.d.data()->manager)->accessPointConfigurations.value(newIapId);
+                if (pt.d) {
+#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
+                    qDebug() << "QNS this : " << QString::number((uint)this) << " - "
+                            << "new configuration was found, name, IAP id: " << pt.name() << pt.identifier();
+#endif
+                    return pt;
+                }
+            }
+#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
+            qDebug() << "QNS this : " << QString::number((uint)this) << " - "
+                    << "configuration was not found, returning invalid.";
+#endif
+#endif // OCC_FUNCTIONALITY_AVAILABLE
             // Given IAP Id was not found from known IAPs array
             return QNetworkConfiguration();
         }
-
         // Matching IAP was not found from used SNAP
         // => IAP from another SNAP is returned
         //    (Note: Returned IAP matches to given IAP Id)
         return pt;
     }
 #endif
-    
     if (publicConfig.type() == QNetworkConfiguration::UserChoice) {
         if (publicConfig.d.data()->manager) {
             QNetworkConfiguration pt;
             // Try to found User Selected IAP from known IAPs (accessPointConfigurations)
-            pt.d = ((QNetworkConfigurationManagerPrivate*)publicConfig.d.data()->manager)->accessPointConfigurations.value(QString::number(qHash(iapId)));
+            pt.d = ((QNetworkConfigurationManagerPrivate*)publicConfig.d.data()->manager)->accessPointConfigurations.value(QT_BEARERMGMT_CONFIGURATION_IAP_PREFIX+QString::number(qHash(iapId)));
             if (pt.d) {
                 return pt;
             } else {
@@ -937,6 +989,10 @@
 
 void QNetworkSessionPrivate::RunL()
 {
+#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
+    qDebug() << "QNS this : " << QString::number((uint)this) << " - "
+            << "RConnection::RunL with status code: " << iStatus.Int();
+#endif
     TInt statusCode = iStatus.Int();
 
     switch (statusCode) {
@@ -1139,6 +1195,7 @@
                         QNetworkConfiguration config = bestConfigFromSNAP(publicConfig);
                         if ((config.state() == QNetworkConfiguration::Defined) ||
                             (config.state() == QNetworkConfiguration::Discovered)) {
+                            activeConfig = QNetworkConfiguration();
                             state = newState;
 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
                             qDebug() << "QNS this : " << QString::number((uint)this) << " - " << "===> EMIT State changed E  to: " << state;
@@ -1159,6 +1216,21 @@
                     }
                 }
             }
+#ifdef OCC_FUNCTIONALITY_AVAILABLE
+            // If the retVal is not true here, it means that the status update may apply to an IAP outside of
+            // SNAP (session is based on SNAP but follows IAP outside of it), which may occur on Symbian^3 EasyWlan.
+            if (retVal == false && activeConfig.d.data() && activeConfig.d.data()->numericId == accessPointId) {
+#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
+                qDebug() << "QNS this : " << QString::number((uint)this) << " - " << "===> EMIT State changed G  to: " << state;
+#endif
+                if (newState == QNetworkSession::Disconnected) {
+                    activeConfig = QNetworkConfiguration();
+                }
+                state = newState;
+                emit q->stateChanged(state);
+                retVal = true;
+            }
+#endif
         }
     }
     
@@ -1171,8 +1243,11 @@
         // considerably later (almost a second). Connection id is an increasing
         // number, so this does not affect next _real_ 'conneting/connected' states.
         iDeprecatedConnectionId = publicConfig.d.data()->connectionId;
+#ifdef OCC_FUNCTIONALITY_AVAILABLE
+        // Just in case clear activeConfiguration.
+        activeConfig = QNetworkConfiguration();
+#endif
     }
-
     return retVal;
 }
 
@@ -1197,7 +1272,6 @@
         case KFinishedSelection:
             if (aError == KErrNone)
                 {
-                // The user successfully selected an IAP to be used
                 break;
                 }
             else