From ee6483a76e62a69641530f36ad35f1f686914442 Mon Sep 17 00:00:00 2001 From: Lorn Potter Date: Mon, 19 Apr 2010 15:38:02 +1000 Subject: move network scan to thread. increases startup time. Task-number: QTBUG-9722 --- src/plugins/bearer/corewlan/qcorewlanengine.h | 41 +- src/plugins/bearer/corewlan/qcorewlanengine.mm | 819 +++++++++++++------------ 2 files changed, 464 insertions(+), 396 deletions(-) diff --git a/src/plugins/bearer/corewlan/qcorewlanengine.h b/src/plugins/bearer/corewlan/qcorewlanengine.h index 5c69299..854dcea 100644 --- a/src/plugins/bearer/corewlan/qcorewlanengine.h +++ b/src/plugins/bearer/corewlan/qcorewlanengine.h @@ -47,15 +47,18 @@ #include #include #include +#include #ifndef QT_NO_BEARERMANAGEMENT QT_BEGIN_NAMESPACE class QNetworkConfigurationPrivate; +class QScanThread; class QCoreWlanEngine : public QBearerEngineImpl { + friend class QScanThread; Q_OBJECT public: @@ -83,28 +86,54 @@ public: bool requiresPolling() const; private Q_SLOTS: + void init(); void doRequestUpdate(); + void networksChanged(); private: bool isWifiReady(const QString &dev); - QMap configurationInterface; - QStringList scanForSsids(const QString &interfaceName); - - bool isKnownSsid(const QString &ssid); QList foundConfigurations; SCDynamicStoreRef storeSession; CFRunLoopSourceRef runloopSource; bool hasWifi; + bool scanning; + QScanThread *scanThread; protected: - QMap > userProfiles; - void startNetworkChangeLoop(); + +}; + +class QScanThread : public QThread +{ + Q_OBJECT + +public: + QScanThread(QObject *parent = 0); + ~QScanThread(); + + void quit(); + QList getConfigurations(); + QString interfaceName; + QMap configurationInterface; void getUserConfigurations(); 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); + }; QT_END_NAMESPACE diff --git a/src/plugins/bearer/corewlan/qcorewlanengine.mm b/src/plugins/bearer/corewlan/qcorewlanengine.mm index 268126a..f54bd4d 100644 --- a/src/plugins/bearer/corewlan/qcorewlanengine.mm +++ b/src/plugins/bearer/corewlan/qcorewlanengine.mm @@ -67,10 +67,6 @@ #include #include "private/qcore_mac_p.h" -#ifndef QT_NO_BEARERMANAGEMENT - -QT_BEGIN_NAMESPACE - @interface QNSListener : NSObject { NSNotificationCenter *center; @@ -96,7 +92,6 @@ QT_BEGIN_NAMESPACE QMacCocoaAutoReleasePool pool; center = [NSNotificationCenter defaultCenter]; currentInterface = [CWInterface interfaceWithName:nil]; -// [center addObserver:self selector:@selector(notificationHandler:) name:kCWLinkDidChangeNotification object:nil]; [center addObserver:self selector:@selector(notificationHandler:) name:kCWPowerDidChangeNotification object:nil]; [locker unlock]; return self; @@ -130,6 +125,8 @@ QT_BEGIN_NAMESPACE QNSListener *listener = 0; +QT_BEGIN_NAMESPACE + void networkChangeCallback(SCDynamicStoreRef/* store*/, CFArrayRef changedKeys, void *info) { for ( long i = 0; i < CFArrayGetCount(changedKeys); i++) { @@ -143,20 +140,277 @@ void networkChangeCallback(SCDynamicStoreRef/* store*/, CFArrayRef changedKeys, return; } -QCoreWlanEngine::QCoreWlanEngine(QObject *parent) -: QBearerEngineImpl(parent) + +QScanThread::QScanThread(QObject *parent) + :QThread(parent) { - startNetworkChangeLoop(); +} + +QScanThread::~QScanThread() +{ +} + +void QScanThread::quit() +{ + wait(); +} + +void QScanThread::run() +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + QStringList found; + mutex.lock(); + CWInterface *currentInterface = [CWInterface interfaceWithName:qt_mac_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 = qt_mac_NSStringToQString([apNetwork ssid]); + const QString id = QString::number(qHash(QLatin1String("corewlan:") + networkSsid)); + found.append(id); + + QNetworkConfiguration::StateFlags state = QNetworkConfiguration::Undefined; + bool known = isKnownSsid(networkSsid); + if( [currentInterface.interfaceState intValue] == kCWInterfaceStateRunning) { + if( networkSsid == qt_mac_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(id, networkSsid, state, interfaceName, purpose)); + + } //end row +// [parametersDict release]; + + } //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 = QString::number(qHash(QLatin1String("corewlan:") + 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 == qt_mac_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]; +} + +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; + + fetchedConfigurations.append( ptr); + configurationInterface.insert(ptr->id, interfaceName); + + locker.unlock(); + locker.relock(); + found.append(id); + return found; +} + +QList QScanThread::getConfigurations() +{ + QMutexLocker locker(&mutex); + + QList foundConfigurations = fetchedConfigurations; + fetchedConfigurations.clear(); + + return foundConfigurations; +} + +void QScanThread::getUserConfigurations() +{ QMacCocoaAutoReleasePool pool; - if([[CWInterface supportedInterfaces] count] > 0 && !listener) { - listener = [[QNSListener alloc] init]; - listener.engine = this; - hasWifi = true; - } else { - hasWifi = false; + 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"]; + for(NSString *ssidkey in thisSsidarray) { + QString thisSsid = qt_mac_NSStringToQString(ssidkey); + if(!userProfiles.contains(thisSsid)) { + QMap map; + map.insert(thisSsid, qt_mac_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 = [[NSMutableDictionary alloc] initWithContentsOfFile:qt_mac_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 = qt_mac_NSStringToQString(objects[i]); + } + if([networkSsidStr isEqualToString:keys[i]]) { + ssid = qt_mac_NSStringToQString(objects[i]); + } + if(!userProfiles.contains(networkName) + && !ssid.isEmpty()) { + QMap map; + map.insert(ssid, qt_mac_NSStringToQString(nsInterfaceName)); + userProfiles.insert(networkName, map); + } + } + } + [itemDict release]; + } + } + [eapDict release]; + } +} + +QString QScanThread::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(); + 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) +{ + 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(); + } + } } - QMetaObject::invokeMethod(this, "requestUpdate", Qt::QueuedConnection); + 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) +: QBearerEngineImpl(parent), scanThread(0) +{ + scanThread = new QScanThread(this); + connect(scanThread, SIGNAL(networksChanged()), + this, SLOT(networksChanged())); + + QTimer::singleShot(0,this,SLOT(init())); } QCoreWlanEngine::~QCoreWlanEngine() @@ -167,18 +421,33 @@ QCoreWlanEngine::~QCoreWlanEngine() [listener release]; } +void QCoreWlanEngine::init() +{ + if([[CWInterface supportedInterfaces] count] > 0 && !listener) { + listener = [[QNSListener alloc] init]; + listener.engine = this; + hasWifi = true; + } else { + hasWifi = false; + } + storeSession = NULL; + + startNetworkChangeLoop(); +} + + QString QCoreWlanEngine::getInterfaceFromId(const QString &id) { QMutexLocker locker(&mutex); - return configurationInterface.value(id); + return scanThread->configurationInterface.value(id); } bool QCoreWlanEngine::hasIdentifier(const QString &id) { QMutexLocker locker(&mutex); - return configurationInterface.contains(id); + return scanThread->configurationInterface.contains(id); } void QCoreWlanEngine::connectToId(const QString &id) @@ -195,13 +464,14 @@ void QCoreWlanEngine::connectToId(const QString &id) NSMutableDictionary *params = [NSMutableDictionary dictionaryWithCapacity:0]; QString wantedSsid; - bool using8021X = false; QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id); - const QString idHash = QString::number(qHash(QLatin1String("corewlan:") + getNetworkNameFromSsid(ptr->name))); + const QString idHash = QString::number(qHash(QLatin1String("corewlan:") + ptr->name)); + const QString idHash2 = QString::number(qHash(QLatin1String("corewlan:") + scanThread->getNetworkNameFromSsid(ptr->name))); - if (idHash != id) { + bool using8021X = false; + if (idHash2 != id) { NSArray *array = [CW8021XProfile allUser8021XProfiles]; for (NSUInteger i = 0; i < [array count]; ++i) { @@ -210,7 +480,7 @@ void QCoreWlanEngine::connectToId(const QString &id) const QString ssidHash = QString::number(qHash(QLatin1String("corewlan:") + qt_mac_NSStringToQString([[array objectAtIndex:i] ssid]))); if (id == networkNameHashCheck || id == ssidHash) { - const QString thisName = getSsidFromNetworkName(id); + const QString thisName = scanThread->getSsidFromNetworkName(id); if (thisName.isEmpty()) wantedSsid = id; else @@ -225,24 +495,25 @@ void QCoreWlanEngine::connectToId(const QString &id) if (!using8021X) { QString wantedNetwork; - QMapIterator > i(userProfiles); + QMapIterator > i(scanThread->userProfiles); while (i.hasNext()) { i.next(); wantedNetwork = i.key(); const QString networkNameHash = QString::number(qHash(QLatin1String("corewlan:") + wantedNetwork)); if (id == networkNameHash) { - wantedSsid = getSsidFromNetworkName(wantedNetwork); + wantedSsid = scanThread->getSsidFromNetworkName(wantedNetwork); break; } } } NSDictionary *scanParameters = [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithBool:YES], kCWScanKeyMerge, + [NSNumber numberWithInt:kCWScanTypeFast], kCWScanKeyScanType, [NSNumber numberWithInteger:100], kCWScanKeyRestTime, qt_mac_QStringToNSString(wantedSsid), kCWScanKeySSID, nil]; - NSArray *scanArray = [NSArray arrayWithArray:[wifiInterface scanForNetworksWithParameters:scanParameters error:&err]]; + NSArray *scanArray = [wifiInterface scanForNetworksWithParameters:scanParameters error:&err]; if(!err) { for(uint row=0; row < [scanArray count]; row++ ) { @@ -261,326 +532,110 @@ void QCoreWlanEngine::connectToId(const QString &id) attributes[0].data = (void *)[account UTF8String]; attributes[0].length = [account length]; - attributes[1].tag = kSecDescriptionItemAttr; - attributes[1].data = (void *)[keyKind UTF8String]; - attributes[1].length = [keyKind length]; - - attributes[2].tag = kSecLabelItemAttr; - attributes[2].data = (void *)[keyName UTF8String]; - attributes[2].length = [keyName length]; - - SecKeychainAttributeList attributeList = {3,attributes}; - - SecKeychainSearchRef searchRef; - SecKeychainSearchCreateFromAttributes(NULL, kSecGenericPasswordItemClass, &attributeList, &searchRef); - - NSString *password = @""; - SecKeychainItemRef searchItem; - - if (SecKeychainSearchCopyNext(searchRef, &searchItem) == noErr) { - UInt32 realPasswordLength; - SecKeychainAttribute attributesW[8]; - attributesW[0].tag = kSecAccountItemAttr; - SecKeychainAttributeList listW = {1,attributesW}; - char *realPassword; - OSStatus status = SecKeychainItemCopyContent(searchItem, NULL, &listW, &realPasswordLength,(void **)&realPassword); - - if (status == noErr) { - if (realPassword != NULL) { - - QByteArray pBuf; - pBuf.resize(realPasswordLength); - pBuf.prepend(realPassword); - pBuf.insert(realPasswordLength,'\0'); - - password = [NSString stringWithUTF8String:pBuf]; - } - SecKeychainItemFreeContent(&listW, realPassword); - } - - CFRelease(searchItem); - } else { - qDebug() << "SecKeychainSearchCopyNext error"; - } - [params setValue: password forKey: kCWAssocKeyPassphrase]; - } // end using8021X - - - bool result = [wifiInterface associateToNetwork: apNetwork parameters:[NSDictionary dictionaryWithDictionary:params] error:&err]; - - if(!err) { - if(!result) { - emit connectionError(id, ConnectError); - } else { - return; - } - } else { - qDebug() <<"associate ERROR"<< qt_mac_NSStringToQString([err localizedDescription ]); - } - } - } //end scan network - } else { - qDebug() <<"scan ERROR"<< qt_mac_NSStringToQString([err localizedDescription ]); - } - emit connectionError(id, InterfaceLookupError); - } - - locker.unlock(); - emit connectionError(id, InterfaceLookupError); -} - -void QCoreWlanEngine::disconnectFromId(const QString &id) -{ - QMutexLocker locker(&mutex); - - QString interfaceString = getInterfaceFromId(id); - QMacCocoaAutoReleasePool pool; - - CWInterface *wifiInterface = - [CWInterface interfaceWithName: qt_mac_QStringToNSString(interfaceString)]; - - [wifiInterface disassociate]; - if ([[wifiInterface interfaceState]intValue] != kCWInterfaceStateInactive) { - locker.unlock(); - emit connectionError(id, DisconnectionError); - locker.relock(); - } -} - -void QCoreWlanEngine::requestUpdate() -{ - getUserConfigurations(); - doRequestUpdate(); -} - -void QCoreWlanEngine::doRequestUpdate() -{ - QMutexLocker locker(&mutex); - - QMacCocoaAutoReleasePool pool; - - QStringList previous = accessPointConfigurations.keys(); - - NSArray *wifiInterfaces = [CWInterface supportedInterfaces]; - for (uint row = 0; row < [wifiInterfaces count]; ++row) { - foreach (const QString &interface, - scanForSsids(qt_mac_NSStringToQString([wifiInterfaces objectAtIndex:row]))) { - previous.removeAll(interface); - } - } - - while (!previous.isEmpty()) { - QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.take(previous.takeFirst()); - - configurationInterface.remove(ptr->id); - - locker.unlock(); - emit configurationRemoved(ptr); - locker.relock(); - } - - locker.unlock(); - emit updateCompleted(); -} - -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(); - const QString networkNameHash = QString::number(qHash(QLatin1String("corewlan:") + i.key())); - if (name == i.key() || name == networkNameHash) { - 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(); -} - -QStringList QCoreWlanEngine::scanForSsids(const QString &interfaceName) -{ - QMutexLocker locker(&mutex); - - QStringList found; - - if(!hasWifi) { - return found; - } - QMacCocoaAutoReleasePool pool; - - CWInterface *currentInterface = [CWInterface interfaceWithName:qt_mac_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]; + attributes[1].tag = kSecDescriptionItemAttr; + attributes[1].data = (void *)[keyKind UTF8String]; + attributes[1].length = [keyKind length]; - const QString networkSsid = qt_mac_NSStringToQString([apNetwork ssid]); + attributes[2].tag = kSecLabelItemAttr; + attributes[2].data = (void *)[keyName UTF8String]; + attributes[2].length = [keyName length]; - const QString id = QString::number(qHash(QLatin1String("corewlan:") + networkSsid)); - found.append(id); + SecKeychainAttributeList attributeList = {3,attributes}; - QNetworkConfiguration::StateFlags state = QNetworkConfiguration::Undefined; - bool known = isKnownSsid(networkSsid); - if( [currentInterface.interfaceState intValue] == kCWInterfaceStateRunning) { - if( networkSsid == qt_mac_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; - } + SecKeychainSearchRef searchRef; + SecKeychainSearchCreateFromAttributes(NULL, kSecGenericPasswordItemClass, &attributeList, &searchRef); - found.append(foundNetwork(id, networkSsid, state, interfaceName, purpose)); + NSString *password = @""; + SecKeychainItemRef searchItem; - } //end row - } //end error - } // endwifi power + if (SecKeychainSearchCopyNext(searchRef, &searchItem) == noErr) { + UInt32 realPasswordLength; + SecKeychainAttribute attributesW[8]; + attributesW[0].tag = kSecAccountItemAttr; + SecKeychainAttributeList listW = {1,attributesW}; + char *realPassword; + OSStatus status = SecKeychainItemCopyContent(searchItem, NULL, &listW, &realPasswordLength,(void **)&realPassword); - // add known configurations that are not around. - QMapIterator > i(userProfiles); - while (i.hasNext()) { - i.next(); + if (status == noErr) { + if (realPassword != NULL) { - QString networkName = i.key(); - const QString id = QString::number(qHash(QLatin1String("corewlan:") + networkName)); + QByteArray pBuf; + pBuf.resize(realPasswordLength); + pBuf.prepend(realPassword); + pBuf.insert(realPasswordLength,'\0'); - 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(); - } + password = [NSString stringWithUTF8String:pBuf]; + } + SecKeychainItemFreeContent(&listW, realPassword); + } - if( [currentInterface.interfaceState intValue] == kCWInterfaceStateRunning) { - if( networkSsid == qt_mac_NSStringToQString([currentInterface ssid])) { - state = QNetworkConfiguration::Active; - } - } - if(state == QNetworkConfiguration::Undefined) { - if( userProfiles.contains(networkName) - && found.contains(ssidId)) { - state = QNetworkConfiguration::Discovered; - } - } + CFRelease(searchItem); + } else { + qDebug() << "SecKeychainSearchCopyNext error"; + } + [params setValue: password forKey: kCWAssocKeyPassphrase]; + } // end using8021X - if(state == QNetworkConfiguration::Undefined) { - state = QNetworkConfiguration::Defined; - } - found.append(foundNetwork(id, networkName, state, interfaceName, QNetworkConfiguration::UnknownPurpose)); + bool result = [wifiInterface associateToNetwork: apNetwork parameters:[NSDictionary dictionaryWithDictionary:params] error:&err]; + + if(!err) { + if(!result) { + emit connectionError(id, ConnectError); + } else { + return; + } + } else { + qDebug() <<"associate ERROR"<< qt_mac_NSStringToQString([err localizedDescription ]); + } + } + } //end scan network + } else { + qDebug() <<"scan ERROR"<< qt_mac_NSStringToQString([err localizedDescription ]); } + emit connectionError(id, InterfaceLookupError); } - return found; + + locker.unlock(); + emit connectionError(id, InterfaceLookupError); } -QStringList QCoreWlanEngine::foundNetwork(const QString &id, const QString &name, const QNetworkConfiguration::StateFlags state, const QString &interfaceName, const QNetworkConfiguration::Purpose purpose) +void QCoreWlanEngine::disconnectFromId(const QString &id) { - QStringList found; QMutexLocker locker(&mutex); - if (accessPointConfigurations.contains(id)) { - QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id); - - bool changed = false; - - ptr->mutex.lock(); - - if (!ptr->isValid) { - ptr->isValid = true; - changed = true; - } - - if (ptr->name != name) { - ptr->name = name; - changed = true; - } - if (ptr->id != id) { - ptr->id = id; - changed = true; - } + QString interfaceString = getInterfaceFromId(id); + QMacCocoaAutoReleasePool pool; - if (ptr->state != state) { - ptr->state = state; - changed = true; - } + CWInterface *wifiInterface = + [CWInterface interfaceWithName: qt_mac_QStringToNSString(interfaceString)]; - if (ptr->purpose != purpose) { - ptr->purpose = purpose; - changed = true; - } - ptr->mutex.unlock(); + [wifiInterface disassociate]; + if ([[wifiInterface interfaceState]intValue] != kCWInterfaceStateInactive) { + locker.unlock(); + emit connectionError(id, DisconnectionError); + locker.relock(); + } +} - if (changed) { - locker.unlock(); - emit configurationChanged(ptr); - locker.relock(); - } - found.append(id); - } else { - QNetworkConfigurationPrivatePointer ptr(new QNetworkConfigurationPrivate); +void QCoreWlanEngine::requestUpdate() +{ + scanThread->getUserConfigurations(); + doRequestUpdate(); +} - ptr->name = name; - ptr->isValid = true; - ptr->id = id; - ptr->state = state; - ptr->type = QNetworkConfiguration::InternetAccessPoint; - ptr->bearer = QLatin1String("WLAN"); - ptr->purpose = purpose; +void QCoreWlanEngine::doRequestUpdate() +{ + QMutexLocker locker(&mutex); - accessPointConfigurations.insert(ptr->id, ptr); - configurationInterface.insert(ptr->id, interfaceName); + QMacCocoaAutoReleasePool pool; - locker.unlock(); - emit configurationAdded(ptr); - locker.relock(); - found.append(id); + NSArray *wifiInterfaces = [CWInterface supportedInterfaces]; + for (uint row = 0; row < [wifiInterfaces count]; ++row) { + scanThread->interfaceName = qt_mac_NSStringToQString([wifiInterfaces objectAtIndex:row]); + scanThread->start(); } - return found; + locker.unlock(); } bool QCoreWlanEngine::isWifiReady(const QString &wifiDeviceName) @@ -596,20 +651,6 @@ bool QCoreWlanEngine::isWifiReady(const QString &wifiDeviceName) return false; } -bool QCoreWlanEngine::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; -} QNetworkSession::State QCoreWlanEngine::sessionStateForId(const QString &id) { @@ -644,7 +685,6 @@ QNetworkConfigurationManager::Capabilities QCoreWlanEngine::capabilities() const void QCoreWlanEngine::startNetworkChangeLoop() { - storeSession = NULL; SCDynamicStoreContext dynStoreContext = { 0, this/*(void *)storeSession*/, NULL, NULL, NULL }; storeSession = SCDynamicStoreCreate(NULL, @@ -711,74 +751,73 @@ bool QCoreWlanEngine::requiresPolling() const return true; } -void QCoreWlanEngine::getUserConfigurations() +void QCoreWlanEngine::networksChanged() { - QMacCocoaAutoReleasePool pool; - userProfiles.clear(); + QMutexLocker locker(&mutex); - NSArray *wifiInterfaces = [CWInterface supportedInterfaces]; - for(uint row=0; row < [wifiInterfaces count]; row++ ) { + QStringList previous = accessPointConfigurations.keys(); - 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); + QList foundConfigurations = scanThread->getConfigurations(); + while (!foundConfigurations.isEmpty()) { + QNetworkConfigurationPrivate *cpPriv = foundConfigurations.takeFirst(); - NSDictionary *prefNetDict = [airportPlist objectForKey:@"PreferredNetworks"]; + previous.removeAll(cpPriv->id); - NSArray *thisSsidarray = [prefNetDict valueForKey:@"SSID_STR"]; - for(NSString *ssidkey in thisSsidarray) { - QString thisSsid = qt_mac_NSStringToQString(ssidkey); - if(!userProfiles.contains(thisSsid)) { - QMap map; - map.insert(thisSsid, qt_mac_NSStringToQString(nsInterfaceName)); - userProfiles.insert(thisSsid, map); + if (accessPointConfigurations.contains(cpPriv->id)) { + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(cpPriv->id); + + bool changed = false; + + ptr->mutex.lock(); + + if (ptr->isValid != cpPriv->isValid) { + ptr->isValid = cpPriv->isValid; + changed = true; } - } - CFRelease(airportPlist); - // 802.1X user profiles - QString userProfilePath = QDir::homePath() + "/Library/Preferences/com.apple.eap.profiles.plist"; - NSDictionary* eapDict = [[NSDictionary alloc] initWithContentsOfFile:qt_mac_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) { + if (ptr->name != cpPriv->name) { + ptr->name = cpPriv->name; + changed = true; + } - NSInteger dictSize = [itemKey count]; - id objects[dictSize]; - id keys[dictSize]; + if (ptr->state != cpPriv->state) { + ptr->state = cpPriv->state; + changed = true; + } - [itemKey getObjects:objects andKeys:keys]; - QString networkName; - QString ssid; - for(int i = 0; i < dictSize; i++) { - if([nameStr isEqualToString:keys[i]]) { - networkName = qt_mac_NSStringToQString(objects[i]); - } - if([networkSsidStr isEqualToString:keys[i]]) { - ssid = qt_mac_NSStringToQString(objects[i]); - } - if(!userProfiles.contains(networkName) - && !ssid.isEmpty()) { - QMap map; - map.insert(ssid, qt_mac_NSStringToQString(nsInterfaceName)); - userProfiles.insert(networkName, map); - } - } - } - [itemDict release]; + ptr->mutex.unlock(); + + if (changed) { + locker.unlock(); + emit configurationChanged(ptr); + locker.relock(); } + + delete cpPriv; + } else { + QNetworkConfigurationPrivatePointer ptr(cpPriv); + + accessPointConfigurations.insert(ptr->id, ptr); + + locker.unlock(); + emit configurationAdded(ptr); + locker.relock(); } - [eapDict release]; } + + while (!previous.isEmpty()) { + QNetworkConfigurationPrivatePointer ptr = + accessPointConfigurations.take(previous.takeFirst()); + + locker.unlock(); + emit configurationRemoved(ptr); + locker.relock(); + } + + locker.unlock(); + emit updateCompleted(); + } -QT_END_NAMESPACE -#endif // QT_NO_BEARERMANAGEMENT +QT_END_NAMESPACE -- cgit v0.12