| /**************************************************************************** |
| ** |
| ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). |
| ** All rights reserved. |
| ** Contact: Nokia Corporation (qt-info@nokia.com) |
| ** |
| ** This file is part of the plugins of the Qt Toolkit. |
| ** |
| ** $QT_BEGIN_LICENSE:LGPL$ |
| ** GNU Lesser General Public License Usage |
| ** This file may be used under the terms of the GNU Lesser General Public |
| ** License version 2.1 as published by the Free Software Foundation and |
| ** appearing in the file LICENSE.LGPL included in the packaging of this |
| ** file. Please review the following information to ensure the GNU Lesser |
| ** General Public License version 2.1 requirements will be met: |
| ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
| ** |
| ** In addition, as a special exception, Nokia gives you certain additional |
| ** rights. These rights are described in the Nokia Qt LGPL Exception |
| ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
| ** |
| ** GNU General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU General |
| ** Public License version 3.0 as published by the Free Software Foundation |
| ** and appearing in the file LICENSE.GPL included in the packaging of this |
| ** file. Please review the following information to ensure the GNU General |
| ** Public License version 3.0 requirements will be met: |
| ** http://www.gnu.org/copyleft/gpl.html. |
| ** |
| ** Other Usage |
| ** Alternatively, this file may be used in accordance with the terms and |
| ** conditions contained in a signed written agreement between you and Nokia. |
| ** |
| ** |
| ** |
| ** |
| ** |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| #include "qcorewlanengine.h" |
| #include "../qnetworksession_impl.h" |
| |
| #include <QtNetwork/private/qnetworkconfiguration_p.h> |
| |
| #include <QtCore/qthread.h> |
| #include <QtCore/qmutex.h> |
| #include <QtCore/qcoreapplication.h> |
| #include <QtCore/qstringlist.h> |
| |
| #include <QtCore/qdebug.h> |
| |
| #include <QDir> |
| #include <CoreWLAN/CoreWLAN.h> |
| #include <CoreWLAN/CWInterface.h> |
| #include <CoreWLAN/CWNetwork.h> |
| #include <CoreWLAN/CWNetwork.h> |
| #include <CoreWLAN/CW8021XProfile.h> |
| |
| #include <Foundation/NSEnumerator.h> |
| #include <Foundation/NSKeyValueObserving.h> |
| #include <Foundation/NSAutoreleasePool.h> |
| #include <Foundation/NSLock.h> |
| |
| #include <SystemConfiguration/SCNetworkConfiguration.h> |
| #include "private/qcore_mac_p.h" |
| |
| #include <net/if.h> |
| #include <ifaddrs.h> |
| |
| inline QString qt_NSStringToQString(const NSString *nsstr) |
| { return QCFString::toQString(reinterpret_cast<const CFStringRef>(nsstr)); } |
| |
| inline NSString *qt_QStringToNSString(const QString &qstr) |
| { return [reinterpret_cast<const NSString *>(QCFString::toCFStringRef(qstr)) autorelease]; } |
| |
| |
| @interface QT_MANGLE_NAMESPACE(QNSListener) : NSObject |
| { |
| NSNotificationCenter *notificationCenter; |
| CWInterface *currentInterface; |
| QCoreWlanEngine *engine; |
| NSLock *locker; |
| } |
| - (void)notificationHandler;//:(NSNotification *)notification; |
| - (void)remove; |
| - (void)setEngine:(QCoreWlanEngine *)coreEngine; |
| - (void)dealloc; |
| |
| @property (assign) QCoreWlanEngine* engine; |
| |
| @end |
| |
| @implementation QT_MANGLE_NAMESPACE(QNSListener) |
| @synthesize engine; |
| |
| - (id) init |
| { |
| [locker lock]; |
| NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; |
| notificationCenter = [NSNotificationCenter defaultCenter]; |
| currentInterface = [CWInterface interfaceWithName:nil]; |
| [notificationCenter addObserver:self selector:@selector(notificationHandler:) name:kCWPowerDidChangeNotification object:nil]; |
| [locker unlock]; |
| [autoreleasepool release]; |
| return self; |
| } |
| |
| -(void)dealloc |
| { |
| [super dealloc]; |
| } |
| |
| -(void)setEngine:(QCoreWlanEngine *)coreEngine |
| { |
| [locker lock]; |
| if(!engine) |
| engine = coreEngine; |
| [locker unlock]; |
| } |
| |
| -(void)remove |
| { |
| [locker lock]; |
| [notificationCenter removeObserver:self]; |
| [locker unlock]; |
| } |
| |
| - (void)notificationHandler//:(NSNotification *)notification |
| { |
| engine->requestUpdate(); |
| } |
| @end |
| |
| QT_MANGLE_NAMESPACE(QNSListener) *listener = 0; |
| |
| QT_BEGIN_NAMESPACE |
| |
| void networkChangeCallback(SCDynamicStoreRef/* store*/, CFArrayRef changedKeys, void *info) |
| { |
| for ( long i = 0; i < CFArrayGetCount(changedKeys); i++) { |
| |
| QString changed = QCFString::toQString((CFStringRef)CFArrayGetValueAtIndex(changedKeys, i)); |
| if( changed.contains("/Network/Global/IPv4")) { |
| QCoreWlanEngine* wlanEngine = static_cast<QCoreWlanEngine*>(info); |
| wlanEngine->requestUpdate(); |
| } |
| } |
| return; |
| } |
| |
| |
| QScanThread::QScanThread(QObject *parent) |
| :QThread(parent) |
| { |
| } |
| |
| QScanThread::~QScanThread() |
| { |
| } |
| |
| void QScanThread::quit() |
| { |
| wait(); |
| } |
| |
| void QScanThread::run() |
| { |
| NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; |
| QStringList found; |
| mutex.lock(); |
| CWInterface *currentInterface = [CWInterface interfaceWithName:qt_QStringToNSString(interfaceName)]; |
| mutex.unlock(); |
| |
| if([currentInterface power]) { |
| NSError *err = nil; |
| NSDictionary *parametersDict = [NSDictionary dictionaryWithObjectsAndKeys: |
| [NSNumber numberWithBool:YES], kCWScanKeyMerge, |
| [NSNumber numberWithInt:kCWScanTypeFast], kCWScanKeyScanType, |
| [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_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_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)); |
| |
| } |
| } |
| } |
| // add known configurations that are not around. |
| QMapIterator<QString, QMap<QString,QString> > 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<QString, QString> ij(i.value()); |
| while (ij.hasNext()) { |
| ij.next(); |
| interfaceName = ij.value(); |
| } |
| |
| if( [currentInterface.interfaceState intValue] == kCWInterfaceStateRunning) { |
| if( networkSsid == qt_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(); |
| [autoreleasepool 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->bearerType = QNetworkConfiguration::BearerWLAN; |
| ptr->purpose = purpose; |
| |
| fetchedConfigurations.append( ptr); |
| configurationInterface.insert(ptr->id, interfaceName); |
| |
| locker.unlock(); |
| locker.relock(); |
| found.append(id); |
| return found; |
| } |
| |
| QList<QNetworkConfigurationPrivate *> QScanThread::getConfigurations() |
| { |
| QMutexLocker locker(&mutex); |
| |
| QList<QNetworkConfigurationPrivate *> foundConfigurations = fetchedConfigurations; |
| fetchedConfigurations.clear(); |
| |
| return foundConfigurations; |
| } |
| |
| void QScanThread::getUserConfigurations() |
| { |
| QMutexLocker locker(&mutex); |
| |
| 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]]; |
| if ( ![wifiInterface power] ) |
| continue; |
| |
| 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); |
| if(airportPlist != nil) { |
| NSDictionary *prefNetDict = [airportPlist objectForKey:@"PreferredNetworks"]; |
| |
| NSArray *thisSsidarray = [prefNetDict valueForKey:@"SSID_STR"]; |
| for(NSString *ssidkey in thisSsidarray) { |
| QString thisSsid = qt_NSStringToQString(ssidkey); |
| if(!userProfiles.contains(thisSsid)) { |
| QMap <QString,QString> map; |
| map.insert(thisSsid, qt_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:qt_QStringToNSString(userProfilePath)] autorelease]; |
| if(eapDict != nil) { |
| 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_NSStringToQString(objects[i]); |
| } |
| if([networkSsidStr isEqualToString:keys[i]]) { |
| ssid = qt_NSStringToQString(objects[i]); |
| } |
| if(!userProfiles.contains(networkName) |
| && !ssid.isEmpty()) { |
| QMap<QString,QString> map; |
| map.insert(ssid, qt_NSStringToQString(nsInterfaceName)); |
| userProfiles.insert(networkName, map); |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| [autoreleasepool release]; |
| } |
| |
| QString QScanThread::getSsidFromNetworkName(const QString &name) |
| { |
| QMutexLocker locker(&mutex); |
| |
| QMapIterator<QString, QMap<QString,QString> > i(userProfiles); |
| while (i.hasNext()) { |
| i.next(); |
| QMap<QString,QString> map = i.value(); |
| QMapIterator<QString, QString> 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<QString, QMap<QString,QString> > i(userProfiles); |
| while (i.hasNext()) { |
| i.next(); |
| QMap<QString,QString> map = i.value(); |
| QMapIterator<QString, QString> 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<QString, QMap<QString,QString> > i(userProfiles); |
| while (i.hasNext()) { |
| i.next(); |
| QMap<QString,QString> 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())); |
| } |
| |
| QCoreWlanEngine::~QCoreWlanEngine() |
| { |
| while (!foundConfigurations.isEmpty()) |
| delete foundConfigurations.takeFirst(); |
| [listener remove]; |
| [listener release]; |
| } |
| |
| void QCoreWlanEngine::initialize() |
| { |
| QMutexLocker locker(&mutex); |
| NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; |
| |
| if([[CWInterface supportedInterfaces] count] > 0 && !listener) { |
| listener = [[QT_MANGLE_NAMESPACE(QNSListener) alloc] init]; |
| listener.engine = this; |
| hasWifi = true; |
| } else { |
| hasWifi = false; |
| } |
| storeSession = NULL; |
| |
| startNetworkChangeLoop(); |
| [autoreleasepool release]; |
| } |
| |
| |
| QString QCoreWlanEngine::getInterfaceFromId(const QString &id) |
| { |
| QMutexLocker locker(&mutex); |
| |
| return scanThread->configurationInterface.value(id); |
| } |
| |
| bool QCoreWlanEngine::hasIdentifier(const QString &id) |
| { |
| QMutexLocker locker(&mutex); |
| |
| return scanThread->configurationInterface.contains(id); |
| } |
| |
| void QCoreWlanEngine::connectToId(const QString &id) |
| { |
| QMutexLocker locker(&mutex); |
| NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; |
| QString interfaceString = getInterfaceFromId(id); |
| |
| CWInterface *wifiInterface = |
| [CWInterface interfaceWithName: qt_QStringToNSString(interfaceString)]; |
| |
| if ([wifiInterface power]) { |
| NSError *err = nil; |
| NSMutableDictionary *params = [NSMutableDictionary dictionaryWithCapacity:0]; |
| |
| QString wantedSsid; |
| |
| QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id); |
| |
| const QString idHash = QString::number(qHash(QLatin1String("corewlan:") + ptr->name)); |
| const QString idHash2 = QString::number(qHash(QLatin1String("corewlan:") + scanThread->getNetworkNameFromSsid(ptr->name))); |
| |
| bool using8021X = false; |
| if (idHash2 != id) { |
| NSArray *array = [CW8021XProfile allUser8021XProfiles]; |
| |
| for (NSUInteger i = 0; i < [array count]; ++i) { |
| const QString networkNameHashCheck = QString::number(qHash(QLatin1String("corewlan:") + qt_NSStringToQString([[array objectAtIndex:i] userDefinedName]))); |
| |
| const QString ssidHash = QString::number(qHash(QLatin1String("corewlan:") + qt_NSStringToQString([[array objectAtIndex:i] ssid]))); |
| |
| if (id == networkNameHashCheck || id == ssidHash) { |
| const QString thisName = scanThread->getSsidFromNetworkName(id); |
| if (thisName.isEmpty()) |
| wantedSsid = id; |
| else |
| wantedSsid = thisName; |
| |
| [params setValue: [array objectAtIndex:i] forKey:kCWAssocKey8021XProfile]; |
| using8021X = true; |
| break; |
| } |
| } |
| } |
| |
| if (!using8021X) { |
| QString wantedNetwork; |
| QMapIterator<QString, QMap<QString,QString> > i(scanThread->userProfiles); |
| while (i.hasNext()) { |
| i.next(); |
| wantedNetwork = i.key(); |
| const QString networkNameHash = QString::number(qHash(QLatin1String("corewlan:") + wantedNetwork)); |
| if (id == networkNameHash) { |
| wantedSsid = scanThread->getSsidFromNetworkName(wantedNetwork); |
| break; |
| } |
| } |
| } |
| NSDictionary *scanParameters = [NSDictionary dictionaryWithObjectsAndKeys: |
| [NSNumber numberWithBool:YES], kCWScanKeyMerge, |
| [NSNumber numberWithInt:kCWScanTypeFast], kCWScanKeyScanType, |
| [NSNumber numberWithInteger:100], kCWScanKeyRestTime, |
| qt_QStringToNSString(wantedSsid), kCWScanKeySSID, |
| nil]; |
| |
| NSArray *scanArray = [wifiInterface scanForNetworksWithParameters:scanParameters error:&err]; |
| |
| if(!err) { |
| for(uint row=0; row < [scanArray count]; row++ ) { |
| CWNetwork *apNetwork = [scanArray objectAtIndex:row]; |
| |
| if(wantedSsid == qt_NSStringToQString([apNetwork ssid])) { |
| |
| if(!using8021X) { |
| SecKeychainAttribute attributes[3]; |
| |
| NSString *account = [apNetwork ssid]; |
| NSString *keyKind = @"AirPort network password"; |
| NSString *keyName = account; |
| |
| attributes[0].tag = kSecAccountItemAttr; |
| 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_NSStringToQString([err localizedDescription ]); |
| } |
| } |
| } //end scan network |
| } else { |
| qDebug() <<"scan ERROR"<< qt_NSStringToQString([err localizedDescription ]); |
| } |
| emit connectionError(id, InterfaceLookupError); |
| } |
| |
| locker.unlock(); |
| emit connectionError(id, InterfaceLookupError); |
| [autoreleasepool release]; |
| } |
| |
| void QCoreWlanEngine::disconnectFromId(const QString &id) |
| { |
| QMutexLocker locker(&mutex); |
| |
| QString interfaceString = getInterfaceFromId(id); |
| NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; |
| |
| CWInterface *wifiInterface = |
| [CWInterface interfaceWithName: qt_QStringToNSString(interfaceString)]; |
| |
| [wifiInterface disassociate]; |
| if ([[wifiInterface interfaceState]intValue] != kCWInterfaceStateInactive) { |
| locker.unlock(); |
| emit connectionError(id, DisconnectionError); |
| locker.relock(); |
| } |
| [autoreleasepool release]; |
| } |
| |
| void QCoreWlanEngine::requestUpdate() |
| { |
| scanThread->getUserConfigurations(); |
| doRequestUpdate(); |
| } |
| |
| void QCoreWlanEngine::doRequestUpdate() |
| { |
| QMutexLocker locker(&mutex); |
| |
| NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; |
| |
| NSArray *wifiInterfaces = [CWInterface supportedInterfaces]; |
| for (uint row = 0; row < [wifiInterfaces count]; ++row) { |
| scanThread->interfaceName = qt_NSStringToQString([wifiInterfaces objectAtIndex:row]); |
| scanThread->start(); |
| } |
| locker.unlock(); |
| [autoreleasepool release]; |
| } |
| |
| bool QCoreWlanEngine::isWifiReady(const QString &wifiDeviceName) |
| { |
| QMutexLocker locker(&mutex); |
| bool haswifi = false; |
| if(hasWifi) { |
| NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; |
| CWInterface *defaultInterface = [CWInterface interfaceWithName: qt_QStringToNSString(wifiDeviceName)]; |
| if([defaultInterface power]) { |
| haswifi = true; |
| } |
| [autoreleasepool release]; |
| } |
| return haswifi; |
| } |
| |
| |
| QNetworkSession::State QCoreWlanEngine::sessionStateForId(const QString &id) |
| { |
| QMutexLocker locker(&mutex); |
| QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id); |
| |
| if (!ptr) |
| return QNetworkSession::Invalid; |
| |
| if (!ptr->isValid) { |
| return QNetworkSession::Invalid; |
| } else if ((ptr->state & QNetworkConfiguration::Active) == QNetworkConfiguration::Active) { |
| return QNetworkSession::Connected; |
| } else if ((ptr->state & QNetworkConfiguration::Discovered) == |
| QNetworkConfiguration::Discovered) { |
| return QNetworkSession::Disconnected; |
| } else if ((ptr->state & QNetworkConfiguration::Defined) == QNetworkConfiguration::Defined) { |
| return QNetworkSession::NotAvailable; |
| } else if ((ptr->state & QNetworkConfiguration::Undefined) == |
| QNetworkConfiguration::Undefined) { |
| return QNetworkSession::NotAvailable; |
| } |
| |
| return QNetworkSession::Invalid; |
| } |
| |
| QNetworkConfigurationManager::Capabilities QCoreWlanEngine::capabilities() const |
| { |
| return QNetworkConfigurationManager::ForcedRoaming; |
| } |
| |
| void QCoreWlanEngine::startNetworkChangeLoop() |
| { |
| |
| SCDynamicStoreContext dynStoreContext = { 0, this/*(void *)storeSession*/, NULL, NULL, NULL }; |
| storeSession = SCDynamicStoreCreate(NULL, |
| CFSTR("networkChangeCallback"), |
| networkChangeCallback, |
| &dynStoreContext); |
| if (!storeSession ) { |
| qWarning() << "could not open dynamic store: error:" << SCErrorString(SCError()); |
| return; |
| } |
| |
| CFMutableArrayRef notificationKeys; |
| notificationKeys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); |
| CFMutableArrayRef patternsArray; |
| patternsArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); |
| |
| CFStringRef storeKey; |
| storeKey = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, |
| kSCDynamicStoreDomainState, |
| kSCEntNetIPv4); |
| CFArrayAppendValue(notificationKeys, storeKey); |
| CFRelease(storeKey); |
| |
| storeKey = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, |
| kSCDynamicStoreDomainState, |
| kSCCompAnyRegex, |
| kSCEntNetIPv4); |
| CFArrayAppendValue(patternsArray, storeKey); |
| CFRelease(storeKey); |
| |
| if (!SCDynamicStoreSetNotificationKeys(storeSession , notificationKeys, patternsArray)) { |
| qWarning() << "register notification error:"<< SCErrorString(SCError()); |
| CFRelease(storeSession ); |
| CFRelease(notificationKeys); |
| CFRelease(patternsArray); |
| return; |
| } |
| CFRelease(notificationKeys); |
| CFRelease(patternsArray); |
| |
| runloopSource = SCDynamicStoreCreateRunLoopSource(NULL, storeSession , 0); |
| if (!runloopSource) { |
| qWarning() << "runloop source error:"<< SCErrorString(SCError()); |
| CFRelease(storeSession ); |
| return; |
| } |
| |
| CFRunLoopAddSource(CFRunLoopGetCurrent(), runloopSource, kCFRunLoopDefaultMode); |
| return; |
| } |
| |
| QNetworkSessionPrivate *QCoreWlanEngine::createSessionBackend() |
| { |
| return new QNetworkSessionPrivateImpl; |
| } |
| |
| QNetworkConfigurationPrivatePointer QCoreWlanEngine::defaultConfiguration() |
| { |
| return QNetworkConfigurationPrivatePointer(); |
| } |
| |
| bool QCoreWlanEngine::requiresPolling() const |
| { |
| return true; |
| } |
| |
| void QCoreWlanEngine::networksChanged() |
| { |
| QMutexLocker locker(&mutex); |
| |
| QStringList previous = accessPointConfigurations.keys(); |
| |
| QList<QNetworkConfigurationPrivate *> foundConfigurations = scanThread->getConfigurations(); |
| while (!foundConfigurations.isEmpty()) { |
| QNetworkConfigurationPrivate *cpPriv = foundConfigurations.takeFirst(); |
| |
| previous.removeAll(cpPriv->id); |
| |
| 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; |
| } |
| |
| if (ptr->name != cpPriv->name) { |
| ptr->name = cpPriv->name; |
| changed = true; |
| } |
| |
| if (ptr->bearerType != cpPriv->bearerType) { |
| ptr->bearerType = cpPriv->bearerType; |
| changed = true; |
| } |
| |
| if (ptr->state != cpPriv->state) { |
| ptr->state = cpPriv->state; |
| changed = true; |
| } |
| |
| 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(); |
| } |
| } |
| |
| while (!previous.isEmpty()) { |
| QNetworkConfigurationPrivatePointer ptr = |
| accessPointConfigurations.take(previous.takeFirst()); |
| |
| locker.unlock(); |
| emit configurationRemoved(ptr); |
| locker.relock(); |
| } |
| |
| locker.unlock(); |
| emit updateCompleted(); |
| |
| } |
| |
| quint64 QCoreWlanEngine::bytesWritten(const QString &id) |
| { |
| QMutexLocker locker(&mutex); |
| const QString interfaceStr = getInterfaceFromId(id); |
| return getBytes(interfaceStr,false); |
| } |
| |
| quint64 QCoreWlanEngine::bytesReceived(const QString &id) |
| { |
| QMutexLocker locker(&mutex); |
| const QString interfaceStr = getInterfaceFromId(id); |
| return getBytes(interfaceStr,true); |
| } |
| |
| quint64 QCoreWlanEngine::startTime(const QString &id) |
| { |
| QMutexLocker locker(&mutex); |
| NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; |
| quint64 timestamp = 0; |
| |
| NSString *filePath = @"/Library/Preferences/SystemConfiguration/com.apple.airport.preferences.plist"; |
| NSDictionary* plistDict = [[[NSDictionary alloc] initWithContentsOfFile:filePath] autorelease]; |
| if(plistDict == nil) |
| return timestamp; |
| NSString *input = @"KnownNetworks"; |
| NSString *timeStampStr = @"_timeStamp"; |
| |
| NSString *ssidStr = @"SSID_STR"; |
| |
| for (id key in plistDict) { |
| if ([input isEqualToString:key]) { |
| |
| NSDictionary *knownNetworksDict = [plistDict objectForKey:key]; |
| if(knownNetworksDict == nil) |
| return timestamp; |
| for (id networkKey in knownNetworksDict) { |
| bool isFound = false; |
| NSDictionary *itemDict = [knownNetworksDict objectForKey:networkKey]; |
| if(itemDict == nil) |
| return timestamp; |
| NSInteger dictSize = [itemDict count]; |
| id objects[dictSize]; |
| id keys[dictSize]; |
| |
| [itemDict getObjects:objects andKeys:keys]; |
| bool ok = false; |
| for(int i = 0; i < dictSize; i++) { |
| if([ssidStr isEqualToString:keys[i]]) { |
| const QString ident = QString::number(qHash(QLatin1String("corewlan:") + qt_NSStringToQString(objects[i]))); |
| if(ident == id) { |
| ok = true; |
| } |
| } |
| if(ok && [timeStampStr isEqualToString:keys[i]]) { |
| timestamp = (quint64)[objects[i] timeIntervalSince1970]; |
| isFound = true; |
| break; |
| } |
| } |
| if(isFound) |
| break; |
| } |
| } |
| } |
| [autoreleasepool release]; |
| return timestamp; |
| } |
| |
| quint64 QCoreWlanEngine::getBytes(const QString &interfaceName, bool b) |
| { |
| struct ifaddrs *ifAddressList, *ifAddress; |
| struct if_data *if_data; |
| |
| quint64 bytes = 0; |
| ifAddressList = nil; |
| if(getifaddrs(&ifAddressList) == 0) { |
| for(ifAddress = ifAddressList; ifAddress; ifAddress = ifAddress->ifa_next) { |
| if(interfaceName == ifAddress->ifa_name) { |
| if_data = (struct if_data*)ifAddress->ifa_data; |
| if(b) { |
| bytes = if_data->ifi_ibytes; |
| break; |
| } else { |
| bytes = if_data->ifi_obytes; |
| break; |
| } |
| } |
| } |
| freeifaddrs(ifAddressList); |
| } |
| return bytes; |
| } |
| |
| QT_END_NAMESPACE |