From 916076bfec520210966f67ae211af65b21a29dac Mon Sep 17 00:00:00 2001
From: Shane Kearns <shane.kearns@accenture.com>
Date: Thu, 24 Nov 2011 11:40:52 +0000
Subject: Symbian - prefer sessions started by this process to choose proxy

When WLAN and 3G connections are both active, the proxy for the wrong
connection may have been chosen in the case of plain sockets or
QNetworkAccessManager with an invalid configuration.
When enumarating active connections to choose a proxy, prefer a connection
that was opened by this process.

Task-number: QTBUG-22615
Task-number: ou1cimx1#930701
Reviewed-by: mread
---
 src/corelib/kernel/qcore_symbian_p.cpp             | 32 ++++++++++++
 src/corelib/kernel/qcore_symbian_p.h               | 22 +++++++++
 src/network/kernel/qnetworkproxy_symbian.cpp       | 27 ++++++++++
 .../bearer/symbian/qnetworksession_impl.cpp        | 57 +++++++++++++++++-----
 src/plugins/bearer/symbian/qnetworksession_impl.h  |  3 ++
 src/s60installs/bwins/QtCoreu.def                  |  5 +-
 src/s60installs/eabi/QtCoreu.def                   |  5 +-
 7 files changed, 137 insertions(+), 14 deletions(-)

diff --git a/src/corelib/kernel/qcore_symbian_p.cpp b/src/corelib/kernel/qcore_symbian_p.cpp
index 4f953a7..65ec3fe 100644
--- a/src/corelib/kernel/qcore_symbian_p.cpp
+++ b/src/corelib/kernel/qcore_symbian_p.cpp
@@ -246,6 +246,38 @@ RConnection* QSymbianSocketManager::defaultConnection() const
     return iDefaultConnection;
 }
 
+void QSymbianSocketManager::addActiveConnection(TUint32 identifier)
+{
+    QMutexLocker l(&iMutex);
+    activeConnectionsMap[identifier]++;
+#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
+    qDebug() << "addActiveConnection" << identifier << activeConnectionsMap[identifier];
+#endif
+}
+
+void QSymbianSocketManager::removeActiveConnection(TUint32 identifier)
+{
+    QMutexLocker l(&iMutex);
+    int& val(activeConnectionsMap[identifier]);
+    Q_ASSERT(val > 0);
+#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
+    qDebug() << "removeActiveConnection" << identifier << val - 1;
+#endif
+    if (val <= 1)
+        activeConnectionsMap.remove(identifier);
+    else
+        val--;
+}
+
+QList<TUint32> QSymbianSocketManager::activeConnections() const
+{
+    QMutexLocker l(&iMutex);
+#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
+    qDebug() << "activeConnections" <<  activeConnectionsMap.keys();
+#endif
+    return activeConnectionsMap.keys();
+}
+
 Q_GLOBAL_STATIC(QSymbianSocketManager, qt_symbianSocketManager);
 
 QSymbianSocketManager& QSymbianSocketManager::instance()
diff --git a/src/corelib/kernel/qcore_symbian_p.h b/src/corelib/kernel/qcore_symbian_p.h
index a8f576d..6176ab5 100644
--- a/src/corelib/kernel/qcore_symbian_p.h
+++ b/src/corelib/kernel/qcore_symbian_p.h
@@ -247,6 +247,27 @@ public:
 
     /*!
       \internal
+      Add an opened connection to the active list
+      \param an open connection
+    */
+    void addActiveConnection(TUint32 identifier);
+
+    /*!
+      \internal
+      Remove a connection from the active list
+      \param a closed connection
+    */
+    void removeActiveConnection(TUint32 identifier);
+
+    /*!
+      \internal
+      Add an opened connection to the active list
+      \param an open connection
+    */
+    QList<TUint32> activeConnections() const;
+
+    /*!
+      \internal
       Gets a reference to the singleton socket manager
     */
     static QSymbianSocketManager& instance();
@@ -258,6 +279,7 @@ private:
     int iNextSocket;
     QHash<QHashableSocket, int> socketMap;
     QHash<int, RSocket> reverseSocketMap;
+    QHash<TUint32, int> activeConnectionsMap;
     mutable QMutex iMutex;
     RSocketServ iSocketServ;
     RConnection *iDefaultConnection;
diff --git a/src/network/kernel/qnetworkproxy_symbian.cpp b/src/network/kernel/qnetworkproxy_symbian.cpp
index 73068d6..e96c372 100644
--- a/src/network/kernel/qnetworkproxy_symbian.cpp
+++ b/src/network/kernel/qnetworkproxy_symbian.cpp
@@ -60,6 +60,7 @@
 #include <QtNetwork/QNetworkConfigurationManager>
 #include <QtNetwork/QNetworkConfiguration>
 #include <QFlags>
+#include <QtCore/private/qcore_symbian_p.h>
 
 using namespace CommsDat;
 
@@ -73,6 +74,25 @@ public:
     void setIapId(TUint32 iapId) { valid = true; id = iapId; }
     bool isValid() { return valid; }
     TUint32 iapId() { return id; }
+    static SymbianIapId fromConfiguration(const QNetworkConfiguration& config)
+    {
+        SymbianIapId iapId;
+        // Note: the following code assumes that the identifier is in format
+        // I_xxxx where xxxx is the identifier of IAP. This is meant as a
+        // temporary solution until there is a support for returning
+        // implementation specific identifier.
+        const int generalPartLength = 2;
+        QString idString(config.identifier().mid(generalPartLength));
+        bool success;
+        uint id = idString.toUInt(&success);
+        if (success)
+            iapId.setIapId(id);
+        else
+            qWarning() << "Failed to convert identifier to access point identifier: "
+                << config.identifier();
+        return iapId;
+    }
+
 private:
     bool valid;
     TUint32 id;
@@ -122,9 +142,16 @@ QNetworkConfiguration SymbianProxyQuery::findCurrentConfigurationFromServiceNetw
 
 QNetworkConfiguration SymbianProxyQuery::findCurrentConfiguration(QNetworkConfigurationManager& configurationManager)
 {
+    QList<TUint32> openConfigurations = QSymbianSocketManager::instance().activeConnections();
     QList<QNetworkConfiguration> activeConfigurations = configurationManager.allConfigurations(
         QNetworkConfiguration::Active);
+    for (int i = 0; i < activeConfigurations.count(); i++) {
+        // get first configuration which was opened by this process
+        if (openConfigurations.contains(SymbianIapId::fromConfiguration(activeConfigurations.at(i)).iapId()))
+            return activeConfigurations.at(i);
+    }
     if (activeConfigurations.count() > 0) {
+        // get first active configuration opened by any process
         return activeConfigurations.at(0);
     } else {
         // No active configurations, try default one
diff --git a/src/plugins/bearer/symbian/qnetworksession_impl.cpp b/src/plugins/bearer/symbian/qnetworksession_impl.cpp
index f5f71cf..58ce8fe 100644
--- a/src/plugins/bearer/symbian/qnetworksession_impl.cpp
+++ b/src/plugins/bearer/symbian/qnetworksession_impl.cpp
@@ -64,7 +64,7 @@ QNetworkSessionPrivateImpl::QNetworkSessionPrivateImpl(SymbianEngine *engine)
     ipConnectionNotifier(0), ipConnectionStarter(0),
     iHandleStateNotificationsFromManager(false), iFirstSync(true), iStoppedByUser(false),
     iClosedByUser(false), iError(QNetworkSession::UnknownSessionError), iALREnabled(0),
-    iConnectInBackground(false), isOpening(false)
+    iConnectInBackground(false), iCurrentIap(0), isOpening(false)
 {
 
 #ifdef SNAP_FUNCTIONALITY_AVAILABLE
@@ -77,6 +77,7 @@ QNetworkSessionPrivateImpl::QNetworkSessionPrivateImpl(SymbianEngine *engine)
 void QNetworkSessionPrivateImpl::closeHandles()
 {
     QMutexLocker lock(&mutex);
+    updateCurrentIap(0);
     // Cancel Connection Progress Notifications first.
     // Note: ConnectionNotifier must be destroyed before RConnection::Close()
     //       => deleting ipConnectionNotifier results RConnection::CancelProgressNotification()
@@ -637,6 +638,8 @@ void QNetworkSessionPrivateImpl::accept()
 
         QSymbianSocketManager::instance().setDefaultConnection(&iConnection);
 
+        updateCurrentIap(iNewRoamingIap);
+
         newState(QNetworkSession::Connected, iNewRoamingIap);
     }
 #endif
@@ -867,19 +870,31 @@ quint64 QNetworkSessionPrivateImpl::activeTime() const
     return startTime.secsTo(QDateTime::currentDateTime());
 }
 
-QNetworkConfiguration QNetworkSessionPrivateImpl::activeConfiguration(TUint32 iapId) const
+bool QNetworkSessionPrivateImpl::activeIapId(TUint32& iapId) const
 {
-    if (iapId == 0) {
-        _LIT(KSetting, "IAP\\Id");
-        iConnection.GetIntSetting(KSetting, iapId);
+    if (!iConnection.SubSessionHandle())
+        return false;
+    _LIT(KSetting, "IAP\\Id");
+    TInt err = iConnection.GetIntSetting(KSetting, iapId);
+    if (err != KErrNone)
+        return false;
 #ifdef SNAP_FUNCTIONALITY_AVAILABLE
-        // Check if this is an Easy WLAN configuration. On Symbian^3 RConnection may report
-        // the used configuration as 'EasyWLAN' IAP ID if someone has just opened the configuration
-        // from WLAN Scan dialog, _and_ that connection is still up. We need to find the
-        // real matching configuration. Function alters the Easy WLAN ID to real IAP ID (only if
-        // easy WLAN):
-        easyWlanTrueIapId(iapId);
+    // Check if this is an Easy WLAN configuration. On Symbian^3 RConnection may report
+    // the used configuration as 'EasyWLAN' IAP ID if someone has just opened the configuration
+    // from WLAN Scan dialog, _and_ that connection is still up. We need to find the
+    // real matching configuration. Function alters the Easy WLAN ID to real IAP ID (only if
+    // easy WLAN):
+    easyWlanTrueIapId(iapId);
 #endif
+    return true;
+}
+
+QNetworkConfiguration QNetworkSessionPrivateImpl::activeConfiguration(TUint32 iapId) const
+{
+    if (iapId == 0) {
+        bool ok = activeIapId(iapId);
+        if (!ok)
+            return QNetworkConfiguration();
     }
 
 #ifdef SNAP_FUNCTIONALITY_AVAILABLE
@@ -1015,6 +1030,20 @@ QNetworkConfiguration QNetworkSessionPrivateImpl::activeConfiguration(TUint32 ia
     return publicConfig;
 }
 
+void QNetworkSessionPrivateImpl::updateCurrentIap(TUint32 iapId)
+{
+    if (iCurrentIap == iapId)
+        return;
+
+    if (iCurrentIap != 0)
+        QSymbianSocketManager::instance().removeActiveConnection(iCurrentIap);
+
+    iCurrentIap = iapId;
+
+    if (iCurrentIap != 0)
+        QSymbianSocketManager::instance().addActiveConnection(iCurrentIap);
+}
+
 void QNetworkSessionPrivateImpl::ConnectionStartComplete(TInt statusCode)
 {
 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
@@ -1028,7 +1057,10 @@ void QNetworkSessionPrivateImpl::ConnectionStartComplete(TInt statusCode)
         case KErrNone: // Connection created successfully
             {
             TInt error = KErrNone;
-            QNetworkConfiguration newActiveConfig = activeConfiguration();
+            TUint32 iapId;
+            QNetworkConfiguration newActiveConfig;
+            if (activeIapId(iapId))
+                newActiveConfig = activeConfiguration(iapId);
             if (!newActiveConfig.isValid()) {
                 // RConnection startup was successful but no configuration
                 // was found. That indicates that user has chosen to create a
@@ -1038,6 +1070,7 @@ void QNetworkSessionPrivateImpl::ConnectionStartComplete(TInt statusCode)
                 error = KErrGeneral;
             } else {
                 QSymbianSocketManager::instance().setDefaultConnection(&iConnection);
+                updateCurrentIap(iapId);
             }
             if (error != KErrNone) {
                 isOpen = false;
diff --git a/src/plugins/bearer/symbian/qnetworksession_impl.h b/src/plugins/bearer/symbian/qnetworksession_impl.h
index 17a051e..9e02e5b 100644
--- a/src/plugins/bearer/symbian/qnetworksession_impl.h
+++ b/src/plugins/bearer/symbian/qnetworksession_impl.h
@@ -143,6 +143,8 @@ private:
     void handleSymbianConnectionStatusChange(TInt aConnectionStatus, TInt aError, TUint accessPointId = 0);
     QNetworkConfiguration bestConfigFromSNAP(const QNetworkConfiguration& snapConfig) const;
     QNetworkConfiguration activeConfiguration(TUint32 iapId = 0) const;
+    bool activeIapId(TUint32 &iapId) const;
+    void updateCurrentIap(TUint32 iapId);
 #ifndef QT_NO_NETWORKINTERFACE
     QNetworkInterface interface(TUint iapId) const;
 #endif
@@ -186,6 +188,7 @@ private: // data
     
     TUint32 iOldRoamingIap;
     TUint32 iNewRoamingIap;
+    TUint32 iCurrentIap;
 
     bool isOpening;
 
diff --git a/src/s60installs/bwins/QtCoreu.def b/src/s60installs/bwins/QtCoreu.def
index 08c67e0..cfd2cec 100644
--- a/src/s60installs/bwins/QtCoreu.def
+++ b/src/s60installs/bwins/QtCoreu.def
@@ -4885,5 +4885,8 @@ EXPORTS
 	?updateDir@QFactoryLoader@@QAEXABVQString@@AAVQSettings@@@Z @ 4884 NONAME ; void QFactoryLoader::updateDir(class QString const &, class QSettings &)
 	?disconnectNotify@QFutureWatcherBase@@MAEXPBD@Z @ 4885 NONAME ; void QFutureWatcherBase::disconnectNotify(char const *)
 	?maybeQueueForLater@QActiveObject@@QAE_NXZ @ 4886 NONAME ; bool QActiveObject::maybeQueueForLater(void)
-	?activeObjectError@QEventDispatcherSymbian@@QAEXH@Z @ 4887 NONAME ; void QEventDispatcherSymbian::activeObjectError(int)
+	?activeConnections@QSymbianSocketManager@@QBE?AV?$QList@K@@XZ @ 4887 NONAME ; class QList<unsigned long> QSymbianSocketManager::activeConnections(void) const
+	?removeActiveConnection@QSymbianSocketManager@@QAEXK@Z @ 4888 NONAME ; void QSymbianSocketManager::removeActiveConnection(unsigned long)
+	?addActiveConnection@QSymbianSocketManager@@QAEXK@Z @ 4889 NONAME ; void QSymbianSocketManager::addActiveConnection(unsigned long)
+	?activeObjectError@QEventDispatcherSymbian@@QAEXH@Z @ 4890 NONAME ; void QEventDispatcherSymbian::activeObjectError(int)
 
diff --git a/src/s60installs/eabi/QtCoreu.def b/src/s60installs/eabi/QtCoreu.def
index d80aecb..44aa48c 100644
--- a/src/s60installs/eabi/QtCoreu.def
+++ b/src/s60installs/eabi/QtCoreu.def
@@ -4165,5 +4165,8 @@ EXPORTS
 	_ZN14QFactoryLoader9updateDirERK7QStringR9QSettings @ 4164 NONAME
 	_ZN23QCoreApplicationPrivate26rebuildInstallLibraryPathsEv @ 4165 NONAME
 	_ZN13QActiveObject18maybeQueueForLaterEv @ 4166 NONAME
-	_ZN23QEventDispatcherSymbian17activeObjectErrorEi @ 4167 NONAME
+	_ZN21QSymbianSocketManager19addActiveConnectionEm @ 4167 NONAME
+	_ZN21QSymbianSocketManager22removeActiveConnectionEm @ 4168 NONAME
+	_ZN23QEventDispatcherSymbian17activeObjectErrorEi @ 4169 NONAME
+	_ZNK21QSymbianSocketManager17activeConnectionsEv @ 4170 NONAME
 
-- 
cgit v0.12

