--- a/qtmobility/src/bearer/qnetworkconfigmanager_s60_p.cpp Tue May 25 13:34:51 2010 +0300
+++ b/qtmobility/src/bearer/qnetworkconfigmanager_s60_p.cpp Wed Jun 09 10:36:00 2010 +0300
@@ -44,14 +44,13 @@
#include <commdb.h>
#include <cdbcols.h>
#include <d32dbms.h>
-#include <QEventLoop>
+#include <nifvar.h>
#include <QTimer>
#include <QTime> // For randgen seeding
#include <QtCore> // For randgen seeding
-// #define QT_BEARERMGMT_CONFIGMGR_DEBUG
-#ifdef QT_BEARERMGMT_CONFIGMGR_DEBUG
+#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
#include <QDebug>
#endif
@@ -70,19 +69,20 @@
QTM_BEGIN_NAMESPACE
-static const int KValueThatWillBeAddedToSNAPId = 1000;
+#ifdef SNAP_FUNCTIONALITY_AVAILABLE
+ static const int KValueThatWillBeAddedToSNAPId = 1000;
+#endif
static const int KUserChoiceIAPId = 0;
QNetworkConfigurationManagerPrivate::QNetworkConfigurationManagerPrivate()
: QObject(0), CActive(CActive::EPriorityIdle), capFlags(0),
- iFirstUpdate(true), iInitOk(true), iIgnoringUpdates(false),
- iTimeToWait(0), iIgnoreEventLoop(0)
+ iFirstUpdate(true), iInitOk(true), iUpdatePending(false),
+ iTimeToWait(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));
@@ -165,6 +165,25 @@
delete cleanup;
}
+void QNetworkConfigurationManagerPrivate::delayedConfigurationUpdate()
+{
+ if (iUpdatePending) {
+#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
+ qDebug("QNCM delayed configuration update (ECommit or ERecover occurred).");
+#endif
+ TRAPD(error, updateConfigurationsL());
+ if (error == KErrNone) {
+ updateStatesToSnaps();
+ }
+ iUpdatePending = false;
+ // Start monitoring again.
+ if (!IsActive()) {
+ SetActive();
+ // Start waiting for new notification
+ ipCommsDB->RequestNotification(iStatus);
+ }
+ }
+}
void QNetworkConfigurationManagerPrivate::registerPlatformCapabilities()
{
@@ -229,7 +248,11 @@
if (!iFirstUpdate) {
QNetworkConfiguration item;
item.d = ptr;
- emit configurationAdded(item);
+ // Emit configuration added. Connected slots may throw execptions
+ // which propagate here --> must be converted to leaves (standard
+ // std::exception would cause any TRAP trapping this function to terminate
+ // program).
+ QT_TRYCATCH_LEAVING(emit configurationAdded(item));
}
}
}
@@ -250,10 +273,9 @@
knownSnapConfigs.removeOne(ident);
} else {
QNetworkConfigurationPrivate* cpPriv = new QNetworkConfigurationPrivate();
- CleanupStack::PushL(cpPriv);
HBufC *pName = destination.NameLC();
- cpPriv->name = QString::fromUtf16(pName->Ptr(),pName->Length());
+ QT_TRYCATCH_LEAVING(cpPriv->name = QString::fromUtf16(pName->Ptr(),pName->Length()));
CleanupStack::PopAndDestroy(pName);
pName = NULL;
@@ -272,10 +294,8 @@
if (!iFirstUpdate) {
QNetworkConfiguration item;
item.d = ptr;
- emit configurationAdded(item);
+ QT_TRYCATCH_LEAVING(emit configurationAdded(item));
}
-
- CleanupStack::Pop(cpPriv);
}
QExplicitlySharedDataPointer<QNetworkConfigurationPrivate> privSNAP = snapConfigurations.value(ident);
@@ -297,7 +317,7 @@
if (!iFirstUpdate) {
QNetworkConfiguration item;
item.d = ptr;
- emit configurationAdded(item);
+ QT_TRYCATCH_LEAVING(emit configurationAdded(item));
}
privSNAP->serviceNetworkMembers.append(ptr);
}
@@ -349,7 +369,7 @@
if (!iFirstUpdate) {
QNetworkConfiguration item;
item.d = ptr;
- emit configurationAdded(item);
+ QT_TRYCATCH_LEAVING(emit configurationAdded(item));
}
} else {
delete cpPriv;
@@ -359,7 +379,7 @@
}
CleanupStack::PopAndDestroy(pDbTView);
#endif
- updateActiveAccessPoints();
+ QT_TRYCATCH_LEAVING(updateActiveAccessPoints());
foreach (const QString &oldIface, knownConfigs) {
//remove non existing IAP
@@ -368,7 +388,7 @@
if (!iFirstUpdate) {
QNetworkConfiguration item;
item.d = priv;
- emit configurationRemoved(item);
+ QT_TRYCATCH_LEAVING(emit configurationRemoved(item));
}
// Remove non existing IAP from SNAPs
foreach (const QString &iface, snapConfigurations.keys()) {
@@ -389,7 +409,7 @@
if (!iFirstUpdate) {
QNetworkConfiguration item;
item.d = priv;
- emit configurationRemoved(item);
+ QT_TRYCATCH_LEAVING(emit configurationRemoved(item));
}
}
}
@@ -399,14 +419,12 @@
RCmConnectionMethod& connectionMethod)
{
QNetworkConfigurationPrivate* cpPriv = new QNetworkConfigurationPrivate();
- CleanupStack::PushL(cpPriv);
-
TUint32 iapId = connectionMethod.GetIntAttributeL(CMManager::ECmIapId);
QString ident = QString::number(qHash(iapId));
HBufC *pName = connectionMethod.GetStringAttributeL(CMManager::ECmName);
CleanupStack::PushL(pName);
- cpPriv->name = QString::fromUtf16(pName->Ptr(),pName->Length());
+ QT_TRYCATCH_LEAVING(cpPriv->name = QString::fromUtf16(pName->Ptr(),pName->Length()));
CleanupStack::PopAndDestroy(pName);
pName = NULL;
@@ -454,7 +472,7 @@
if (error == KErrNone && pName) {
CleanupStack::PushL(pName);
- cpPriv->mappingName = QString::fromUtf16(pName->Ptr(),pName->Length());
+ QT_TRYCATCH_LEAVING(cpPriv->mappingName = QString::fromUtf16(pName->Ptr(),pName->Length()));
CleanupStack::PopAndDestroy(pName);
pName = NULL;
}
@@ -473,8 +491,6 @@
cpPriv->purpose = QNetworkConfiguration::UnknownPurpose;
cpPriv->roamingSupported = false;
cpPriv->manager = this;
-
- CleanupStack::Pop(cpPriv);
return cpPriv;
}
#else
@@ -507,7 +523,7 @@
QString ident = QString::number(qHash(aApId));
- apNetworkConfiguration->name = QString::fromUtf16(name.Ptr(),name.Length());
+ QT_TRYCATCH_LEAVING(apNetworkConfiguration->name = QString::fromUtf16(name.Ptr(),name.Length()));
apNetworkConfiguration->isValid = true;
apNetworkConfiguration->id = ident;
apNetworkConfiguration->numericId = aApId;
@@ -607,10 +623,14 @@
iConnectionMonitor.GetConnectionCount(connectionCount, status);
User::WaitForRequest(status);
- // Go through all connections and set state of related IAPs to Active
+ // Go through all connections and set state of related IAPs to Active.
+ // Status needs to be checked carefully, because ConnMon lists also e.g.
+ // WLAN connections that are being currently tried --> we don't want to
+ // state these as active.
TUint connectionId;
TUint subConnectionCount;
TUint apId;
+ TInt connectionStatus;
if (status.Int() == KErrNone) {
for (TUint i = 1; i <= connectionCount; i++) {
iConnectionMonitor.GetConnectionInfo(i, connectionId, subConnectionCount);
@@ -619,11 +639,15 @@
QString ident = QString::number(qHash(apId));
QExplicitlySharedDataPointer<QNetworkConfigurationPrivate> priv = accessPointConfigurations.value(ident);
if (priv.data()) {
- online = true;
- inactiveConfigs.removeOne(ident);
- priv.data()->connectionId = connectionId;
- // Configuration is Active
- changeConfigurationStateTo(priv, QNetworkConfiguration::Active);
+ iConnectionMonitor.GetIntAttribute(connectionId, subConnectionCount, KConnectionStatus, connectionStatus, status);
+ User::WaitForRequest(status);
+ if (connectionStatus == KLinkLayerOpen) {
+ online = true;
+ inactiveConfigs.removeOne(ident);
+ priv.data()->connectionId = connectionId;
+ // Configuration is Active
+ changeConfigurationStateTo(priv, QNetworkConfiguration::Active);
+ }
}
}
}
@@ -674,12 +698,12 @@
}
}
- // Make sure that state of rest of the IAPs won't be Discovered or Active
+ // Make sure that state of rest of the IAPs won't be Active
foreach (const QString &iface, unavailableConfigs) {
QExplicitlySharedDataPointer<QNetworkConfigurationPrivate> priv = accessPointConfigurations.value(iface);
if (priv.data()) {
// Configuration is Defined
- changeConfigurationStateAtMaxTo(priv, QNetworkConfiguration::Defined);
+ changeConfigurationStateAtMaxTo(priv, QNetworkConfiguration::Discovered);
}
}
}
@@ -807,47 +831,26 @@
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).");
+ if (iStatus != KErrCancel) {
+#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
+ qDebug("QNCM CommsDB event (of type RDbNotifier::TEvent) received: %d", iStatus.Int());
#endif
- return;
- }
- if (iStatus != KErrCancel) {
+ // By default, start relistening notifications. Stop only if interesting event occured.
+ iWaitingCommsDatabaseNotifications = true;
RDbNotifier::TEvent event = STATIC_CAST(RDbNotifier::TEvent, iStatus.Int());
switch (event) {
- 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 */
-#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();
- }
+ // Mark that there is update pending. No need to ask more events,
+ // as we know we will be updating anyway when the timer expires.
+ if (!iUpdatePending) {
+ iUpdatePending = true;
+ iWaitingCommsDatabaseNotifications = false;
+ // Update after random time, so that many processes won't
+ // start updating simultaneously
+ updateConfigurationsAfterRandomTime();
}
- iIgnoringUpdates = false; // Wait time done, allow updating again
- iWaitingCommsDatabaseNotifications = true;
- break;
+ break;
default:
// Do nothing
break;
@@ -867,64 +870,91 @@
ipCommsDB->CancelRequestNotification();
}
-
void QNetworkConfigurationManagerPrivate::EventL(const CConnMonEventBase& aEvent)
{
switch (aEvent.EventType()) {
- case EConnMonCreateConnection:
+ case EConnMonConnectionStatusChange:
{
- CConnMonCreateConnection* realEvent;
- realEvent = (CConnMonCreateConnection*) &aEvent;
- TUint subConnectionCount = 0;
- TUint apId;
- TUint connectionId = realEvent->ConnectionId();
- TRequestStatus status;
- iConnectionMonitor.GetUintAttribute(connectionId, subConnectionCount, KIAPId, apId, status);
- User::WaitForRequest(status);
- QString ident = QString::number(qHash(apId));
- QExplicitlySharedDataPointer<QNetworkConfigurationPrivate> priv = accessPointConfigurations.value(ident);
- if (priv.data()) {
- priv.data()->connectionId = connectionId;
- // Configuration is Active
- if (changeConfigurationStateTo(priv, QNetworkConfiguration::Active)) {
- updateStatesToSnaps();
+ CConnMonConnectionStatusChange* realEvent;
+ realEvent = (CConnMonConnectionStatusChange*) &aEvent;
+ TInt connectionStatus = realEvent->ConnectionStatus();
+#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
+ qDebug() << "QNCM Connection status : " << QString::number(connectionStatus) << " , connection monitor Id : " << realEvent->ConnectionId();
+#endif
+ if (connectionStatus == KConfigDaemonStartingRegistration) {
+ TUint connectionId = realEvent->ConnectionId();
+ TUint subConnectionCount = 0;
+ TUint apId;
+ TRequestStatus status;
+ iConnectionMonitor.GetUintAttribute(connectionId, subConnectionCount, KIAPId, apId, status);
+ User::WaitForRequest(status);
+ QString ident = QString::number(qHash(apId));
+ QExplicitlySharedDataPointer<QNetworkConfigurationPrivate> priv = accessPointConfigurations.value(ident);
+ if (priv.data()) {
+ priv.data()->connectionId = connectionId;
+ QT_TRYCATCH_LEAVING(emit this->configurationStateChanged(priv.data()->numericId, connectionId, QNetworkSession::Connecting));
}
- if (!iOnline) {
- iOnline = true;
- emit this->onlineStateChanged(iOnline);
+ } else if (connectionStatus == KLinkLayerOpen) {
+ // Connection has been successfully opened
+ TUint connectionId = realEvent->ConnectionId();
+ TUint subConnectionCount = 0;
+ TUint apId;
+ TRequestStatus status;
+ iConnectionMonitor.GetUintAttribute(connectionId, subConnectionCount, KIAPId, apId, status);
+ User::WaitForRequest(status);
+ QString ident = QString::number(qHash(apId));
+ QExplicitlySharedDataPointer<QNetworkConfigurationPrivate> priv = accessPointConfigurations.value(ident);
+ if (priv.data()) {
+ priv.data()->connectionId = connectionId;
+ // Configuration is Active
+ QT_TRYCATCH_LEAVING(
+ if (changeConfigurationStateTo(priv, QNetworkConfiguration::Active)) {
+ updateStatesToSnaps();
+ }
+ emit this->configurationStateChanged(priv.data()->numericId, connectionId, QNetworkSession::Connected);
+ if (!iOnline) {
+ iOnline = true;
+ emit this->onlineStateChanged(iOnline);
+ }
+ );
+ }
+ } else if (connectionStatus == KConfigDaemonStartingDeregistration) {
+ TUint connectionId = realEvent->ConnectionId();
+ QExplicitlySharedDataPointer<QNetworkConfigurationPrivate> priv = dataByConnectionId(connectionId);
+ if (priv.data()) {
+ QT_TRYCATCH_LEAVING(emit this->configurationStateChanged(priv.data()->numericId, connectionId, QNetworkSession::Closing));
+ }
+ } else if (connectionStatus == KLinkLayerClosed ||
+ connectionStatus == KConnectionClosed) {
+ // Connection has been closed. Which of the above events is reported, depends on the Symbian
+ // platform.
+ TUint connectionId = realEvent->ConnectionId();
+ QExplicitlySharedDataPointer<QNetworkConfigurationPrivate> priv = dataByConnectionId(connectionId);
+ if (priv.data()) {
+ // Configuration is either Defined or Discovered
+ QT_TRYCATCH_LEAVING(
+ if (changeConfigurationStateAtMaxTo(priv, QNetworkConfiguration::Discovered)) {
+ updateStatesToSnaps();
+ }
+ emit this->configurationStateChanged(priv.data()->numericId, connectionId, QNetworkSession::Disconnected);
+ );
+ }
+
+ bool online = false;
+ foreach (const QString &iface, accessPointConfigurations.keys()) {
+ QExplicitlySharedDataPointer<QNetworkConfigurationPrivate> priv = accessPointConfigurations.value(iface);
+ if (priv.data()->state == QNetworkConfiguration::Active) {
+ online = true;
+ break;
+ }
+ }
+ if (iOnline != online) {
+ iOnline = online;
+ QT_TRYCATCH_LEAVING(emit this->onlineStateChanged(iOnline));
}
}
}
- break;
-
- case EConnMonDeleteConnection:
- {
- CConnMonDeleteConnection* realEvent;
- realEvent = (CConnMonDeleteConnection*) &aEvent;
- TUint connectionId = realEvent->ConnectionId();
- QExplicitlySharedDataPointer<QNetworkConfigurationPrivate> priv = dataByConnectionId(connectionId);
- if (priv.data()) {
- priv.data()->connectionId = 0;
- // Configuration is either Defined or Discovered
- if (changeConfigurationStateAtMaxTo(priv, QNetworkConfiguration::Discovered)) {
- updateStatesToSnaps();
- }
- }
-
- bool online = false;
- foreach (const QString &iface, accessPointConfigurations.keys()) {
- QExplicitlySharedDataPointer<QNetworkConfigurationPrivate> priv = accessPointConfigurations.value(iface);
- if (priv.data()->state == QNetworkConfiguration::Active) {
- online = true;
- break;
- }
- }
- if (iOnline != online) {
- iOnline = online;
- emit this->onlineStateChanged(iOnline);
- }
- }
- break;
+ break;
case EConnMonIapAvailabilityChange:
{
@@ -937,7 +967,7 @@
QExplicitlySharedDataPointer<QNetworkConfigurationPrivate> priv = accessPointConfigurations.value(ident);
if (priv.data()) {
// Configuration is either Discovered or Active
- changeConfigurationStateAtMinTo(priv, QNetworkConfiguration::Discovered);
+ QT_TRYCATCH_LEAVING(changeConfigurationStateAtMinTo(priv, QNetworkConfiguration::Discovered));
unDiscoveredConfigs.removeOne(ident);
}
}
@@ -945,36 +975,87 @@
QExplicitlySharedDataPointer<QNetworkConfigurationPrivate> priv = accessPointConfigurations.value(iface);
if (priv.data()) {
// Configuration is Defined
- changeConfigurationStateAtMaxTo(priv, QNetworkConfiguration::Defined);
+ QT_TRYCATCH_LEAVING(changeConfigurationStateAtMaxTo(priv, QNetworkConfiguration::Defined));
}
}
}
break;
+ case EConnMonCreateConnection:
+ {
+ // This event is caught to keep connection monitor IDs up-to-date.
+ CConnMonCreateConnection* realEvent;
+ realEvent = (CConnMonCreateConnection*) &aEvent;
+ TUint subConnectionCount = 0;
+ TUint apId;
+ TUint connectionId = realEvent->ConnectionId();
+ TRequestStatus status;
+ iConnectionMonitor.GetUintAttribute(connectionId, subConnectionCount, KIAPId, apId, status);
+ User::WaitForRequest(status);
+ QString ident = QString::number(qHash(apId));
+ QExplicitlySharedDataPointer<QNetworkConfigurationPrivate> priv = accessPointConfigurations.value(ident);
+ if (priv.data()) {
+#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
+ qDebug() << "QNCM updating connection monitor ID : from, to, whose: " << priv.data()->connectionId << connectionId << priv->name;
+#endif
+ priv.data()->connectionId = connectionId;
+ }
+ }
+ break;
default:
// For unrecognized events
break;
}
}
-// Waits for 1..4 seconds.
-void QNetworkConfigurationManagerPrivate::waitRandomTime()
+// Sessions may use this function to report configuration state changes,
+// because on some Symbian platforms (especially Symbian^3) all state changes are not
+// reported by the RConnectionMonitor, in particular in relation to stop() call,
+// whereas they _are_ reported on RConnection progress notifier used by sessions --> centralize
+// this data here so that other sessions may benefit from it too (not all sessions necessarily have
+// RConnection progress notifiers available but they relay on having e.g. disconnected information from
+// manager). Currently only 'Disconnected' state is of interest because it has proven to be troublesome.
+void QNetworkConfigurationManagerPrivate::configurationStateChangeReport(TUint32 accessPointId, QNetworkSession::State newState)
{
- iTimeToWait = (qAbs(qrand()) % 5) * 1000;
+#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
+ qDebug() << "QNCM A session reported state change for IAP ID: " << accessPointId << " whose new state is: " << newState;
+#endif
+ switch (newState) {
+ case QNetworkSession::Disconnected:
+ {
+ QString ident = QString::number(qHash(accessPointId));
+ QExplicitlySharedDataPointer<QNetworkConfigurationPrivate> priv = accessPointConfigurations.value(ident);
+ if (priv.data()) {
+ // Configuration is either Defined or Discovered
+ if (changeConfigurationStateAtMaxTo(priv, QNetworkConfiguration::Discovered)) {
+ updateStatesToSnaps();
+ }
+ emit this->configurationStateChanged(
+ priv.data()->numericId, priv.data()->connectionId, QNetworkSession::Disconnected);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+// Waits for 2..6 seconds.
+void QNetworkConfigurationManagerPrivate::updateConfigurationsAfterRandomTime()
+{
+ iTimeToWait = (qAbs(qrand()) % 68) * 100;
if (iTimeToWait < 1000) {
iTimeToWait = 1000;
}
-#ifdef QT_BEARERMGMT_CONFIGMGR_DEBUG
- qDebug("QNetworkConfigurationManager waiting random time: %d ms", iTimeToWait);
+#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
+ qDebug("QNCM waiting random time: %d ms", iTimeToWait);
#endif
- QTimer::singleShot(iTimeToWait, iIgnoreEventLoop, SLOT(quit()));
- iIgnoreEventLoop->exec();
+ QTimer::singleShot(iTimeToWait, this, SLOT(delayedConfigurationUpdate()));
}
QExplicitlySharedDataPointer<QNetworkConfigurationPrivate> QNetworkConfigurationManagerPrivate::dataByConnectionId(TUint aConnectionId)
{
QNetworkConfiguration item;
-
QHash<QString, QExplicitlySharedDataPointer<QNetworkConfigurationPrivate> >::const_iterator i =
accessPointConfigurations.constBegin();
while (i != accessPointConfigurations.constEnd()) {
@@ -990,7 +1071,7 @@
AccessPointsAvailabilityScanner::AccessPointsAvailabilityScanner(QNetworkConfigurationManagerPrivate& owner,
RConnectionMonitor& connectionMonitor)
- : CActive(CActive::EPriorityStandard), iOwner(owner), iConnectionMonitor(connectionMonitor)
+ : CActive(CActive::EPriorityHigh), iOwner(owner), iConnectionMonitor(connectionMonitor)
{
CActiveScheduler::Add(this);
}
@@ -1028,9 +1109,9 @@
{
if (iStatus.Int() != KErrNone) {
iIapBuf().iCount = 0;
- iOwner.accessPointScanningReady(false,iIapBuf());
+ QT_TRYCATCH_LEAVING(iOwner.accessPointScanningReady(false,iIapBuf()));
} else {
- iOwner.accessPointScanningReady(true,iIapBuf());
+ QT_TRYCATCH_LEAVING(iOwner.accessPointScanningReady(true,iIapBuf()));
}
}
#include "moc_qnetworkconfigmanager_s60_p.cpp"