# HG changeset patch # User Dremov Kirill (Nokia-D-MSW/Tampere) # Date 1276068960 -10800 # Node ID 4ea83c148e8436602cdcf6cc57f98ee49651104c # Parent d965ea371a4f251452e6dff135cd4b665389853f Revision: 201021 Kit: 2010123 diff -r d965ea371a4f -r 4ea83c148e84 qtmobility/data/qtmobility.sisx Binary file qtmobility/data/qtmobility.sisx has changed diff -r d965ea371a4f -r 4ea83c148e84 qtmobility/src/bearer/qcorewlanengine_mac.mm --- a/qtmobility/src/bearer/qcorewlanengine_mac.mm Tue May 25 13:34:51 2010 +0300 +++ b/qtmobility/src/bearer/qcorewlanengine_mac.mm Wed Jun 09 10:36:00 2010 +0300 @@ -43,6 +43,7 @@ #include "qnetworkconfiguration_p.h" #include +#include #include #include #include @@ -105,6 +106,8 @@ QTM_NAMESPACE::QCoreWlanEngine::instance()->requestUpdate(); } @end + +QNSListener *listener = 0; #endif QTM_BEGIN_NAMESPACE @@ -143,11 +146,6 @@ return result; } -static QString qGetInterfaceType(const QString &interfaceString) -{ - return networkInterfaces.value(interfaceString, QLatin1String("Unknown")); -} - void networkChangeCallback(SCDynamicStoreRef/* store*/, CFArrayRef changedKeys, void *info) { for ( long i = 0; i < CFArrayGetCount(changedKeys); i++) { @@ -161,23 +159,314 @@ return; } +QScanThread::QScanThread(QObject *parent) + :QThread(parent), interfaceName(nil) +{ +} + +QScanThread::~QScanThread() +{ +} + +void QScanThread::quit() +{ + wait(); +} + +void QScanThread::run() +{ +#if defined(MAC_SDK_10_6) + getUserProfiles(); + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + QStringList found; + mutex.lock(); + CWInterface *currentInterface; + if(interfaceName.isEmpty()) { + currentInterface = [CWInterface interfaceWithName:nil]; + interfaceName = nsstringToQString([currentInterface name]); + } else { + currentInterface = [CWInterface interfaceWithName:qstringToNSString(interfaceName)]; + } + mutex.unlock(); + + if([currentInterface power]) { + NSError *err = nil; + NSDictionary *parametersDict = [NSDictionary dictionaryWithObjectsAndKeys: + [NSNumber numberWithBool:YES], kCWScanKeyMerge, + [NSNumber numberWithInteger:100], kCWScanKeyRestTime, nil]; + + NSArray* apArray = [currentInterface scanForNetworksWithParameters:parametersDict error:&err]; + CWNetwork *apNetwork; + + if (!err) { + for(uint row=0; row < [apArray count]; row++ ) { + apNetwork = [apArray objectAtIndex:row]; + + const QString networkSsid = nsstringToQString([apNetwork ssid]); + found.append(networkSsid); + + QNetworkConfiguration::StateFlags state = QNetworkConfiguration::Undefined; + + bool known = isKnownSsid(networkSsid); + if( [currentInterface.interfaceState intValue] == kCWInterfaceStateRunning) { + if( networkSsid == nsstringToQString( [currentInterface ssid])) { + state = QNetworkConfiguration::Active; + } + } + if(state == QNetworkConfiguration::Undefined) { + if(known) { + state = QNetworkConfiguration::Discovered; + } else { + state = QNetworkConfiguration::Undefined; + } + } + + QNetworkConfiguration::Purpose purpose = QNetworkConfiguration::UnknownPurpose; + if([[apNetwork securityMode] intValue] == kCWSecurityModeOpen) { + purpose = QNetworkConfiguration::PublicPurpose; + } else { + purpose = QNetworkConfiguration::PrivatePurpose; + } + + found.append(foundNetwork(networkSsid, networkSsid, state, interfaceName, purpose)); + + } //end row + }//end error + }// endwifi power + +// add known configurations that are not around. + QMapIterator > i(userProfiles); + while (i.hasNext()) { + i.next(); + + QString networkName = i.key(); + const QString id = networkName; + + if(!found.contains(id)) { + QString networkSsid = getSsidFromNetworkName(networkName); + const QString ssidId = QString::number(qHash(QLatin1String("corewlan:") + networkSsid)); + QNetworkConfiguration::StateFlags state = QNetworkConfiguration::Undefined; + QString interfaceName; + QMapIterator ij(i.value()); + while (ij.hasNext()) { + ij.next(); + interfaceName = ij.value(); + } + + if( [currentInterface.interfaceState intValue] == kCWInterfaceStateRunning) { + if( networkSsid == nsstringToQString([currentInterface ssid])) { + state = QNetworkConfiguration::Active; + } + } + if(state == QNetworkConfiguration::Undefined) { + if( userProfiles.contains(networkName) + && found.contains(ssidId)) { + state = QNetworkConfiguration::Discovered; + } + } + + if(state == QNetworkConfiguration::Undefined) { + state = QNetworkConfiguration::Defined; + } + + found.append(foundNetwork(id, networkName, state, interfaceName, QNetworkConfiguration::UnknownPurpose)); + } + } + emit networksChanged(); + [pool release]; +#endif +} + +QStringList QScanThread::foundNetwork(const QString &id, const QString &name, const QNetworkConfiguration::StateFlags state, const QString &interfaceName, const QNetworkConfiguration::Purpose purpose) +{ + QStringList found; + QMutexLocker locker(&mutex); + QNetworkConfigurationPrivate *ptr = new QNetworkConfigurationPrivate; + + ptr->name = name; + ptr->isValid = true; + ptr->id = id; + ptr->state = state; + ptr->type = QNetworkConfiguration::InternetAccessPoint; + ptr->bearer = QLatin1String("WLAN"); + ptr->purpose = purpose; + ptr->internet = true; + ptr->serviceInterface = QNetworkInterface::interfaceFromName(interfaceName); + + fetchedConfigurations.append( ptr); + configurationInterface[name] = interfaceName; + + locker.unlock(); + locker.relock(); + found.append(id); + return found; +} + +QList QScanThread::getConfigurations() +{ + QMutexLocker locker(&mutex); + + QList foundConfigurations; + + for (int i = 0; i < fetchedConfigurations.count(); ++i) { + QNetworkConfigurationPrivate *config = new QNetworkConfigurationPrivate; + config->name = fetchedConfigurations.at(i)->name; + config->isValid = fetchedConfigurations.at(i)->isValid; + config->id = fetchedConfigurations.at(i)->id; + config->state = fetchedConfigurations.at(i)->state; + + config->type = fetchedConfigurations.at(i)->type; + config->roamingSupported = fetchedConfigurations.at(i)->roamingSupported; + config->purpose = fetchedConfigurations.at(i)->purpose; + config->internet = fetchedConfigurations.at(i)->internet; + foundConfigurations.append(config); + } + + return foundConfigurations; +} + +void QScanThread::getUserProfiles() +{ +#if defined(MAC_SDK_10_6) + QMutexLocker locker(&mutex); + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + userProfiles.clear(); + + NSArray *wifiInterfaces = [CWInterface supportedInterfaces]; + for(uint row=0; row < [wifiInterfaces count]; row++ ) { + + CWInterface *wifiInterface = [CWInterface interfaceWithName: [wifiInterfaces objectAtIndex:row]]; + NSString *nsInterfaceName = [wifiInterface name]; +// add user configured system networks + SCDynamicStoreRef dynRef = SCDynamicStoreCreate(kCFAllocatorSystemDefault, (CFStringRef)@"Qt corewlan", nil, nil); + NSDictionary * airportPlist = (NSDictionary *)SCDynamicStoreCopyValue(dynRef, (CFStringRef)[NSString stringWithFormat:@"Setup:/Network/Interface/%@/AirPort", nsInterfaceName]); + CFRelease(dynRef); + + NSDictionary *prefNetDict = [airportPlist objectForKey:@"PreferredNetworks"]; + + NSArray *thisSsidarray = [prefNetDict valueForKey:@"SSID_STR"]; + NSEnumerator *ssidEnumerator = [thisSsidarray objectEnumerator]; + NSString *ssidkey; + while ((ssidkey = [ssidEnumerator nextObject])) { + QString thisSsid = nsstringToQString(ssidkey); + if(!userProfiles.contains(thisSsid)) { + QMap map; + map.insert(thisSsid, nsstringToQString(nsInterfaceName)); + userProfiles.insert(thisSsid, map); + } + } + CFRelease(airportPlist); + + // 802.1X user profiles + QString userProfilePath = QDir::homePath() + "/Library/Preferences/com.apple.eap.profiles.plist"; + NSDictionary* eapDict = [[[NSDictionary alloc] initWithContentsOfFile:qstringToNSString(userProfilePath)] autorelease]; + NSString *profileStr= @"Profiles"; + NSString *nameStr = @"UserDefinedName"; + NSString *networkSsidStr = @"Wireless Network"; + + id profileKey; + NSEnumerator *dictEnumerator = [eapDict objectEnumerator]; + while ((profileKey = [dictEnumerator nextObject])) { + + if ([profileStr isEqualToString:profileKey]) { + NSDictionary *itemDict = [eapDict objectForKey:profileKey]; + id itemKey; + NSEnumerator *dictEnumerator = [thisSsidarray objectEnumerator]; + while ((itemKey = [dictEnumerator nextObject])) { + + NSInteger dictSize = [itemKey count]; + id objects[dictSize]; + id keys[dictSize]; + + [itemKey getObjects:objects andKeys:keys]; + QString networkName; + QString ssid; + for(int i = 0; i < dictSize; i++) { + if([nameStr isEqualToString:keys[i]]) { + networkName = nsstringToQString(objects[i]); + } + if([networkSsidStr isEqualToString:keys[i]]) { + ssid = nsstringToQString(objects[i]); + } + if(!userProfiles.contains(networkName) + && !ssid.isEmpty()) { + QMap map; + map.insert(ssid, nsstringToQString(nsInterfaceName)); + userProfiles.insert(networkName, map); + } + } + } + } + } + } + + [pool release]; +#endif +} + +QString QScanThread::getSsidFromNetworkName(const QString &name) +{ + QMutexLocker locker(&mutex); + QMapIterator > i(userProfiles); + while (i.hasNext()) { + i.next(); + QMap map = i.value(); + QMapIterator ij(i.value()); + while (ij.hasNext()) { + ij.next(); + const QString networkNameHash = QString::number(qHash(QLatin1String("corewlan:") +i.key())); + if(name == i.key() || name == networkNameHash) { + return ij.key(); + } + } + } + return QString(); +} + +QString QScanThread::getNetworkNameFromSsid(const QString &ssid) +{ + QMutexLocker locker(&mutex); + QMapIterator > i(userProfiles); + while (i.hasNext()) { + i.next(); + QMap map = i.value(); + QMapIterator ij(i.value()); + while (ij.hasNext()) { + ij.next(); + if(ij.key() == ssid) { + return i.key(); + } + } + } + return QString(); +} + +bool QScanThread::isKnownSsid(const QString &ssid) +{ + QMutexLocker locker(&mutex); + + QMapIterator > i(userProfiles); + while (i.hasNext()) { + i.next(); + QMap map = i.value(); + if(map.keys().contains(ssid)) { + return true; + } + } + return false; +} + + QCoreWlanEngine::QCoreWlanEngine(QObject *parent) : QNetworkSessionEngine(parent) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; getAllScInterfaces(); - startNetworkChangeLoop(); -#ifdef MAC_SDK_10_6 - if([[CWInterface supportedInterfaces] count] > 0 ) { - QNSListener *listener; - listener = [[QNSListener alloc] init]; - hasWifi = true; - } else { - hasWifi = false; - } -#endif - getUserConfigurations(); - requestUpdate(); + scanThread = new QScanThread(this); + connect(scanThread, SIGNAL(networksChanged()), + this, SIGNAL(configurationsChanged())); + + QTimer::singleShot(0,this,SLOT(init())); [pool release]; } @@ -191,82 +480,65 @@ } } +void QCoreWlanEngine::init() +{ +#ifdef MAC_SDK_10_6 + if([[CWInterface supportedInterfaces] count] > 0 && !listener) { + listener = [[QNSListener alloc] init]; + hasWifi = true; + } else { + hasWifi = false; + } +#endif + storeSession = NULL; + scanThread->start(); + + startNetworkChangeLoop(); +} + + QList QCoreWlanEngine::getConfigurations(bool *ok) { if (ok) *ok = true; foundConfigurations.clear(); - uint identifier; - QMapIterator i(networkInterfaces); QNetworkConfigurationPrivate* cpPriv = 0; - while (i.hasNext()) { - i.next(); - if (i.value() == "WLAN") { - QList fetchedConfigurations = scanForSsids(i.key()); - for (int i = 0; i < fetchedConfigurations.count(); ++i) { - - QNetworkConfigurationPrivate *config = new QNetworkConfigurationPrivate(); - cpPriv = fetchedConfigurations.at(i); - config->name = cpPriv->name; - config->isValid = cpPriv->isValid; - config->id = cpPriv->id; + QMutexLocker locker(&mutex); + QList fetchedConfigurations = scanThread->getConfigurations(); +locker.unlock(); - config->state = cpPriv->state; - config->type = cpPriv->type; - config->roamingSupported = cpPriv->roamingSupported; - config->purpose = cpPriv->purpose; - config->internet = cpPriv->internet; - config->serviceInterface = cpPriv->serviceInterface; - config->bearer = cpPriv->bearer; - - identifier = config->name.toUInt(); - configurationInterface[identifier] = config->serviceInterface.name(); - foundConfigurations.append(config); - delete cpPriv; - } - } + for (int i = 0; i < fetchedConfigurations.count(); ++i) { - QNetworkInterface interface = QNetworkInterface::interfaceFromName(i.key()); - QNetworkConfigurationPrivate *cpPriv = new QNetworkConfigurationPrivate(); - const QString humanReadableName = interface.humanReadableName(); - cpPriv->name = humanReadableName.isEmpty() ? interface.name() : humanReadableName; - cpPriv->isValid = true; - - if (interface.index()) - identifier = interface.index(); - else - identifier = qHash(interface.hardwareAddress()); - - cpPriv->id = QString::number(identifier); - cpPriv->type = QNetworkConfiguration::InternetAccessPoint; - cpPriv->state = QNetworkConfiguration::Undefined; + QNetworkConfigurationPrivate *config = new QNetworkConfigurationPrivate(); + cpPriv = fetchedConfigurations.at(i); + config->name = cpPriv->name; + config->isValid = cpPriv->isValid; + config->id = cpPriv->id; + config->state = cpPriv->state; + config->type = cpPriv->type; + config->roamingSupported = cpPriv->roamingSupported; + config->purpose = cpPriv->purpose; + config->internet = cpPriv->internet; + config->serviceInterface = cpPriv->serviceInterface; + config->bearer = cpPriv->bearer; - if (interface.flags() & QNetworkInterface::IsRunning) { - cpPriv->state = QNetworkConfiguration::Defined; - cpPriv->internet = true; - } - if ( !interface.addressEntries().isEmpty()) { - cpPriv->state |= QNetworkConfiguration::Active; - cpPriv->internet = true; - } - configurationInterface[identifier] = interface.name(); - cpPriv->bearer = interface.name().isEmpty()? QLatin1String("Unknown") : qGetInterfaceType(interface.name()); - foundConfigurations.append(cpPriv); - } + foundConfigurations.append(config); + delete cpPriv; + } - pollTimer.start(); - return foundConfigurations; + + return foundConfigurations; } QString QCoreWlanEngine::getInterfaceFromId(const QString &id) { - return configurationInterface.value(id.toUInt()); + return scanThread->configurationInterface.value(id); } bool QCoreWlanEngine::hasIdentifier(const QString &id) { - return configurationInterface.contains(id.toUInt()); + return scanThread->configurationInterface.contains(id); } void QCoreWlanEngine::connectToId(const QString &id) @@ -285,13 +557,13 @@ QString wantedSsid = 0; bool using8021X = false; - if(getNetworkNameFromSsid(id) != id) { + if(scanThread->getNetworkNameFromSsid(id) != id) { NSArray *array = [CW8021XProfile allUser8021XProfiles]; for (NSUInteger i=0; i<[array count]; ++i) { if(id == nsstringToQString([[array objectAtIndex:i] userDefinedName]) || id == nsstringToQString([[array objectAtIndex:i] ssid]) ) { - QString thisName = getSsidFromNetworkName(id); + QString thisName = scanThread->getSsidFromNetworkName(id); if(thisName.isEmpty()) { wantedSsid = id; } else { @@ -306,12 +578,12 @@ if(!using8021X) { QString wantedNetwork; - QMapIterator > i(userProfiles); + QMapIterator > i(scanThread->userProfiles); while (i.hasNext()) { i.next(); wantedNetwork = i.key(); if(id == wantedNetwork) { - wantedSsid = getSsidFromNetworkName(wantedNetwork); + wantedSsid = scanThread->getSsidFromNetworkName(wantedNetwork); break; } } @@ -319,12 +591,12 @@ NSDictionary *parametersDict = [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithBool:YES], kCWScanKeyMerge, + [NSNumber numberWithInt:kCWScanTypeFast], kCWScanKeyScanType, [NSNumber numberWithInteger:100], kCWScanKeyRestTime, qstringToNSString(wantedSsid), kCWScanKeySSID, nil]; - - NSArray *scanArray = [NSMutableArray arrayWithArray:[wifiInterface scanForNetworksWithParameters:parametersDict error:&err]]; + NSArray *scanArray = [wifiInterface scanForNetworksWithParameters:parametersDict error:&err]; if(!err) { for(uint row=0; row < [scanArray count]; row++ ) { CWNetwork *apNetwork = [scanArray objectAtIndex:row]; @@ -353,11 +625,13 @@ SecKeychainSearchRef searchRef; OSErr result = SecKeychainSearchCreateFromAttributes(NULL, kSecGenericPasswordItemClass, &attributeList, &searchRef); - +Q_UNUSED(result); NSString *password = @""; SecKeychainItemRef searchItem; + OSStatus resultStatus; + resultStatus = SecKeychainSearchCopyNext(searchRef, &searchItem); - if (SecKeychainSearchCopyNext(searchRef, &searchItem) == noErr) { + if (resultStatus == errSecSuccess) { UInt32 realPasswordLength; SecKeychainAttribute attributesW[8]; attributesW[0].tag = kSecAccountItemAttr; @@ -380,7 +654,7 @@ CFRelease(searchItem); SecKeychainItemFreeContent(&listW, realPassword); } else { - qDebug() << "SecKeychainSearchCopyNext error"; + qDebug() << "SecKeychainSearchCopyNext error" << cfstringRefToQstring(SecCopyErrorMessageString(resultStatus, NULL)); } [params setValue: password forKey: kCWAssocKeyPassphrase]; } // end using8021X @@ -403,6 +677,7 @@ [autoreleasepool release]; } else { + qDebug() << "wifi power off"; // not wifi } #endif @@ -433,8 +708,8 @@ void QCoreWlanEngine::requestUpdate() { getAllScInterfaces(); - getUserConfigurations(); - emit configurationsChanged(); + scanThread->getUserProfiles(); + scanThread->start(); } QCoreWlanEngine *QCoreWlanEngine::instance() @@ -442,148 +717,6 @@ return coreWlanEngine(); } -QString QCoreWlanEngine::getSsidFromNetworkName(const QString &name) -{ - QMapIterator > i(userProfiles); - while (i.hasNext()) { - i.next(); - QMap map = i.value(); - QMapIterator ij(i.value()); - while (ij.hasNext()) { - ij.next(); - if(name == i.key()) { - return ij.key(); - } - } - } - return QString(); -} - -QString QCoreWlanEngine::getNetworkNameFromSsid(const QString &ssid) -{ - QMapIterator > i(userProfiles); - while (i.hasNext()) { - i.next(); - QMap map = i.value(); - QMapIterator ij(i.value()); - while (ij.hasNext()) { - ij.next(); - if(ij.key() == ssid) { - return i.key(); - } - } - } - return QString(); -} - -QList QCoreWlanEngine::scanForSsids(const QString &interfaceName) -{ - QList foundConfigs; - if(!hasWifi) { - return foundConfigs; - } -#if defined(MAC_SDK_10_6) - NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; - CWInterface *currentInterface = [CWInterface interfaceWithName:qstringToNSString(interfaceName)]; - QStringList addedConfigs; - - if([currentInterface power]) { - NSError *err = nil; - NSDictionary *parametersDict = [NSDictionary dictionaryWithObjectsAndKeys: - [NSNumber numberWithBool:YES], kCWScanKeyMerge, - [NSNumber numberWithInt:kCWScanTypeFast], kCWScanKeyScanType, // get the networks in the scan cache - [NSNumber numberWithInteger:100], kCWScanKeyRestTime, nil]; - NSArray* apArray = [currentInterface scanForNetworksWithParameters:parametersDict error:&err]; - CWNetwork *apNetwork; - if(!err) { - for(uint row=0; row < [apArray count]; row++ ) { - apNetwork = [apArray objectAtIndex:row]; - - QString networkSsid = nsstringToQString([apNetwork ssid]); - - QNetworkConfigurationPrivate* cpPriv = new QNetworkConfigurationPrivate(); - cpPriv->name = networkSsid; - cpPriv->isValid = true; - cpPriv->id = networkSsid; - cpPriv->internet = true; - cpPriv->bearer = QLatin1String("WLAN"); - cpPriv->type = QNetworkConfiguration::InternetAccessPoint; - cpPriv->serviceInterface = QNetworkInterface::interfaceFromName(interfaceName); - bool known = isKnownSsid(networkSsid); - if( [currentInterface.interfaceState intValue] == kCWInterfaceStateRunning) { - if( cpPriv->name == nsstringToQString( [currentInterface ssid])) { - cpPriv->state |= QNetworkConfiguration::Active; - } - } - - if(!cpPriv->state) { - if(known) { - cpPriv->state = QNetworkConfiguration::Discovered; - } else { - cpPriv->state = QNetworkConfiguration::Undefined; - } - } - if([[apNetwork securityMode ] intValue]== kCWSecurityModeOpen) - cpPriv->purpose = QNetworkConfiguration::PublicPurpose; - else - cpPriv->purpose = QNetworkConfiguration::PrivatePurpose; - - foundConfigs.append(cpPriv); - addedConfigs << networkSsid; - - } //end scanned row - } - } //end power - - - // add known configurations that are not around. - QMapIterator > i(userProfiles); - while (i.hasNext()) { - i.next(); - QString networkName = i.key(); - - if(!addedConfigs.contains(networkName)) { - QString interfaceName; - QMapIterator ij(i.value()); - while (ij.hasNext()) { - ij.next(); - interfaceName = ij.value(); - } - - QNetworkConfigurationPrivate* cpPriv = new QNetworkConfigurationPrivate(); - cpPriv->name = networkName; - cpPriv->isValid = true; - cpPriv->id = networkName; - cpPriv->internet = true; - cpPriv->bearer = QLatin1String("WLAN"); - cpPriv->type = QNetworkConfiguration::InternetAccessPoint; - cpPriv->serviceInterface = QNetworkInterface::interfaceFromName(interfaceName); - QString ssid = getSsidFromNetworkName(networkName); - if( [currentInterface.interfaceState intValue] == kCWInterfaceStateRunning) { - if( ssid == nsstringToQString( [currentInterface ssid])) { - cpPriv->state |= QNetworkConfiguration::Active; - } - } - - if( addedConfigs.contains(ssid)) { - cpPriv->state |= QNetworkConfiguration::Discovered; - } - - if(!cpPriv->state) { - cpPriv->state = QNetworkConfiguration::Defined; - } - - foundConfigs.append(cpPriv); - } - } - - [autoreleasepool drain]; -#else - Q_UNUSED(interfaceName); -#endif - return foundConfigs; -} - bool QCoreWlanEngine::isWifiReady(const QString &wifiDeviceName) { #if defined(MAC_SDK_10_6) @@ -598,23 +731,6 @@ return false; } -bool QCoreWlanEngine::isKnownSsid( const QString &ssid) -{ -#if defined(MAC_SDK_10_6) - QMapIterator > i(userProfiles); - while (i.hasNext()) { - i.next(); - QMap map = i.value(); - if(map.keys().contains(ssid)) { - return true; - } - } -#else - Q_UNUSED(ssid); -#endif - return false; -} - bool QCoreWlanEngine::getAllScInterfaces() { networkInterfaces.clear(); @@ -665,7 +781,7 @@ networkChangeCallback, &dynStoreContext); if (!storeSession ) { - qWarning() << "could not open dynamic store: error:" << SCErrorString(SCError()); + qDebug() << "could not open dynamic store: error:" << SCErrorString(SCError()); return; } @@ -689,7 +805,7 @@ CFRelease(storeKey); if (!SCDynamicStoreSetNotificationKeys(storeSession , notificationKeys, patternsArray)) { - qWarning() << "register notification error:"<< SCErrorString(SCError()); + qDebug() << "register notification error:"<< SCErrorString(SCError()); CFRelease(storeSession ); CFRelease(notificationKeys); CFRelease(patternsArray); @@ -700,7 +816,7 @@ runloopSource = SCDynamicStoreCreateRunLoopSource(NULL, storeSession , 0); if (!runloopSource) { - qWarning() << "runloop source error:"<< SCErrorString(SCError()); + qDebug() << "runloop source error:"<< SCErrorString(SCError()); CFRelease(storeSession ); return; } @@ -708,79 +824,6 @@ CFRunLoopAddSource(CFRunLoopGetCurrent(), runloopSource, kCFRunLoopDefaultMode); return; } - -void QCoreWlanEngine::getUserConfigurations() -{ -#ifdef MAC_SDK_10_6 - NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; - userProfiles.clear(); - - NSArray *wifiInterfaces = [CWInterface supportedInterfaces]; - for(uint row=0; row < [wifiInterfaces count]; row++ ) { - - CWInterface *wifiInterface = [CWInterface interfaceWithName: [wifiInterfaces objectAtIndex:row]]; - NSString *nsInterfaceName = [wifiInterface name]; -// add user configured system networks - SCDynamicStoreRef dynRef = SCDynamicStoreCreate(kCFAllocatorSystemDefault, (CFStringRef)@"Qt corewlan", nil, nil); - NSDictionary *airportPlist = (NSDictionary *)SCDynamicStoreCopyValue(dynRef, (CFStringRef)[[NSString stringWithFormat:@"Setup:/Network/Interface/%@/AirPort", nsInterfaceName] autorelease]); - CFRelease(dynRef); - - NSDictionary *prefNetDict = [airportPlist objectForKey:@"PreferredNetworks"]; - - NSArray *thisSsidarray = [prefNetDict valueForKey:@"SSID_STR"]; - for(NSString *ssidkey in thisSsidarray) { - QString thisSsid = nsstringToQString(ssidkey); - if(!userProfiles.contains(thisSsid)) { - QMap map; - map.insert(thisSsid, nsstringToQString(nsInterfaceName)); - userProfiles.insert(thisSsid, map); - } - } - CFRelease(airportPlist); - - // 802.1X user profiles - QString userProfilePath = QDir::homePath() + "/Library/Preferences/com.apple.eap.profiles.plist"; - NSDictionary* eapDict = [[NSDictionary alloc] initWithContentsOfFile:qstringToNSString(userProfilePath)]; - NSString *profileStr= @"Profiles"; - NSString *nameStr = @"UserDefinedName"; - NSString *networkSsidStr = @"Wireless Network"; - for (id profileKey in eapDict) { - if ([profileStr isEqualToString:profileKey]) { - NSDictionary *itemDict = [eapDict objectForKey:profileKey]; - for (id itemKey in itemDict) { - - NSInteger dictSize = [itemKey count]; - id objects[dictSize]; - id keys[dictSize]; - - [itemKey getObjects:objects andKeys:keys]; - QString networkName; - QString ssid; - for(int i = 0; i < dictSize; i++) { - if([nameStr isEqualToString:keys[i]]) { - networkName = nsstringToQString(objects[i]); - } - if([networkSsidStr isEqualToString:keys[i]]) { - ssid = nsstringToQString(objects[i]); - } - if(!userProfiles.contains(networkName) - && !ssid.isEmpty()) { - QMap map; - map.insert(ssid, nsstringToQString(nsInterfaceName)); - userProfiles.insert(networkName, map); - } - } - } - [itemDict release]; - } - } - [eapDict release]; - } - [autoreleasepool release]; -#endif - -} - #include "moc_qcorewlanengine_mac_p.cpp" QTM_END_NAMESPACE diff -r d965ea371a4f -r 4ea83c148e84 qtmobility/src/bearer/qcorewlanengine_mac_p.h --- a/qtmobility/src/bearer/qcorewlanengine_mac_p.h Tue May 25 13:34:51 2010 +0300 +++ b/qtmobility/src/bearer/qcorewlanengine_mac_p.h Wed Jun 09 10:36:00 2010 +0300 @@ -54,17 +54,23 @@ // #include "qnetworksessionengine_p.h" +#include "qnetworkconfiguration.h" + #include #include #include +#include +#include QTM_BEGIN_NAMESPACE class QNetworkConfigurationPrivate; +class QScanThread; class QCoreWlanEngine : public QNetworkSessionEngine { Q_OBJECT + friend class QScanThread; public: QCoreWlanEngine(QObject *parent = 0); @@ -82,30 +88,62 @@ void requestUpdate(); static QCoreWlanEngine *instance(); - static bool getAllScInterfaces(); + QString interfaceName; private: bool isWifiReady(const QString &dev); - QMap configurationInterface; QTimer pollTimer; - QList scanForSsids(const QString &interfaceName); - - bool isKnownSsid(const QString &ssid); QList foundConfigurations; SCDynamicStoreRef storeSession; CFRunLoopSourceRef runloopSource; bool hasWifi; + QScanThread *scanThread; + QMutex mutex; + static bool getAllScInterfaces(); + +private Q_SLOTS: + void init(); protected: - QMap > userProfiles; + void startNetworkChangeLoop(); +}; + +class QScanThread : public QThread +{ + Q_OBJECT - void startNetworkChangeLoop(); - void getUserConfigurations(); +public: + QScanThread(QObject *parent = 0); + ~QScanThread(); + + void quit(); + QList getConfigurations(); + QString interfaceName; + QMap configurationInterface; + void getUserProfiles(); QString getNetworkNameFromSsid(const QString &ssid); QString getSsidFromNetworkName(const QString &name); + bool isKnownSsid(const QString &ssid); + QMap > userProfiles; + +signals: + void networksChanged(); + +protected: + void run(); + +private: + QList fetchedConfigurations; + QMutex mutex; + QStringList foundNetwork(const QString &id, const QString &ssid, + const QNetworkConfiguration::StateFlags state, + const QString &interfaceName, + const QNetworkConfiguration::Purpose purpose); + }; + QTM_END_NAMESPACE #endif diff -r d965ea371a4f -r 4ea83c148e84 qtmobility/src/bearer/qnetworkconfigmanager_s60_p.cpp --- 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 #include #include -#include +#include #include #include // For randgen seeding #include // For randgen seeding -// #define QT_BEARERMGMT_CONFIGMGR_DEBUG -#ifdef QT_BEARERMGMT_CONFIGMGR_DEBUG +#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG #include #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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 QNetworkConfigurationManagerPrivate::dataByConnectionId(TUint aConnectionId) { QNetworkConfiguration item; - QHash >::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" diff -r d965ea371a4f -r 4ea83c148e84 qtmobility/src/bearer/qnetworkconfigmanager_s60_p.h --- a/qtmobility/src/bearer/qnetworkconfigmanager_s60_p.h Tue May 25 13:34:51 2010 +0300 +++ b/qtmobility/src/bearer/qnetworkconfigmanager_s60_p.h Wed Jun 09 10:36:00 2010 +0300 @@ -55,6 +55,7 @@ #include #include +#include #include #include @@ -62,6 +63,9 @@ #include #endif +// Uncomment and compile QtBearer to gain detailed state tracing +// #define QT_BEARERMGMT_SYMBIAN_DEBUG + class CCommsDatabase; class QEventLoop; @@ -92,8 +96,12 @@ void configurationChanged(const QNetworkConfiguration& config); void onlineStateChanged(bool isOnline); + void configurationStateChanged(TUint32 accessPointId, TUint32 connMonId, + QNetworkSession::State newState); + public Q_SLOTS: void updateConfigurations(); + void delayedConfigurationUpdate(); private: void registerPlatformCapabilities(); @@ -119,19 +127,24 @@ void accessPointScanningReady(TBool scanSuccessful, TConnMonIapInfo iapInfo); void startCommsDatabaseNotifications(); void stopCommsDatabaseNotifications(); - void waitRandomTime(); + void updateConfigurationsAfterRandomTime(); QNetworkConfiguration defaultConfigurationL(); TBool GetS60PlatformVersion(TUint& aMajor, TUint& aMinor) const; void startMonitoringIAPData(TUint32 aIapId); QExplicitlySharedDataPointer dataByConnectionId(TUint aConnectionId); -protected: // From CActive +protected: + // From CActive void RunL(); void DoCancel(); -private: // MConnectionMonitorObserver +private: + // MConnectionMonitorObserver void EventL(const CConnMonEventBase& aEvent); + // For QNetworkSessionPrivate to indicate about state changes + void configurationStateChangeReport(TUint32 accessPointId, + QNetworkSession::State newState); public: // Data //this table contains an up to date list of all configs at any time. @@ -151,9 +164,8 @@ TBool iOnline; TBool iInitOk; TBool iUpdateGoingOn; - TBool iIgnoringUpdates; + TBool iUpdatePending; TUint iTimeToWait; - QEventLoop* iIgnoreEventLoop; AccessPointsAvailabilityScanner* ipAccessPointsAvailabilityScanner; diff -r d965ea371a4f -r 4ea83c148e84 qtmobility/src/bearer/qnetworkconfiguration_s60_p.h --- a/qtmobility/src/bearer/qnetworkconfiguration_s60_p.h Tue May 25 13:34:51 2010 +0300 +++ b/qtmobility/src/bearer/qnetworkconfiguration_s60_p.h Wed Jun 09 10:36:00 2010 +0300 @@ -88,7 +88,18 @@ QNetworkConfigurationPrivate::Bearer bearer; QString bearerName() const; + // So called IAP id from the platform. Remains constant as long as the + // platform is aware of the configuration ie. it is stored in the databases + // --> does not depend on whether connections are currently open or not. + // In practice is the same for the lifetime of the QNetworkConfiguration. TUint32 numericId; + // So called connection id, or connection monitor ID. A dynamic ID assigned + // by RConnectionMonitor whenever a new connection is opened. ConnectionID and + // numericId/IAP id have 1-to-1 mapping during the lifetime of the connection at + // connection monitor. Notably however it changes whenever a new connection to + // a given IAP is created. In a sense it is constant during the time the + // configuration remains between states Discovered..Active..Discovered, do not + // however relay on this. TUint connectionId; TAny* manager; diff -r d965ea371a4f -r 4ea83c148e84 qtmobility/src/bearer/qnetworksession_s60_p.cpp --- a/qtmobility/src/bearer/qnetworksession_s60_p.cpp Tue May 25 13:34:51 2010 +0300 +++ b/qtmobility/src/bearer/qnetworksession_s60_p.cpp Wed Jun 09 10:36:00 2010 +0300 @@ -52,15 +52,17 @@ QTM_BEGIN_NAMESPACE QNetworkSessionPrivate::QNetworkSessionPrivate() - : CActive(CActive::EPriorityStandard), state(QNetworkSession::Invalid), - isOpen(false), ipConnectionNotifier(0), iError(QNetworkSession::UnknownSessionError), - iALREnabled(0), iConnectInBackground(false) + : 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) { CActiveScheduler::Add(this); #ifdef SNAP_FUNCTIONALITY_AVAILABLE iMobility = NULL; #endif + TRAP_IGNORE(iConnectionMonitor.ConnectL()); } @@ -89,9 +91,43 @@ // Close global 'Open C' RConnection setdefaultif(0); + + iConnectionMonitor.Close(); +} - iConnectionMonitor.CancelNotifications(); - iConnectionMonitor.Close(); +void QNetworkSessionPrivate::configurationStateChanged(TUint32 accessPointId, TUint32 connMonId, QNetworkSession::State newState) +{ + if (iHandleStateNotificationsFromManager) { +#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG + qDebug() << "QNS this : " << QString::number((uint)this) << " - " + << "configurationStateChanged from manager for IAP : " << QString::number(accessPointId) + << "configurationStateChanged connMon ID : " << QString::number(connMonId) + << " : to a state: " << newState + << " whereas my current state is: " << state; +#endif + if (connMonId == iDeprecatedConnectionId) { +#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG + qDebug() << "QNS this : " << QString::number((uint)this) << " - " + << "however status update from manager ignored because it related to already closed connection."; +#endif + return; + } + this->newState(newState, accessPointId); + } +} + +void QNetworkSessionPrivate::configurationRemoved(const QNetworkConfiguration& config) +{ + if (!publicConfig.d.data()) { + return; + } + if (config.d.data()->numericId == publicConfig.d.data()->numericId) { +#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG + qDebug() << "QNS this : " << QString::number((uint)this) << " - " + << "configurationRemoved IAP: " << QString::number(publicConfig.d.data()->numericId) << " : going to State: Invalid"; +#endif + this->newState(QNetworkSession::Invalid, publicConfig.d.data()->numericId); + } } void QNetworkSessionPrivate::syncStateWithInterface() @@ -100,8 +136,17 @@ return; } - // Start monitoring changes in IAP states - TRAP_IGNORE(iConnectionMonitor.NotifyEventL(*this)); + if (iFirstSync && publicConfig.d.data()) { + QObject::connect(((QNetworkConfigurationManagerPrivate*)publicConfig.d.data()->manager), SIGNAL(configurationStateChanged(TUint32, TUint32, QNetworkSession::State)), + this, SLOT(configurationStateChanged(TUint32, TUint32, QNetworkSession::State))); + // Listen to configuration removals, so that in case the configuration + // this session is based on is removed, session knows to enter Invalid -state. + QObject::connect(((QNetworkConfigurationManagerPrivate*)publicConfig.d.data()->manager), + SIGNAL(configurationRemoved(QNetworkConfiguration)), + this, SLOT(configurationRemoved(QNetworkConfiguration))); + } + // Start listening IAP state changes from QNetworkConfigurationManagerPrivate + iHandleStateNotificationsFromManager = true; // Check open connections to see if there is already // an open connection to selected IAP or SNAP @@ -137,11 +182,7 @@ } if (state != QNetworkSession::Connected) { - // There were no open connections to used IAP or SNAP - if (iError == QNetworkSession::InvalidConfigurationError) { - newState(QNetworkSession::Invalid); - } - else if ((publicConfig.d.data()->state & QNetworkConfiguration::Discovered) == + if ((publicConfig.d.data()->state & QNetworkConfiguration::Discovered) == QNetworkConfiguration::Discovered) { newState(QNetworkSession::Disconnected); } else { @@ -242,13 +283,18 @@ void QNetworkSessionPrivate::open() { +#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG + qDebug() << "QNS this : " << QString::number((uint)this) << " - " + << "open() called, session state is: " << state << " and isOpen is: " + << isOpen; +#endif if (isOpen || (state == QNetworkSession::Connecting)) { return; } - - // Cancel notifications from RConnectionMonitor + + // Stop handling IAP state change signals from QNetworkConfigurationManagerPrivate // => RConnection::ProgressNotification will be used for IAP/SNAP monitoring - iConnectionMonitor.CancelNotifications(); + iHandleStateNotificationsFromManager = false; // Configuration may have been invalidated after session creation by platform // (e.g. configuration has been deleted). @@ -256,19 +302,25 @@ newState(QNetworkSession::Invalid); iError = QNetworkSession::InvalidConfigurationError; emit q->error(iError); - syncStateWithInterface(); return; } - // If opening a (un)defined configuration, session emits error and enters - // NotAvailable -state. - if (publicConfig.state() == QNetworkConfiguration::Undefined || - publicConfig.state() == QNetworkConfiguration::Defined) { + // If opening a undefined configuration, session emits error and enters + // NotAvailable -state. Note that we will try ones in 'defined' state to avoid excessive + // need for WLAN scans (via updateConfigurations()), because user may have walked + // into a WLAN range, but periodic background scan has not occurred yet --> + // we don't want to force application to make frequent updateConfigurations() calls + // to be able to try if e.g. home WLAN is available. + if (publicConfig.state() == QNetworkConfiguration::Undefined) { newState(QNetworkSession::NotAvailable); iError = QNetworkSession::InvalidConfigurationError; emit q->error(iError); return; } - + // Clear possible previous states + iStoppedByUser = false; + iClosedByUser = false; + iDeprecatedConnectionId = 0; + TInt error = iSocketServ.Connect(); if (error != KErrNone) { // Could not open RSocketServ @@ -420,11 +472,19 @@ void QNetworkSessionPrivate::close(bool allowSignals) { +#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG + qDebug() << "QNS this : " << QString::number((uint)this) << " - " + << "close() called, session state is: " << state << " and isOpen is : " + << isOpen; +#endif if (!isOpen) { 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; - TUint activeIap = activeConfig.d.data()->numericId; isOpen = false; activeConfig = QNetworkConfiguration(); serviceConfig = QNetworkConfiguration(); @@ -437,8 +497,10 @@ } #endif - if (ipConnectionNotifier) { + if (ipConnectionNotifier && !iHandleStateNotificationsFromManager) { ipConnectionNotifier->StopNotifications(); + // Start handling IAP state change signals from QNetworkConfigurationManagerPrivate + iHandleStateNotificationsFromManager = true; } iConnection.Close(); @@ -447,29 +509,31 @@ // Close global 'Open C' RConnection setdefaultif(0); -#ifdef Q_CC_NOKIAX86 - if ((allowSignals && iapClientCount(activeIap) <= 0) || -#else - if ((allowSignals && iapClientCount(activeIap) <= 1) || -#endif - (publicConfig.type() == QNetworkConfiguration::UserChoice)) { + if (publicConfig.type() == QNetworkConfiguration::UserChoice) { newState(QNetworkSession::Closing); + newState(QNetworkSession::Disconnected); } - syncStateWithInterface(); if (allowSignals) { - if (publicConfig.type() == QNetworkConfiguration::UserChoice) { - newState(QNetworkSession::Disconnected); - } emit q->closed(); } } void QNetworkSessionPrivate::stop() { +#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG + qDebug() << "QNS this : " << QString::number((uint)this) << " - " + << "stop() called, session state is: " << state << " and isOpen is : " + << isOpen; +#endif if (!isOpen && publicConfig.isValid() && publicConfig.type() == QNetworkConfiguration::InternetAccessPoint) { +#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG + qDebug() << "QNS this : " << QString::number((uint)this) << " - " + << "since session is not open, using RConnectionMonitor to stop() the interface"; +#endif + iStoppedByUser = true; // If the publicConfig is type of IAP, enumerate through connections at // connection monitor. If publicConfig is active in that list, stop it. // Otherwise there is nothing to stop. Note: because this QNetworkSession is not open, @@ -483,7 +547,7 @@ } TUint numSubConnections; // Not used but needed by GetConnectionInfo i/f TUint connectionId; - for (TInt i = 1; i <= count; ++i) { + for (TUint i = 1; i <= count; ++i) { // Get (connection monitor's assigned) connection ID TInt ret = iConnectionMonitor.GetConnectionInfo(i, connectionId, numSubConnections); if (ret == KErrNone) { @@ -495,11 +559,25 @@ ETrue); } } + // Enter disconnected state right away since the session is not even open. + // Symbian^3 connection monitor does not emit KLinkLayerClosed when + // connection is stopped via connection monitor. + newState(QNetworkSession::Disconnected); } } else if (isOpen) { +#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG + qDebug() << "QNS this : " << QString::number((uint)this) << " - " + << "since session is open, using RConnection to stop() the interface"; +#endif // Since we are open, use RConnection to stop the interface isOpen = false; + iStoppedByUser = true; newState(QNetworkSession::Closing); + if (ipConnectionNotifier) { + ipConnectionNotifier->StopNotifications(); + // Start handling IAP state change signals from QNetworkConfigurationManagerPrivate + iHandleStateNotificationsFromManager = true; + } iConnection.Stop(RConnection::EStopAuthoritative); isOpen = true; close(false); @@ -592,7 +670,15 @@ QList configs = publicConfig.children(); for (int i=0; i < configs.count(); i++) { if (configs[i].d.data()->numericId == aNewAPInfo.AccessPoint()) { - emit q->preferredConfigurationChanged(configs[i],aIsSeamless); + // Any slot connected to the signal might throw an std::exception, + // which must not propagate into Symbian code (this function is a callback + // from platform). We could convert exception to a symbian Leave, but since the + // prototype of this function bans this (no trailing 'L'), we just catch + // and drop. + QT_TRY { + emit q->preferredConfigurationChanged(configs[i],aIsSeamless); + } + QT_CATCH (std::exception&) {} } } } else { @@ -603,7 +689,10 @@ void QNetworkSessionPrivate::NewCarrierActive(TAccessPointInfo /*aNewAPInfo*/, TBool /*aIsSeamless*/) { if (iALREnabled > 0) { - emit q->newConfigurationActivated(); + QT_TRY { + emit q->newConfigurationActivated(); + } + QT_CATCH (std::exception&) {} } else { accept(); } @@ -611,6 +700,10 @@ void QNetworkSessionPrivate::Error(TInt /*aError*/) { +#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG + qDebug() << "QNS this : " << QString::number((uint)this) << " - " + << "roaming Error() occured"; +#endif if (isOpen) { isOpen = false; activeConfig = QNetworkConfiguration(); @@ -621,13 +714,24 @@ if (ipConnectionNotifier) { ipConnectionNotifier->StopNotifications(); } - syncStateWithInterface(); - // In some cases IAP is still in Connected state when - // syncStateWithInterface(); is called - // => Following call makes sure that Session state - // changes immediately to Disconnected. - newState(QNetworkSession::Disconnected); - emit q->closed(); + QT_TRY { + syncStateWithInterface(); + // In some cases IAP is still in Connected state when + // syncStateWithInterface(); is called + // => Following call makes sure that Session state + // changes immediately to Disconnected. + newState(QNetworkSession::Disconnected); + emit q->closed(); + } + QT_CATCH (std::exception&) {} + } else if (iStoppedByUser) { + // If the user of this session has called the stop() and + // configuration is based on internet SNAP, this needs to be + // done here because platform might roam. + QT_TRY { + newState(QNetworkSession::Disconnected); + } + QT_CATCH (std::exception&) {} } } #endif @@ -854,12 +958,12 @@ if (error != KErrNone) { isOpen = false; iError = QNetworkSession::UnknownSessionError; - emit q->error(iError); + QT_TRYCATCH_LEAVING(emit q->error(iError)); Cancel(); if (ipConnectionNotifier) { ipConnectionNotifier->StopNotifications(); } - syncStateWithInterface(); + QT_TRYCATCH_LEAVING(syncStateWithInterface()); return; } @@ -880,8 +984,10 @@ startTime = QDateTime::currentDateTime(); - newState(QNetworkSession::Connected); - emit quitPendingWaitsForOpened(); + QT_TRYCATCH_LEAVING({ + newState(QNetworkSession::Connected); + emit quitPendingWaitsForOpened(); + }); } break; case KErrNotFound: // Connection failed @@ -889,12 +995,12 @@ activeConfig = QNetworkConfiguration(); serviceConfig = QNetworkConfiguration(); iError = QNetworkSession::InvalidConfigurationError; - emit q->error(iError); + QT_TRYCATCH_LEAVING(emit q->error(iError)); Cancel(); if (ipConnectionNotifier) { ipConnectionNotifier->StopNotifications(); } - syncStateWithInterface(); + QT_TRYCATCH_LEAVING(syncStateWithInterface()); break; case KErrCancel: // Connection attempt cancelled case KErrAlreadyExists: // Connection already exists @@ -902,13 +1008,18 @@ isOpen = false; activeConfig = QNetworkConfiguration(); serviceConfig = QNetworkConfiguration(); - iError = QNetworkSession::UnknownSessionError; - emit q->error(iError); + if (publicConfig.state() == QNetworkConfiguration::Undefined || + publicConfig.state() == QNetworkConfiguration::Defined) { + iError = QNetworkSession::InvalidConfigurationError; + } else { + iError = QNetworkSession::UnknownSessionError; + } + QT_TRYCATCH_LEAVING(emit q->error(iError)); Cancel(); if (ipConnectionNotifier) { ipConnectionNotifier->StopNotifications(); } - syncStateWithInterface(); + QT_TRYCATCH_LEAVING(syncStateWithInterface()); break; } } @@ -918,8 +1029,16 @@ iConnection.Close(); } +// Enters newState if feasible according to current state. +// AccessPointId may be given as parameter. If it is zero, state-change is assumed to +// concern this session's configuration. If non-zero, the configuration is looked up +// and checked if it matches the configuration this session is based on. bool QNetworkSessionPrivate::newState(QNetworkSession::State newState, TUint accessPointId) { +#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG + qDebug() << "QNS this : " << QString::number((uint)this) << " - " + << "NEW STATE, IAP ID : " << QString::number(accessPointId) << " , newState : " << QString::number(newState); +#endif // Make sure that activeConfig is always updated when SNAP is signaled to be // connected. if (isOpen && publicConfig.type() == QNetworkConfiguration::ServiceNetwork && @@ -937,9 +1056,29 @@ if (state == QNetworkSession::Roaming && newState == QNetworkSession::Connecting) { return false; } + + // Make sure that Connected state is not reported when Connection is + // already Closing. + // Note: Stopping connection results sometimes KLinkLayerOpen + // to be reported first (just before KLinkLayerClosed). + if (state == QNetworkSession::Closing && newState == QNetworkSession::Connected) { + return false; + } + + // Make sure that some lagging 'closing' state-changes do not overwrite + // if we are already disconnected or closed. + if (state == QNetworkSession::Disconnected && newState == QNetworkSession::Closing) { + return false; + } bool emitSessionClosed = false; - if (isOpen && state == QNetworkSession::Connected && newState == QNetworkSession::Disconnected) { + + // If we abruptly go down and user hasn't closed the session, we've been aborted. + // Note that session may be in 'closing' state and not in 'connected' state, because + // depending on platform the platform may report KConfigDaemonStartingDeregistration + // event before KLinkLayerClosed + if ((isOpen && state == QNetworkSession::Connected && newState == QNetworkSession::Disconnected) || + (isOpen && !iClosedByUser && newState == QNetworkSession::Disconnected)) { // Active & Connected state should change directly to Disconnected state // only when something forces connection to close (eg. when another // application or session stops connection or when network drops @@ -953,26 +1092,35 @@ if (ipConnectionNotifier) { ipConnectionNotifier->StopNotifications(); } - // Start monitoring changes in IAP states - TRAP_IGNORE(iConnectionMonitor.NotifyEventL(*this)); + // Start handling IAP state change signals from QNetworkConfigurationManagerPrivate + iHandleStateNotificationsFromManager = true; emitSessionClosed = true; // Emit SessionClosed after state change has been reported } bool retVal = false; if (accessPointId == 0) { state = newState; +#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG + qDebug() << "QNS this : " << QString::number((uint)this) << " - " << "===> EMIT State changed A to: " << state; +#endif emit q->stateChanged(state); retVal = true; } else { if (publicConfig.type() == QNetworkConfiguration::InternetAccessPoint) { if (publicConfig.d.data()->numericId == accessPointId) { state = newState; +#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG + qDebug() << "QNS this : " << QString::number((uint)this) << " - " << "===> EMIT State changed B to: " << state; +#endif emit q->stateChanged(state); retVal = true; } } else if (publicConfig.type() == QNetworkConfiguration::UserChoice && isOpen) { if (activeConfig.d.data()->numericId == accessPointId) { state = newState; +#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG + qDebug() << "QNS this : " << QString::number((uint)this) << " - " << "===> EMIT State changed C to: " << state; +#endif emit q->stateChanged(state); retVal = true; } @@ -980,26 +1128,33 @@ QList subConfigurations = publicConfig.children(); for (int i = 0; i < subConfigurations.count(); i++) { if (subConfigurations[i].d.data()->numericId == accessPointId) { - if (newState == QNetworkSession::Connected) { - // Make sure that when AccessPoint is reported to be Connected - // also state of the related configuration changes to Active. - subConfigurations[i].d.data()->state = QNetworkConfiguration::Active; - + if (newState != QNetworkSession::Disconnected) { state = newState; +#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG + qDebug() << "QNS this : " << QString::number((uint)this) << " - " << "===> EMIT State changed D to: " << state; +#endif emit q->stateChanged(state); retVal = true; } else { - if (newState == QNetworkSession::Disconnected) { - // Make sure that when AccessPoint is reported to be disconnected - // also state of the related configuration changes from Active to Defined. - subConfigurations[i].d.data()->state = QNetworkConfiguration::Defined; - } QNetworkConfiguration config = bestConfigFromSNAP(publicConfig); if ((config.state() == QNetworkConfiguration::Defined) || (config.state() == QNetworkConfiguration::Discovered)) { state = newState; +#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG + qDebug() << "QNS this : " << QString::number((uint)this) << " - " << "===> EMIT State changed E to: " << state; +#endif emit q->stateChanged(state); retVal = true; + } else if (config.state() == QNetworkConfiguration::Active) { + // Connection to used IAP was closed, but there is another + // IAP that's active in used SNAP + // => Change state back to Connected + state = QNetworkSession::Connected; + emit q->stateChanged(state); + retVal = true; +#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG + qDebug() << "QNS this : " << QString::number((uint)this) << " - " << "===> EMIT State changed F to: " << state; +#endif } } } @@ -1010,6 +1165,13 @@ if (emitSessionClosed) { emit q->closed(); } + if (state == QNetworkSession::Disconnected) { + // 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; + } return retVal; } @@ -1018,6 +1180,9 @@ TInt aError, TUint accessPointId) { +#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG + qDebug() << "QNS this : " << QString::number((uint)this) << " - " << QString::number(accessPointId) << " , status : " << QString::number(aConnectionStatus); +#endif switch (aConnectionStatus) { // Connection unitialised @@ -1056,6 +1221,7 @@ case KCsdGotLoginInfo: break; + case KConfigDaemonStartingRegistration: // Creating connection (e.g. GPRS activation) case KCsdStartingConnect: case KCsdFinishedConnect: @@ -1082,6 +1248,7 @@ case KDataTransferTemporarilyBlocked: break; + case KConfigDaemonStartingDeregistration: // Hangup or GRPS deactivation case KConnectionStartingClose: newState(QNetworkSession::Closing,accessPointId); @@ -1089,110 +1256,27 @@ // Connection closed case KConnectionClosed: - break; - case KLinkLayerClosed: newState(QNetworkSession::Disconnected,accessPointId); + // Report manager about this to make sure this event + // is received by all interseted parties (mediated by + // manager because it does always receive all events from + // connection monitor). +#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG + qDebug() << "QNS this : " << QString::number((uint)this) << " - " << "reporting disconnection to manager."; +#endif + if (publicConfig.d.data()) { + ((QNetworkConfigurationManagerPrivate*)publicConfig.d.data()->manager)->configurationStateChangeReport(publicConfig.d.data()->numericId, QNetworkSession::Disconnected); + } break; - // Unhandled state default: break; } } -void QNetworkSessionPrivate::EventL(const CConnMonEventBase& aEvent) -{ - switch (aEvent.EventType()) - { - case EConnMonConnectionStatusChange: - { - CConnMonConnectionStatusChange* realEvent; - realEvent = (CConnMonConnectionStatusChange*) &aEvent; - - TUint connectionId = realEvent->ConnectionId(); - TInt connectionStatus = realEvent->ConnectionStatus(); - - // Try to Find IAP Id using connection Id - TUint apId = 0; - if (publicConfig.type() == QNetworkConfiguration::ServiceNetwork) { - QList subConfigurations = publicConfig.children(); - for (int i = 0; i < subConfigurations.count(); i++ ) { - if (subConfigurations[i].d.data()->connectionId == connectionId) { - apId = subConfigurations[i].d.data()->numericId; - break; - } - } - } else if (publicConfig.type() == QNetworkConfiguration::InternetAccessPoint) { - if (publicConfig.d.data()->connectionId == connectionId) { - apId = publicConfig.d.data()->numericId; - } - } - - if (apId > 0) { - handleSymbianConnectionStatusChange(connectionStatus, KErrNone, apId); - } - } - break; - - case EConnMonCreateConnection: - { - CConnMonCreateConnection* realEvent; - realEvent = (CConnMonCreateConnection*) &aEvent; - TUint apId; - TUint connectionId = realEvent->ConnectionId(); - TRequestStatus status; - iConnectionMonitor.GetUintAttribute(connectionId, 0, KIAPId, apId, status); - User::WaitForRequest(status); - if (status.Int() == KErrNone) { - // Store connection id to related AccessPoint Configuration - if (publicConfig.type() == QNetworkConfiguration::ServiceNetwork) { - QList subConfigurations = publicConfig.children(); - for (int i = 0; i < subConfigurations.count(); i++ ) { - if (subConfigurations[i].d.data()->numericId == apId) { - subConfigurations[i].d.data()->connectionId = connectionId; - break; - } - } - } else if (publicConfig.type() == QNetworkConfiguration::InternetAccessPoint) { - if (publicConfig.d.data()->numericId == apId) { - publicConfig.d.data()->connectionId = connectionId; - } - } - } - } - break; - - case EConnMonDeleteConnection: - { - CConnMonDeleteConnection* realEvent; - realEvent = (CConnMonDeleteConnection*) &aEvent; - TUint connectionId = realEvent->ConnectionId(); - // Remove connection id from related AccessPoint Configuration - if (publicConfig.type() == QNetworkConfiguration::ServiceNetwork) { - QList subConfigurations = publicConfig.children(); - for (int i = 0; i < subConfigurations.count(); i++ ) { - if (subConfigurations[i].d.data()->connectionId == connectionId) { - subConfigurations[i].d.data()->connectionId = 0; - break; - } - } - } else if (publicConfig.type() == QNetworkConfiguration::InternetAccessPoint) { - if (publicConfig.d.data()->connectionId == connectionId) { - publicConfig.d.data()->connectionId = 0; - } - } - } - break; - - default: - // For unrecognized events - break; - } -} - ConnectionProgressNotifier::ConnectionProgressNotifier(QNetworkSessionPrivate& owner, RConnection& connection) - : CActive(CActive::EPriorityStandard), iOwner(owner), iConnection(connection) + : CActive(CActive::EPriorityUserInput), iOwner(owner), iConnection(connection) { CActiveScheduler::Add(this); } @@ -1223,7 +1307,7 @@ void ConnectionProgressNotifier::RunL() { if (iStatus == KErrNone) { - iOwner.handleSymbianConnectionStatusChange(iProgress().iStage, iProgress().iError); + QT_TRYCATCH_LEAVING(iOwner.handleSymbianConnectionStatusChange(iProgress().iStage, iProgress().iError)); SetActive(); iConnection.ProgressNotification(iProgress, iStatus); diff -r d965ea371a4f -r 4ea83c148e84 qtmobility/src/bearer/qnetworksession_s60_p.h --- a/qtmobility/src/bearer/qnetworksession_s60_p.h Tue May 25 13:34:51 2010 +0300 +++ b/qtmobility/src/bearer/qnetworksession_s60_p.h Wed Jun 09 10:36:00 2010 +0300 @@ -72,11 +72,10 @@ class ConnectionProgressNotifier; -class QNetworkSessionPrivate : public QObject, public CActive, +class QNetworkSessionPrivate : public QObject, public CActive #ifdef SNAP_FUNCTIONALITY_AVAILABLE - public MMobilityProtocolResp, + , public MMobilityProtocolResp #endif - public MConnectionMonitorObserver { Q_OBJECT public: @@ -129,8 +128,9 @@ void RunL(); void DoCancel(); -private: // MConnectionMonitorObserver - void EventL(const CConnMonEventBase& aEvent); +private Q_SLOTS: + void configurationStateChanged(TUint32 accessPointId, TUint32 connMonId, QNetworkSession::State newState); + void configurationRemoved(const QNetworkConfiguration& config); private: TUint iapClientCount(TUint aIAPId) const; @@ -166,6 +166,13 @@ mutable RConnection iConnection; mutable RConnectionMonitor iConnectionMonitor; ConnectionProgressNotifier* ipConnectionNotifier; + + bool iHandleStateNotificationsFromManager; + bool iFirstSync; + bool iStoppedByUser; + bool iClosedByUser; + TUint32 iDeprecatedConnectionId; + #ifdef SNAP_FUNCTIONALITY_AVAILABLE CActiveCommsMobilityApiExt* iMobility; #endif diff -r d965ea371a4f -r 4ea83c148e84 qtmobility/tests/auto/qnetworkconfiguration/tst_qnetworkconfiguration.cpp --- a/qtmobility/tests/auto/qnetworkconfiguration/tst_qnetworkconfiguration.cpp Tue May 25 13:34:51 2010 +0300 +++ b/qtmobility/tests/auto/qnetworkconfiguration/tst_qnetworkconfiguration.cpp Wed Jun 09 10:36:00 2010 +0300 @@ -44,6 +44,13 @@ #include "../../../src/bearer/qnetworkconfiguration.h" #include "../../../src/bearer/qnetworkconfigmanager.h" +/* + Although this unit test doesn't use QNetworkAccessManager + this include is used to ensure that bearer continues to compile against + Qt 4.7+ which has a QNetworkConfiguration enabled QNetworkAccessManager +*/ +#include + #if defined(Q_WS_MAEMO_6) || defined(Q_WS_MAEMO_5) #include #include diff -r d965ea371a4f -r 4ea83c148e84 qtmobility/tests/auto/qnetworksession/lackey/main.cpp --- a/qtmobility/tests/auto/qnetworksession/lackey/main.cpp Tue May 25 13:34:51 2010 +0300 +++ b/qtmobility/tests/auto/qnetworksession/lackey/main.cpp Wed Jun 09 10:36:00 2010 +0300 @@ -46,6 +46,8 @@ #include "../../../../src/bearer/qnetworkconfiguration.h" #include "../../../../src/bearer/qnetworksession.h" +#include +#include #include QTM_USE_NAMESPACE @@ -59,7 +61,14 @@ { QCoreApplication app(argc, argv); + // Update configurations so that everything is up to date for this process too. + // Event loop is used to wait for awhile. QNetworkConfigurationManager manager; + manager.updateConfigurations(); + QEventLoop iIgnoreEventLoop; + QTimer::singleShot(3000, &iIgnoreEventLoop, SLOT(quit())); + iIgnoreEventLoop.exec(); + QList discovered = manager.allConfigurations(QNetworkConfiguration::Discovered); @@ -75,7 +84,6 @@ // Cannot read/write to processes on WinCE or Symbian. // Easiest alternative is to use sockets for IPC. - QLocalSocket oopSocket; oopSocket.connectToServer("tst_qnetworksession"); diff -r d965ea371a4f -r 4ea83c148e84 qtmobility/tests/auto/qnetworksession/tst_qnetworksession/tst_qnetworksession.cpp --- a/qtmobility/tests/auto/qnetworksession/tst_qnetworksession/tst_qnetworksession.cpp Tue May 25 13:34:51 2010 +0300 +++ b/qtmobility/tests/auto/qnetworksession/tst_qnetworksession/tst_qnetworksession.cpp Wed Jun 09 10:36:00 2010 +0300 @@ -1,5 +1,5 @@ /**************************************************************************** -** +** ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) @@ -96,6 +96,7 @@ private: QNetworkConfigurationManager manager; + QMap testsToRun; uint inProcessSessionManagementCount; @@ -113,6 +114,7 @@ bool openSession(QNetworkSession *session); bool closeSession(QNetworkSession *session, bool lastSessionOnConfiguration = true); void updateConfigurations(); +void printConfigurations(); QNetworkConfiguration suitableConfiguration(QString bearerType, QNetworkConfiguration::Type configType); void tst_QNetworkSession::initTestCase() @@ -121,7 +123,19 @@ qRegisterMetaType("QNetworkSession::SessionError"); qRegisterMetaType("QNetworkConfiguration"); qRegisterMetaType("QNetworkConfiguration::Type"); - + + // If you wish to skip tests, set value as false. This is often very convinient because tests are so lengthy. + // Better way still would be to make this readable from a file. + testsToRun["robustnessBombing"] = true; + testsToRun["outOfProcessSession"] = true; + testsToRun["invalidSession"] = true; + testsToRun["repeatedOpenClose"] = true; + testsToRun["roamingErrorCodes"] = true; + testsToRun["sessionStop"] = true; + testsToRun["sessionProperties"] = true; + testsToRun["userChoiceSession"] = true; + testsToRun["sessionOpenCloseStop"] = true; + #if defined(Q_WS_MAEMO_6) || defined(Q_WS_MAEMO_5) iapconf = new Maemo::IAPConf("007"); iapconf->setValue("ipv4_type", "AUTO"); @@ -234,6 +248,10 @@ // Robustness test for calling interfaces in nonsense order / with nonsense parameters void tst_QNetworkSession::robustnessBombing() { + if (!testsToRun["robustnessBombing"]) { + QSKIP("Temporary skip due to value set false (or it is missing) in testsToRun map", SkipAll); + } + QNetworkConfigurationManager mgr; QNetworkSession testSession(mgr.defaultConfiguration()); // Should not reset even session is not opened @@ -241,15 +259,14 @@ testSession.accept(); testSession.ignore(); testSession.reject(); - quint64 temp; - temp = testSession.bytesWritten(); - temp = testSession.bytesReceived(); - temp = testSession.activeTime(); } void tst_QNetworkSession::invalidSession() -{ +{ + if (!testsToRun["invalidSession"]) { + QSKIP("Temporary skip due to value set false (or it is missing) in testsToRun map", SkipAll); + } // 1. Verify that session created with invalid configuration remains in invalid state QNetworkSession session(QNetworkConfiguration(), 0); QVERIFY(!session.isOpen()); @@ -264,11 +281,24 @@ qvariant_cast (errorSpy.first().at(0)); QVERIFY(error == QNetworkSession::InvalidConfigurationError); QVERIFY(session.state() == QNetworkSession::Invalid); + +#ifdef QNETWORKSESSION_MANUAL_TESTS -#ifdef QNETWORKSESSION_MANUAL_TESTS + QNetworkConfiguration invalidatedConfig = suitableConfiguration("WLAN",QNetworkConfiguration::InternetAccessPoint); + if (invalidatedConfig.isValid()) { + // 3. Verify that invalidating a session after its successfully configured works + QNetworkSession invalidatedSession(invalidatedConfig); + qDebug() << "Delete the WLAN IAP from phone now (waiting 60 seconds): " << invalidatedConfig.name(); + QTest::qWait(60000); + QVERIFY(!invalidatedConfig.isValid()); + QVERIFY(invalidatedSession.state() == QNetworkSession::Invalid); + qDebug() << "Add the WLAN IAP back (waiting 60 seconds): " << invalidatedConfig.name(); + QTest::qWait(60000); + } + QNetworkConfiguration definedConfig = suitableConfiguration("WLAN",QNetworkConfiguration::InternetAccessPoint); if (definedConfig.isValid()) { - // 3. Verify that opening a session with defined configuration emits error and enters notavailable-state + // 4. Verify that opening a session with defined configuration emits error and enters notavailable-state // TODO these timer waits should be changed to waiting appropriate signals, now these wait excessively qDebug() << "Shutdown WLAN IAP (waiting 60 seconds): " << definedConfig.name(); QTest::qWait(60000); @@ -277,43 +307,27 @@ QNetworkSession definedSession(definedConfig); QSignalSpy errorSpy(&definedSession, SIGNAL(error(QNetworkSession::SessionError))); QNetworkSession::SessionError sessionError; + updateConfigurations(); definedSession.open(); +#ifdef Q_OS_SYMBIAN + // On symbian, the connection opening is tried even with defined state. + qDebug("Waiting for 10 seconds to all signals to propagate."); + QTest::qWait(10000); +#endif + updateConfigurations(); QVERIFY(definedConfig.isValid()); // Session remains valid QVERIFY(definedSession.state() == QNetworkSession::NotAvailable); // State is not available because WLAN is not in coverage QVERIFY(!errorSpy.isEmpty()); // Session tells with error about invalidated configuration sessionError = qvariant_cast (errorSpy.first().at(0)); - qDebug() << "Error code is: " << sessionError; QVERIFY(sessionError == QNetworkSession::InvalidConfigurationError); - qDebug() << "Turn the WLAN IAP back on (waiting 60 seconds): " << definedConfig.name(); QTest::qWait(60000); - updateConfigurations(); - + updateConfigurations(); QVERIFY(definedConfig.state() == QNetworkConfiguration::Discovered); } - - QNetworkConfiguration invalidatedConfig = suitableConfiguration("WLAN",QNetworkConfiguration::InternetAccessPoint); - if (invalidatedConfig.isValid()) { - // 4. Verify that invalidating a session after its successfully configured works - QNetworkSession invalidatedSession(invalidatedConfig); - QSignalSpy errorSpy(&invalidatedSession, SIGNAL(error(QNetworkSession::SessionError))); - QNetworkSession::SessionError sessionError; - - qDebug() << "Delete the WLAN IAP from phone now (waiting 60 seconds): " << invalidatedConfig.name(); - QTest::qWait(60000); - - invalidatedSession.open(); - QVERIFY(!invalidatedConfig.isValid()); - QVERIFY(invalidatedSession.state() == QNetworkSession::Invalid); - QVERIFY(!errorSpy.isEmpty()); - - sessionError = qvariant_cast (errorSpy.first().at(0)); - QVERIFY(sessionError == QNetworkSession::InvalidConfigurationError); - qDebug() << "Add the WLAN IAP back (waiting 60 seconds): " << invalidatedConfig.name(); - QTest::qWait(60000); - } + #endif } @@ -331,12 +345,12 @@ void tst_QNetworkSession::sessionProperties() { + if (!testsToRun["sessionProperties"]) { + QSKIP("Temporary skip due to value set false (or it is missing) in testsToRun map", SkipAll); + } QFETCH(QNetworkConfiguration, configuration); - QNetworkSession session(configuration); - QVERIFY(session.configuration() == configuration); - QStringList validBearerNames = QStringList() << QLatin1String("Unknown") << QLatin1String("Ethernet") << QLatin1String("WLAN") @@ -407,7 +421,12 @@ } // Tests repeated-open close. -void tst_QNetworkSession::repeatedOpenClose() { +void tst_QNetworkSession::repeatedOpenClose() +{ + if (!testsToRun["repeatedOpenClose"]) { + QSKIP("Temporary skip due to value set false (or it is missing) in testsToRun map", SkipAll); + } + QFETCH(QString, bearerType); QFETCH(QNetworkConfiguration::Type, configurationType); QFETCH(int, repeatTimes); @@ -423,13 +442,20 @@ !closeSession(&permanentSession)) { QSKIP("Unable to open/close session, skipping this round of repeated open-close test.", SkipSingle); } - for (int i = repeatTimes; i > 0; i--) { + for (int i = 0; i < repeatTimes; i++) { + qDebug() << "Opening, loop number " << i; QVERIFY(openSession(&permanentSession)); + qDebug() << "Closing, loop number, then waiting 5 seconds: " << i; QVERIFY(closeSession(&permanentSession)); + QTest::qWait(5000); } } -void tst_QNetworkSession::roamingErrorCodes() { +void tst_QNetworkSession::roamingErrorCodes() +{ + if (!testsToRun["roamingErrorCodes"]) { + QSKIP("Temporary skip due to value set false (or it is missing) in testsToRun map", SkipAll); + } #ifndef Q_OS_SYMBIAN QSKIP("Roaming supported on Symbian.", SkipAll); #else @@ -453,41 +479,11 @@ adminIapSession.stop(); // requires NetworkControl capabilities QTRY_VERIFY(!errorSpy.isEmpty()); // wait for error signals QNetworkSession::SessionError error = qvariant_cast(errorSpy.first().at(0)); + QTest::qWait(2000); // Wait for a moment to all platform signals to propagate QVERIFY(error == QNetworkSession::SessionAbortedError); QVERIFY(iapSession.state() == QNetworkSession::Disconnected); QVERIFY(adminIapSession.state() == QNetworkSession::Disconnected); #endif // Q_OS_SYMBIAN - -#ifdef QNETWORKSESSION_MANUAL_TESTS - // Check for roaming error. - // Case requires that you have controllable WLAN in Internet SNAP (only). - QNetworkConfiguration snapConfig = suitableConfiguration("bearer_not_relevant_with_snaps", QNetworkConfiguration::ServiceNetwork); - if (!snapConfig.isValid()) { - QSKIP("No SNAP accessible, skipping test.", SkipAll); - } - QNetworkSession snapSession(snapConfig); - QVERIFY(openSession(&snapSession)); - QSignalSpy errorSpySnap(&snapSession, SIGNAL(error(QNetworkSession::SessionError))); - qDebug("Disconnect the WLAN now"); - QTRY_VERIFY(!errorSpySnap.isEmpty()); // wait for error signals - QVERIFY(errorSpySnap.count() == 1); - error = qvariant_cast(errorSpySnap.first().at(0)); - qDebug() << "Error received when turning off wlan on SNAP: " << error; - QVERIFY(error == QNetworkSession::RoamingError); - - qDebug("Connect the WLAN now"); - QTest::qWait(60000); // Wait for WLAN to get up - QNetworkConfiguration wlanIapConfig2 = suitableConfiguration("WLAN", QNetworkConfiguration::InternetAccessPoint); - QNetworkSession iapSession2(wlanIapConfig2); - QVERIFY(openSession(&iapSession2)); - QSignalSpy errorSpy2(&iapSession2, SIGNAL(error(QNetworkSession::SessionError))); - qDebug("Disconnect the WLAN now"); - QTRY_VERIFY(!errorSpy2.isEmpty()); // wait for error signals - QVERIFY(errorSpy2.count() == 1); - error = qvariant_cast(errorSpy2.first().at(0)); - QVERIFY(error == QNetworkSession::SessionAbortedError); - QVERIFY(iapSession2.state() == QNetworkSession::Disconnected); -#endif } @@ -502,6 +498,9 @@ void tst_QNetworkSession::sessionStop() { + if (!testsToRun["sessionStop"]) { + QSKIP("Temporary skip due to value set false (or it is missing) in testsToRun map", SkipAll); + } #ifndef Q_OS_SYMBIAN QSKIP("Testcase contains mainly Symbian specific checks, because it is only platform to really support interface (IAP-level) Stop.", SkipAll); #endif @@ -509,6 +508,9 @@ QFETCH(QNetworkConfiguration::Type, configurationType); int configWaitdelayInMs = 2000; + + updateConfigurations(); + printConfigurations(); QNetworkConfiguration config = suitableConfiguration(bearerType, configurationType); if (!config.isValid()) { @@ -526,6 +528,9 @@ QSignalSpy closedSessionStateChangedSpy(&closedSession, SIGNAL(stateChanged(QNetworkSession::State))); QSignalSpy closedErrorSpy(&closedSession, SIGNAL(error(QNetworkSession::SessionError))); + QSignalSpy openedSessionClosedSpy(&openedSession, SIGNAL(closed())); + QSignalSpy openedSessionStateChangedSpy(&openedSession, SIGNAL(stateChanged(QNetworkSession::State))); + QSignalSpy innocentSessionClosedSpy(&innocentSession, SIGNAL(closed())); QSignalSpy innocentSessionStateChangedSpy(&innocentSession, SIGNAL(stateChanged(QNetworkSession::State))); QSignalSpy innocentErrorSpy(&innocentSession, SIGNAL(error(QNetworkSession::SessionError))); @@ -541,10 +546,18 @@ closedSessionClosedSpy.clear(); closedSessionStateChangedSpy.clear(); closedErrorSpy.clear(); + openedSessionStateChangedSpy.clear(); + openedSessionClosedSpy.clear(); + openedSession.stop(); + qDebug("Waiting for %d ms to get all configurationChange signals from platform.", configWaitdelayInMs); + QTest::qWait(configWaitdelayInMs); // Wait to get all relevant configurationChange() signals + + // First to closing, then to disconnected + QVERIFY(openedSessionStateChangedSpy.count() == 2); + QVERIFY(!openedSessionClosedSpy.isEmpty()); QVERIFY(openedSession.state() == QNetworkSession::Disconnected); - QTest::qWait(configWaitdelayInMs); // Wait to get all relevant configurationChange() signals QVERIFY(config.state() != QNetworkConfiguration::Active); // 2. Verify that stopping a session based on non-connected configuration does nothing @@ -570,18 +583,20 @@ // 3. Check that stopping a opened session affects also other opened session based on the same configuration. if (config.type() == QNetworkConfiguration::InternetAccessPoint) { qDebug("----------3. Check that stopping a opened session affects also other opened session based on the same configuration."); + QVERIFY(openSession(&openedSession)); QVERIFY(openSession(&innocentSession)); - + configChangeSpy.clear(); innocentSessionClosedSpy.clear(); innocentSessionStateChangedSpy.clear(); innocentErrorSpy.clear(); - + openedSession.stop(); qDebug("Waiting for %d ms to get all configurationChange signals from platform.", configWaitdelayInMs); QTest::qWait(configWaitdelayInMs); // Wait to get all relevant configurationChange() signals - + QTest::qWait(configWaitdelayInMs); // Wait to get all relevant configurationChange() signals + QVERIFY(!innocentSessionClosedSpy.isEmpty()); QVERIFY(!innocentSessionStateChangedSpy.isEmpty()); QVERIFY(!innocentErrorSpy.isEmpty()); @@ -601,14 +616,19 @@ if (config.type() == QNetworkConfiguration::ServiceNetwork) { qDebug("----------4. Skip for SNAP configuration."); } else if (config.type() == QNetworkConfiguration::InternetAccessPoint) { - qDebug("----------4. Check that stopping a non-opened session stops the other session based on the same configuration"); - QVERIFY(openSession(&innocentSession)); + qDebug("----------4. Check that stopping a non-opened session stops the other session based on the same configuration"); + qDebug("----------4.1 Opening innocent session"); + QVERIFY(openSession(&innocentSession)); qDebug("Waiting for %d ms after open to make sure all platform indications are propagated", configWaitdelayInMs); QTest::qWait(configWaitdelayInMs); + qDebug("----------4.2 Calling closedSession.stop()"); closedSession.stop(); qDebug("Waiting for %d ms to get all configurationChange signals from platform..", configWaitdelayInMs); QTest::qWait(configWaitdelayInMs); // Wait to get all relevant configurationChange() signals + QTest::qWait(configWaitdelayInMs); + QTest::qWait(configWaitdelayInMs); + QVERIFY(!innocentSessionClosedSpy.isEmpty()); QVERIFY(!innocentSessionStateChangedSpy.isEmpty()); QVERIFY(!innocentErrorSpy.isEmpty()); @@ -640,6 +660,9 @@ void tst_QNetworkSession::userChoiceSession() { + if (!testsToRun["userChoiceSession"]) { + QSKIP("Temporary skip due to value set false (or it is missing) in testsToRun map", SkipAll); + } QFETCH(QNetworkConfiguration, configuration); QVERIFY(configuration.type() == QNetworkConfiguration::UserChoice); @@ -669,7 +692,20 @@ session.open(); +#if defined(Q_OS_SYMBIAN) + // Opening & closing multiple connections in a row sometimes + // results hanging of connection opening on Symbian devices + // => If first open fails, wait a moment and try again. + if (!session.waitForOpened()) { + qDebug("**** Session open Timeout - Wait 5 seconds and try once again ****"); + session.close(); + QTest::qWait(5000); // Wait a while before trying to open session again + session.open(); + session.waitForOpened(); + } +#else session.waitForOpened(); +#endif if (session.isOpen()) QVERIFY(!sessionOpenedSpy.isEmpty() || !errorSpy.isEmpty()); @@ -769,6 +805,9 @@ void tst_QNetworkSession::sessionOpenCloseStop() { + if (!testsToRun["sessionOpenCloseStop"]) { + QSKIP("Temporary skip due to value set false (or it is missing) in testsToRun map", SkipAll); + } QFETCH(QNetworkConfiguration, configuration); QFETCH(bool, forceSessionStop); @@ -801,7 +840,20 @@ session.open(); +#if defined(Q_OS_SYMBIAN) + // Opening & closing multiple connections in a row sometimes + // results hanging of connection opening on Symbian devices + // => If first open fails, wait a moment and try again. + if (!session.waitForOpened()) { + qDebug("**** Session open Timeout - Wait 5 seconds and try once again ****"); + session.close(); + QTest::qWait(5000); // Wait a while before trying to open session again + session.open(); + session.waitForOpened(); + } +#else session.waitForOpened(); +#endif if (session.isOpen()) QVERIFY(!sessionOpenedSpy.isEmpty() || !errorSpy.isEmpty()); @@ -875,24 +927,28 @@ QVERIFY(session.error() == QNetworkSession::UnknownSessionError); session2.open(); - + QTRY_VERIFY(!sessionOpenedSpy2.isEmpty() || !errorSpy2.isEmpty()); + if (errorSpy2.isEmpty()) { + QVERIFY(session2.isOpen()); + QVERIFY(session2.state() == QNetworkSession::Connected); + } QVERIFY(session.isOpen()); - QVERIFY(session2.isOpen()); QVERIFY(session.state() == QNetworkSession::Connected); - QVERIFY(session2.state() == QNetworkSession::Connected); #if !(defined(Q_OS_SYMBIAN) && defined(__WINS__)) // On Symbian emulator, the support for data bearers is limited QVERIFY(session.interface().isValid()); #endif - QCOMPARE(session.interface().hardwareAddress(), session2.interface().hardwareAddress()); - QCOMPARE(session.interface().index(), session2.interface().index()); + if (errorSpy2.isEmpty()) { + QCOMPARE(session.interface().hardwareAddress(), session2.interface().hardwareAddress()); + QCOMPARE(session.interface().index(), session2.interface().index()); + } } sessionOpenedSpy2.clear(); - if (forceSessionStop) { + if (forceSessionStop && session2.isOpen()) { // Test forcing the second session to stop the interface. QNetworkSession::State previousState = session.state(); #ifdef Q_CC_NOKIAX86 @@ -901,15 +957,17 @@ #else bool expectStateChange = previousState != QNetworkSession::Disconnected; #endif - session2.stop(); + // QNetworkSession::stop() must result either closed() signal + // or error() signal QTRY_VERIFY(!sessionClosedSpy2.isEmpty() || !errorSpy2.isEmpty()); - QVERIFY(!session2.isOpen()); if (!errorSpy2.isEmpty()) { - QVERIFY(!errorSpy.isEmpty()); + // QNetworkSession::stop() resulted error() signal for session2 + // => also session should emit error() signal + QTRY_VERIFY(!errorSpy.isEmpty()); // check for SessionAbortedError QNetworkSession::SessionError error = @@ -929,9 +987,12 @@ QVERIFY(errorSpy.isEmpty()); QVERIFY(errorSpy2.isEmpty()); - + + // Wait for Disconnected state + QTRY_NOOP(session2.state() == QNetworkSession::Disconnected); + if (expectStateChange) - QTRY_VERIFY(stateChangedSpy2.count() >= 2 || !errorSpy2.isEmpty()); + QTRY_VERIFY(stateChangedSpy2.count() >= 1 || !errorSpy2.isEmpty()); if (!errorSpy2.isEmpty()) { QVERIFY(session2.state() == previousState); @@ -975,54 +1036,66 @@ state = qvariant_cast(stateChangedSpy2.at(3).at(0)); QVERIFY(state == QNetworkSession::Disconnected); + + QTRY_VERIFY(session.state() == QNetworkSession::Roaming || + session.state() == QNetworkSession::Connected || + session.state() == QNetworkSession::Disconnected); + QTRY_VERIFY(stateChangedSpy.count() > 0); - state = qvariant_cast(stateChangedSpy.at(0).at(0)); + state = qvariant_cast(stateChangedSpy.at(stateChangedSpy.count() - 1).at(0)); + if (state == QNetworkSession::Roaming) { - QTRY_VERIFY(!errorSpy.isEmpty() || stateChangedSpy.count() > 1); + QTRY_VERIFY(session.state() == QNetworkSession::Connected); + QTRY_VERIFY(session2.state() == QNetworkSession::Connected); + roamedSuccessfully = true; + } else if (state == QNetworkSession::Disconnected) { + QTRY_VERIFY(!errorSpy.isEmpty()); + QTRY_VERIFY(session2.state() == QNetworkSession::Disconnected); + } else if (state == QNetworkSession::Connected) { + QTRY_VERIFY(errorSpy.isEmpty()); if (stateChangedSpy.count() > 1) { - state = qvariant_cast(stateChangedSpy.at(1).at(0)); - if (state == QNetworkSession::Connected) { - roamedSuccessfully = true; - QTRY_VERIFY(session2.state() == QNetworkSession::Disconnected); - } + state = qvariant_cast(stateChangedSpy.at(stateChangedSpy.count() - 2).at(0)); + QVERIFY(state == QNetworkSession::Roaming); } - } + roamedSuccessfully = true; + } + if (roamedSuccessfully) { QString configId = session.sessionProperty("ActiveConfiguration").toString(); QNetworkConfiguration config = manager.configurationFromIdentifier(configId); QNetworkSession session3(config); QSignalSpy errorSpy3(&session3, SIGNAL(error(QNetworkSession::SessionError))); QSignalSpy sessionOpenedSpy3(&session3, SIGNAL(opened())); - session3.open(); - session3.waitForOpened(); - + session3.waitForOpened(); if (session.isOpen()) QVERIFY(!sessionOpenedSpy3.isEmpty() || !errorSpy3.isEmpty()); - session.stop(); - QTRY_VERIFY(session.state() == QNetworkSession::Disconnected); - QTRY_VERIFY(session3.state() == QNetworkSession::Disconnected); } #ifndef Q_CC_NOKIAX86 if (!roamedSuccessfully) QVERIFY(!errorSpy.isEmpty()); #endif } else { - QCOMPARE(stateChangedSpy2.count(), 2); - - QNetworkSession::State state = - qvariant_cast(stateChangedSpy2.at(0).at(0)); - QVERIFY(state == QNetworkSession::Closing); - - state = qvariant_cast(stateChangedSpy2.at(1).at(0)); - QVERIFY(state == QNetworkSession::Disconnected); + QTest::qWait(2000); // Wait awhile to get all signals from platform + + if (stateChangedSpy2.count() == 2) { + QNetworkSession::State state = + qvariant_cast(stateChangedSpy2.at(0).at(0)); + QVERIFY(state == QNetworkSession::Closing); + state = qvariant_cast(stateChangedSpy2.at(1).at(0)); + QVERIFY(state == QNetworkSession::Disconnected); + } else { // Assume .count() == 1 + QCOMPARE(stateChangedSpy2.count(), 1); + QNetworkSession::State state = qvariant_cast(stateChangedSpy2.at(0).at(0)); + // Symbian version dependant. + QVERIFY(state == QNetworkSession::Disconnected); + } } QTRY_VERIFY(!sessionClosedSpy.isEmpty()); - QVERIFY(session.state() == QNetworkSession::Disconnected); - QVERIFY(session2.state() == QNetworkSession::Disconnected); + QTRY_VERIFY(session.state() == QNetworkSession::Disconnected); } QVERIFY(errorSpy2.isEmpty()); @@ -1041,7 +1114,7 @@ QVERIFY(!session.isOpen()); #endif QVERIFY(!session2.isOpen()); - } else { + } else if (session2.isOpen()) { // Test closing the second session. { int stateChangedCountBeforeClose = stateChangedSpy2.count(); @@ -1138,9 +1211,15 @@ // at Discovered -state. void tst_QNetworkSession::outOfProcessSession() { + if (!testsToRun["outOfProcessSession"]) { + QSKIP("Temporary skip due to value set false (or it is missing) in testsToRun map", SkipAll); + } #if defined(Q_OS_SYMBIAN) && defined(__WINS__) QSKIP("Symbian emulator does not support two [QR]PRocesses linking a dll (QtBearer.dll) with global writeable static data.", SkipAll); #endif + updateConfigurations(); + QTest::qWait(2000); + QNetworkConfigurationManager manager; // Create a QNetworkConfigurationManager to detect configuration changes made in Lackey. This // is actually the essence of this testcase - to check that platform mediates/reflects changes @@ -1161,6 +1240,7 @@ lackey.start("qnetworksessionlackey"); QVERIFY(lackey.waitForStarted()); + QVERIFY(oopServer.waitForNewConnection(-1)); QLocalSocket *oopSocket = oopServer.nextPendingConnection(); @@ -1241,6 +1321,7 @@ // Refresh configurations and derive configurations matching given parameters. QNetworkConfigurationManager mgr; QSignalSpy updateSpy(&mgr, SIGNAL(updateCompleted())); + mgr.updateConfigurations(); QTRY_NOOP(updateSpy.count() == 1); if (updateSpy.count() != 1) { @@ -1249,8 +1330,7 @@ } QList discoveredConfigs = mgr.allConfigurations(QNetworkConfiguration::Discovered); foreach(QNetworkConfiguration config, discoveredConfigs) { - if ((config.state() & QNetworkConfiguration::Active) == QNetworkConfiguration::Active) { - // qDebug() << "Dumping config because is active: " << config.name(); + if ((config.state() & QNetworkConfiguration::Active) == QNetworkConfiguration::Active) { discoveredConfigs.removeOne(config); } else if (config.type() != configType) { // qDebug() << "Dumping config because type (IAP/SNAP) mismatches: " << config.name(); @@ -1287,9 +1367,23 @@ QTRY_NOOP(updateSpy.count() == 1); } +// A convinience-function: updates and prints all available confiurations and their states +void printConfigurations() +{ + QNetworkConfigurationManager manager; + QList allConfigs = + manager.allConfigurations(); + qDebug("tst_QNetworkSession::printConfigurations QNetworkConfigurationManager gives following configurations: "); + foreach(QNetworkConfiguration config, allConfigs) { + qDebug() << "Name of the configuration: " << config.name(); + qDebug() << "State of the configuration: " << config.state(); + } +} + // A convinience function for test-cases: opens the given configuration and return // true if it was done gracefully. bool openSession(QNetworkSession *session) { + bool result = true; QNetworkConfigurationManager mgr; QSignalSpy openedSpy(session, SIGNAL(opened())); QSignalSpy stateChangeSpy(session, SIGNAL(stateChanged(QNetworkSession::State))); @@ -1299,43 +1393,57 @@ // active by some other session QNetworkConfiguration::StateFlags configInitState = session->configuration().state(); QNetworkSession::State sessionInitState = session->state(); + qDebug() << "tst_QNetworkSession::openSession() name of the configuration to be opened: " << session->configuration().name(); + qDebug() << "tst_QNetworkSession::openSession() state of the configuration to be opened: " << session->configuration().state(); + qDebug() << "tst_QNetworkSession::openSession() state of the session to be opened: " << session->state(); if (session->isOpen() || !session->sessionProperty("ActiveConfiguration").toString().isEmpty()) { qDebug("tst_QNetworkSession::openSession() failure: session was already open / active."); - return false; + result = false; } else { session->open(); session->waitForOpened(120000); // Bringing interfaces up and down may take time at platform } + QTest::qWait(5000); // Wait a moment to ensure all signals are propagated // Check that connection opening went by the book. Add checks here if more strictness needed. if (!session->isOpen()) { qDebug("tst_QNetworkSession::openSession() failure: QNetworkSession::open() failed."); - return false; + result = false; } if (openedSpy.count() != 1) { qDebug("tst_QNetworkSession::openSession() failure: QNetworkSession::opened() - signal not received."); - return false; + result = false; } if (!errorSpy.isEmpty()) { qDebug("tst_QNetworkSession::openSession() failure: QNetworkSession::error() - signal was detected."); - return false; + result = false; } if (sessionInitState != QNetworkSession::Connected && stateChangeSpy.isEmpty()) { qDebug("tst_QNetworkSession::openSession() failure: QNetworkSession::stateChanged() - signals not detected."); - return false; + result = false; } if (configInitState != QNetworkConfiguration::Active && configChangeSpy.isEmpty()) { qDebug("tst_QNetworkSession::openSession() failure: QNetworkConfigurationManager::configurationChanged() - signals not detected."); - return false; + result = false; } if (session->configuration().state() != QNetworkConfiguration::Active) { qDebug("tst_QNetworkSession::openSession() failure: session's configuration is not in 'Active' -state."); - return false; + qDebug() << "tst_QNetworkSession::openSession() state is: " << session->configuration().state(); + result = false; } - return true; + if (result == false) { + qDebug() << "tst_QNetworkSession::openSession() opening session failed."; + } else { + qDebug() << "tst_QNetworkSession::openSession() opening session succeeded."; + } + qDebug() << "tst_QNetworkSession::openSession() name of the configuration is: " << session->configuration().name(); + qDebug() << "tst_QNetworkSession::openSession() configuration state is: " << session->configuration().state(); + qDebug() << "tst_QNetworkSession::openSession() session state is: " << session->state(); + + return result; } // Helper function for closing opened session. Performs checks that @@ -1348,6 +1456,11 @@ qDebug("tst_QNetworkSession::closeSession() failure: NULL session given"); return false; } + + qDebug() << "tst_QNetworkSession::closeSession() name of the configuration to be closed: " << session->configuration().name(); + qDebug() << "tst_QNetworkSession::closeSession() state of the configuration to be closed: " << session->configuration().state(); + qDebug() << "tst_QNetworkSession::closeSession() state of the session to be closed: " << session->state(); + if (session->state() != QNetworkSession::Connected || !session->isOpen()) { qDebug("tst_QNetworkSession::closeSession() failure: session is not opened."); @@ -1359,38 +1472,48 @@ QSignalSpy sessionErrorSpy(session, SIGNAL(error(QNetworkSession::SessionError))); QSignalSpy configChangeSpy(&mgr, SIGNAL(configurationChanged(QNetworkConfiguration))); + bool result = true; session->close(); + QTest::qWait(5000); // Wait a moment so that all signals are propagated if (!sessionErrorSpy.isEmpty()) { qDebug("tst_QNetworkSession::closeSession() failure: QNetworkSession::error() received."); - return false; + result = false; } if (sessionClosedSpy.count() != 1) { qDebug("tst_QNetworkSession::closeSession() failure: QNetworkSession::closed() signal not received."); - return false; + result = false; } if (lastSessionOnConfiguration && sessionStateChangedSpy.isEmpty()) { qDebug("tst_QNetworkSession::closeSession() failure: QNetworkSession::stateChanged() signals not received."); - return false; + result = false; } if (lastSessionOnConfiguration && session->state() != QNetworkSession::Disconnected) { qDebug("tst_QNetworkSession::closeSession() failure: QNetworkSession is not in Disconnected -state"); - return false; + result = false; } QTRY_NOOP(!configChangeSpy.isEmpty()); if (lastSessionOnConfiguration && configChangeSpy.isEmpty()) { qDebug("tst_QNetworkSession::closeSession() failure: QNetworkConfigurationManager::configurationChanged() - signal not detected."); - return false; + result = false; } if (lastSessionOnConfiguration && session->configuration().state() == QNetworkConfiguration::Active) { qDebug("tst_QNetworkSession::closeSession() failure: session's configuration is still in active state."); - return false; + result = false; } - return true; + if (result == false) { + qDebug() << "tst_QNetworkSession::closeSession() closing session failed."; + } else { + qDebug() << "tst_QNetworkSession::closeSession() closing session succeeded."; + } + qDebug() << "tst_QNetworkSession::closeSession() name of the configuration is: " << session->configuration().name(); + qDebug() << "tst_QNetworkSession::closeSession() configuration state is: " << session->configuration().state(); + qDebug() << "tst_QNetworkSession::closeSession() session state is: " << session->state(); + return result; } QTEST_MAIN(tst_QNetworkSession)