qtmobility/src/bearer/qnetworkconfigmanager_s60_p.cpp
branchRCL_3
changeset 1 5822d84012fb
parent 0 cfcbf08528c4
child 5 4ea83c148e84
--- a/qtmobility/src/bearer/qnetworkconfigmanager_s60_p.cpp	Thu Apr 01 08:30:34 2010 +0300
+++ b/qtmobility/src/bearer/qnetworkconfigmanager_s60_p.cpp	Thu Apr 15 08:16:03 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)
 **
@@ -44,6 +44,16 @@
 #include <commdb.h>
 #include <cdbcols.h>
 #include <d32dbms.h>
+#include <QEventLoop>
+#include <QTimer>
+#include <QTime>  // For randgen seeding
+#include <QtCore> // For randgen seeding
+
+// #define QT_BEARERMGMT_CONFIGMGR_DEBUG
+
+#ifdef QT_BEARERMGMT_CONFIGMGR_DEBUG
+#include <QDebug>
+#endif
 
 #ifdef SNAP_FUNCTIONALITY_AVAILABLE
     #include <cmdestination.h>
@@ -64,10 +74,16 @@
 static const int KUserChoiceIAPId = 0;
 
 QNetworkConfigurationManagerPrivate::QNetworkConfigurationManagerPrivate()
-    : QObject(0), CActive(CActive::EPriorityIdle), capFlags(0), iFirstUpdate(true), iInitOk(true)
+    : QObject(0), CActive(CActive::EPriorityIdle), capFlags(0),
+    iFirstUpdate(true), iInitOk(true), iIgnoringUpdates(false),
+    iTimeToWait(0), iIgnoreEventLoop(0)
 {
     CActiveScheduler::Add(this);
 
+    // Seed the randomgenerator
+    qsrand(QTime(0,0,0).secsTo(QTime::currentTime()) + QCoreApplication::applicationPid());
+    iIgnoreEventLoop = new QEventLoop(this);
+
     registerPlatformCapabilities();
     TRAPD(error, ipCommsDB = CCommsDatabase::NewL(EDatabaseTypeIAP));
     if (error != KErrNone) {
@@ -100,12 +116,9 @@
     cpPriv->manager = this;
     QExplicitlySharedDataPointer<QNetworkConfigurationPrivate> ptr(cpPriv);
     userChoiceConfigurations.insert(cpPriv->id, ptr);
-
     updateConfigurations();
     updateStatesToSnaps();
-
     updateAvailableAccessPoints(); // On first time updates synchronously (without WLAN scans)
-    
     // Start monitoring IAP and/or SNAP changes in Symbian CommsDB
     startCommsDatabaseNotifications();
     iFirstUpdate = false;
@@ -115,22 +128,19 @@
 {
     Cancel();
 
-    QList<QString> configIdents = snapConfigurations.keys();
-    foreach(QString oldIface, configIdents) {
+    foreach (const QString &oldIface, snapConfigurations.keys()) {
         QExplicitlySharedDataPointer<QNetworkConfigurationPrivate> priv = snapConfigurations.take(oldIface);
         priv->isValid = false;
         priv->id.clear();
     }
 
-    configIdents = accessPointConfigurations.keys();
-    foreach(QString oldIface, configIdents) {
+    foreach (const QString &oldIface, accessPointConfigurations.keys()) {
         QExplicitlySharedDataPointer<QNetworkConfigurationPrivate> priv = accessPointConfigurations.take(oldIface);
         priv->isValid = false;
         priv->id.clear();
     }
 
-    configIdents = userChoiceConfigurations.keys();
-    foreach(QString oldIface, configIdents) {
+    foreach (const QString &oldIface, userChoiceConfigurations.keys()) {
         QExplicitlySharedDataPointer<QNetworkConfigurationPrivate> priv = userChoiceConfigurations.take(oldIface);
         priv->isValid = false;
         priv->id.clear();
@@ -166,6 +176,7 @@
     capFlags |= QNetworkConfigurationManager::ForcedRoaming;
 #endif
     capFlags |= QNetworkConfigurationManager::DataStatistics;
+    capFlags |= QNetworkConfigurationManager::NetworkSessionRequired;
 }
 
 void QNetworkConfigurationManagerPrivate::performAsyncConfigurationUpdate()
@@ -193,7 +204,7 @@
 {
     QList<QString> knownConfigs = accessPointConfigurations.keys();
     QList<QString> knownSnapConfigs = snapConfigurations.keys();
-    
+
 #ifdef SNAP_FUNCTIONALITY_AVAILABLE    
     // S60 version is >= Series60 3rd Edition Feature Pack 2
     TInt error = KErrNone;
@@ -350,7 +361,7 @@
 #endif
     updateActiveAccessPoints();
     
-    foreach (QString oldIface, knownConfigs) {
+    foreach (const QString &oldIface, knownConfigs) {
         //remove non existing IAP
         QExplicitlySharedDataPointer<QNetworkConfigurationPrivate> priv = accessPointConfigurations.take(oldIface);
         priv->isValid = false;
@@ -360,8 +371,7 @@
             emit configurationRemoved(item);
         }
         // Remove non existing IAP from SNAPs
-        QList<QString> snapConfigIdents = snapConfigurations.keys();
-        foreach (QString iface, snapConfigIdents) {
+        foreach (const QString &iface, snapConfigurations.keys()) {
             QExplicitlySharedDataPointer<QNetworkConfigurationPrivate> priv2 = snapConfigurations.value(iface);
             // => Check if one of the IAPs of the SNAP is active
             for (int i=0; i<priv2->serviceNetworkMembers.count(); i++) {
@@ -372,7 +382,7 @@
             }
         }    
     }
-    foreach (QString oldIface, knownSnapConfigs) {
+    foreach (const QString &oldIface, knownSnapConfigs) {
         //remove non existing SNAPs
         QExplicitlySharedDataPointer<QNetworkConfigurationPrivate> priv = snapConfigurations.take(oldIface);
         priv->isValid = false;
@@ -619,7 +629,7 @@
     }
 
     // Make sure that state of rest of the IAPs won't be Active
-    foreach (QString iface, inactiveConfigs) {
+    foreach (const QString &iface, inactiveConfigs) {
         QExplicitlySharedDataPointer<QNetworkConfigurationPrivate> priv = accessPointConfigurations.value(iface);
         if (priv.data()) {
             // Configuration is either Defined or Discovered
@@ -665,7 +675,7 @@
         }
         
         // Make sure that state of rest of the IAPs won't be Discovered or Active
-        foreach (QString iface, unavailableConfigs) {
+        foreach (const QString &iface, unavailableConfigs) {
             QExplicitlySharedDataPointer<QNetworkConfigurationPrivate> priv = accessPointConfigurations.value(iface);
             if (priv.data()) {
                 // Configuration is Defined
@@ -685,8 +695,7 @@
 void QNetworkConfigurationManagerPrivate::updateStatesToSnaps()
 {
     // Go through SNAPs and set correct state to SNAPs
-    QList<QString> snapConfigIdents = snapConfigurations.keys();
-    foreach (QString iface, snapConfigIdents) {
+    foreach (const QString &iface, snapConfigurations.keys()) {
         bool discovered = false;
         bool active = false;
         QExplicitlySharedDataPointer<QNetworkConfigurationPrivate> priv = snapConfigurations.value(iface);
@@ -798,23 +807,45 @@
 
 void QNetworkConfigurationManagerPrivate::RunL()
 {
+    if (iIgnoringUpdates) {
+#ifdef QT_BEARERMGMT_CONFIGMGR_DEBUG
+        qDebug("CommsDB event handling postponed (postpone-timer running because IAPs/SNAPs were updated very recently).");
+#endif
+        return;
+    }
     if (iStatus != KErrCancel) {
         RDbNotifier::TEvent event = STATIC_CAST(RDbNotifier::TEvent, iStatus.Int());
         switch (event) {
-//        case RDbNotifier::EUnlock:   /** All read locks have been removed.  */
+        case RDbNotifier::EUnlock:   /** All read locks have been removed.  */
         case RDbNotifier::ECommit:   /** A transaction has been committed.  */ 
         case RDbNotifier::ERollback: /** A transaction has been rolled back */
         case RDbNotifier::ERecover:  /** The database has been recovered    */
-            // Note that if further database events occur while a client is handling
-            // a request completion, the notifier records the most significant database
-            // event and this is signalled as soon as the client issues the next
-            // RequestNotification() request.
-            // => Stop recording notifications
-            stopCommsDatabaseNotifications();
-            TRAPD(error, updateConfigurationsL());
-            if (error == KErrNone) {
-                updateStatesToSnaps();
+#ifdef QT_BEARERMGMT_CONFIGMGR_DEBUG
+            qDebug("CommsDB event (of type RDbNotifier::TEvent) received: %d", iStatus.Int());
+#endif
+            iIgnoringUpdates = true;
+            // Other events than ECommit get lower priority. In practice with those events,
+            // we delay_before_updating methods, whereas
+            // with ECommit we _update_before_delaying the reaction to next event.
+            // Few important notes: 1) listening to only ECommit does not seem to be adequate,
+            // but updates will be missed. Hence other events are reacted upon too.
+            // 2) RDbNotifier records the most significant event, and that will be returned once
+            // we issue new RequestNotification, and hence updates will not be missed even
+            // when we are 'not reacting to them' for few seconds.
+            if (event == RDbNotifier::ECommit) {
+                TRAPD(error, updateConfigurationsL());
+                if (error == KErrNone) {
+                    updateStatesToSnaps();
+                }
+                waitRandomTime();
+            } else {
+                waitRandomTime();
+                TRAPD(error, updateConfigurationsL());
+                if (error == KErrNone) {
+                    updateStatesToSnaps();
+                }   
             }
+            iIgnoringUpdates = false; // Wait time done, allow updating again
             iWaitingCommsDatabaseNotifications = true;
             break;
         default:
@@ -822,7 +853,6 @@
             break;
         }
     }
-
     if (iWaitingCommsDatabaseNotifications) {
         if (!IsActive()) {
             SetActive();
@@ -882,8 +912,7 @@
         }
         
         bool online = false;
-        QList<QString> iapConfigs = accessPointConfigurations.keys();
-        foreach (QString iface, iapConfigs) {
+        foreach (const QString &iface, accessPointConfigurations.keys()) {
             QExplicitlySharedDataPointer<QNetworkConfigurationPrivate> priv = accessPointConfigurations.value(iface);
             if (priv.data()->state == QNetworkConfiguration::Active) {
                 online = true;
@@ -912,7 +941,7 @@
                 unDiscoveredConfigs.removeOne(ident);
             }
         }
-        foreach (QString iface, unDiscoveredConfigs) {
+        foreach (const QString &iface, unDiscoveredConfigs) {
             QExplicitlySharedDataPointer<QNetworkConfigurationPrivate> priv = accessPointConfigurations.value(iface);
             if (priv.data()) {
                 // Configuration is Defined
@@ -928,6 +957,20 @@
     }
 }
 
+// Waits for 1..4 seconds.
+void QNetworkConfigurationManagerPrivate::waitRandomTime()
+{
+    iTimeToWait = (qAbs(qrand()) % 5) * 1000;
+    if (iTimeToWait < 1000) {
+        iTimeToWait = 1000;
+    }
+#ifdef QT_BEARERMGMT_CONFIGMGR_DEBUG
+    qDebug("QNetworkConfigurationManager waiting random time: %d ms", iTimeToWait);
+#endif
+    QTimer::singleShot(iTimeToWait, iIgnoreEventLoop, SLOT(quit()));
+    iIgnoreEventLoop->exec();
+}
+
 QExplicitlySharedDataPointer<QNetworkConfigurationPrivate> QNetworkConfigurationManagerPrivate::dataByConnectionId(TUint aConnectionId)
 {
     QNetworkConfiguration item;