1/**************************************************************************** 2** 3** Copyright (C) 2016 The Qt Company Ltd. 4** Contact: https://www.qt.io/licensing/ 5** 6** This file is part of the plugins of the Qt Toolkit. 7** 8** $QT_BEGIN_LICENSE:LGPL$ 9** Commercial License Usage 10** Licensees holding valid commercial Qt licenses may use this file in 11** accordance with the commercial license agreement provided with the 12** Software or, alternatively, in accordance with the terms contained in 13** a written agreement between you and The Qt Company. For licensing terms 14** and conditions see https://www.qt.io/terms-conditions. For further 15** information use the contact form at https://www.qt.io/contact-us. 16** 17** GNU Lesser General Public License Usage 18** Alternatively, this file may be used under the terms of the GNU Lesser 19** General Public License version 3 as published by the Free Software 20** Foundation and appearing in the file LICENSE.LGPL3 included in the 21** packaging of this file. Please review the following information to 22** ensure the GNU Lesser General Public License version 3 requirements 23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. 24** 25** GNU General Public License Usage 26** Alternatively, this file may be used under the terms of the GNU 27** General Public License version 2.0 or (at your option) the GNU General 28** Public license version 3 or any later version approved by the KDE Free 29** Qt Foundation. The licenses are as published by the Free Software 30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 31** included in the packaging of this file. Please review the following 32** information to ensure the GNU General Public License requirements will 33** be met: https://www.gnu.org/licenses/gpl-2.0.html and 34** https://www.gnu.org/licenses/gpl-3.0.html. 35** 36** $QT_END_LICENSE$ 37** 38****************************************************************************/ 39 40#include "qcorewlanengine.h" 41#include "../qnetworksession_impl.h" 42 43#include <QtNetwork/private/qnetworkconfiguration_p.h> 44 45#include <QtCore/qthread.h> 46#include <QtCore/qmutex.h> 47#include <QtCore/qcoreapplication.h> 48#include <QtCore/qstringlist.h> 49 50#include <QtCore/qdebug.h> 51 52#include <QDir> 53#ifndef QT_NO_BEARERMANAGEMENT 54 55extern "C" { // Otherwise it won't find CWKeychain* symbols at link time 56#import <CoreWLAN/CoreWLAN.h> 57} 58 59#include "private/qcore_mac_p.h" 60 61#include <net/if.h> 62#include <ifaddrs.h> 63 64@interface QT_MANGLE_NAMESPACE(QNSListener) : NSObject <CWEventDelegate> 65@property (assign) QCoreWlanEngine* engine; 66@end 67QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSListener); 68 69@implementation QNSListener { 70 NSNotificationCenter *notificationCenter; 71 CWWiFiClient *client; 72 QCoreWlanEngine *engine; 73 NSLock *locker; 74} 75 76- (instancetype)init 77{ 78 if ((self = [super init])) { 79 [locker lock]; 80 QMacAutoReleasePool pool; 81 notificationCenter = [NSNotificationCenter defaultCenter]; 82 client = [CWWiFiClient sharedWiFiClient]; 83 client.delegate = self; 84 [client startMonitoringEventWithType:CWEventTypePowerDidChange error:nil]; 85 [locker unlock]; 86 } 87 return self; 88} 89 90static QNSListener *listener = 0; 91 92-(void)dealloc 93{ 94 client.delegate = nil; 95 listener = nil; 96 [super dealloc]; 97} 98 99-(void)setEngine:(QCoreWlanEngine *)coreEngine 100{ 101 [locker lock]; 102 if(!engine) 103 engine = coreEngine; 104 [locker unlock]; 105} 106 107-(QCoreWlanEngine *)engine 108{ 109 return engine; 110} 111 112-(void)remove 113{ 114 [locker lock]; 115 [client stopMonitoringAllEventsAndReturnError:nil]; 116 [locker unlock]; 117} 118 119- (void)powerStateDidChangeForWiFiInterfaceWithName:(NSString *)interfaceName 120{ 121 Q_UNUSED(interfaceName); 122 engine->requestUpdate(); 123} 124@end 125 126 127QT_BEGIN_NAMESPACE 128 129void networkChangeCallback(SCDynamicStoreRef/* store*/, CFArrayRef changedKeys, void *info) 130{ 131 for ( long i = 0; i < CFArrayGetCount(changedKeys); i++) { 132 133 QString changed = QString::fromCFString((CFStringRef)CFArrayGetValueAtIndex(changedKeys, i)); 134 if( changed.contains("/Network/Global/IPv4")) { 135 QCoreWlanEngine* wlanEngine = static_cast<QCoreWlanEngine*>(info); 136 wlanEngine->requestUpdate(); 137 } 138 } 139 return; 140} 141 142 143QScanThread::QScanThread(QObject *parent) 144 :QThread(parent) 145{ 146} 147 148QScanThread::~QScanThread() 149{ 150} 151 152void QScanThread::quit() 153{ 154 wait(); 155} 156 157void QScanThread::run() 158{ 159 QMacAutoReleasePool pool; 160 QStringList found; 161 mutex.lock(); 162 CWInterface *currentInterface = [[CWWiFiClient sharedWiFiClient] 163 interfaceWithName:interfaceName.toNSString()]; 164 mutex.unlock(); 165 const bool currentInterfaceServiceActive = currentInterface.serviceActive; 166 167 if (currentInterface.powerOn) { 168 NSError *err = nil; 169 170 NSSet* apSet = [currentInterface scanForNetworksWithName:nil error:&err]; 171 172 if (!err) { 173 for (CWNetwork *apNetwork in apSet) { 174 const QString networkSsid = QString::fromNSString([apNetwork ssid]); 175 const QString id = QString::number(qHash(QLatin1String("corewlan:") + networkSsid)); 176 found.append(id); 177 178 QNetworkConfiguration::StateFlags state = QNetworkConfiguration::Undefined; 179 bool known = isKnownSsid(networkSsid); 180 if (currentInterfaceServiceActive) { 181 if (networkSsid == QString::fromNSString([currentInterface ssid])) { 182 state = QNetworkConfiguration::Active; 183 } 184 } 185 if (state == QNetworkConfiguration::Undefined) { 186 if(known) { 187 state = QNetworkConfiguration::Discovered; 188 } else { 189 state = QNetworkConfiguration::Undefined; 190 } 191 } 192 QNetworkConfiguration::Purpose purpose = QNetworkConfiguration::UnknownPurpose; 193 if ([apNetwork supportsSecurity:kCWSecurityNone]) { 194 purpose = QNetworkConfiguration::PublicPurpose; 195 } else { 196 purpose = QNetworkConfiguration::PrivatePurpose; 197 } 198 199 found.append(foundNetwork(id, networkSsid, state, interfaceName, purpose)); 200 201 } 202 } 203 } 204 // add known configurations that are not around. 205 for (auto i = userProfiles.cbegin(), end = userProfiles.cend(); i != end; ++i) { 206 207 QString networkName = i.key(); 208 const QString id = QString::number(qHash(QLatin1String("corewlan:") + networkName)); 209 210 if(!found.contains(id)) { 211 QString networkSsid = getSsidFromNetworkName(networkName); 212 const QString ssidId = QString::number(qHash(QLatin1String("corewlan:") + networkSsid)); 213 QNetworkConfiguration::StateFlags state = QNetworkConfiguration::Undefined; 214 QString interfaceName; 215 if (!i.value().isEmpty()) 216 interfaceName = i.value().last(); 217 218 if (currentInterfaceServiceActive) { 219 if (networkSsid == QString::fromNSString([currentInterface ssid])) { 220 state = QNetworkConfiguration::Active; 221 } 222 } 223 if(state == QNetworkConfiguration::Undefined) { 224 if( userProfiles.contains(networkName) 225 && found.contains(ssidId)) { 226 state = QNetworkConfiguration::Discovered; 227 } 228 } 229 230 if(state == QNetworkConfiguration::Undefined) { 231 state = QNetworkConfiguration::Defined; 232 } 233 234 found.append(foundNetwork(id, networkName, state, interfaceName, QNetworkConfiguration::UnknownPurpose)); 235 } 236 } 237 emit networksChanged(); 238} 239 240QStringList QScanThread::foundNetwork(const QString &id, const QString &name, const QNetworkConfiguration::StateFlags state, const QString &interfaceName, const QNetworkConfiguration::Purpose purpose) 241{ 242 QStringList found; 243 QMutexLocker locker(&mutex); 244 QNetworkConfigurationPrivate *ptr = new QNetworkConfigurationPrivate; 245 246 ptr->name = name; 247 ptr->isValid = true; 248 ptr->id = id; 249 ptr->state = state; 250 ptr->type = QNetworkConfiguration::InternetAccessPoint; 251 ptr->bearerType = QNetworkConfiguration::BearerWLAN; 252 ptr->purpose = purpose; 253 254 fetchedConfigurations.append( ptr); 255 configurationInterface.insert(ptr->id, interfaceName); 256 257 locker.unlock(); 258 locker.relock(); 259 found.append(id); 260 return found; 261} 262 263QList<QNetworkConfigurationPrivate *> QScanThread::getConfigurations() 264{ 265 QMutexLocker locker(&mutex); 266 return qExchange(fetchedConfigurations, {}); 267} 268 269void QScanThread::getUserConfigurations() 270{ 271 QMutexLocker locker(&mutex); 272 273 QMacAutoReleasePool pool; 274 userProfiles.clear(); 275 276 NSArray<NSString *> *wifiInterfaces = [CWWiFiClient interfaceNames]; 277 for (NSString *ifName in wifiInterfaces) { 278 279 CWInterface *wifiInterface = [[CWWiFiClient sharedWiFiClient] interfaceWithName:ifName]; 280 281 NSString *nsInterfaceName = wifiInterface.ssid; 282// add user configured system networks 283 SCDynamicStoreRef dynRef = SCDynamicStoreCreate(kCFAllocatorSystemDefault, (CFStringRef)@"Qt corewlan", nil, nil); 284 NSDictionary * airportPlist = (NSDictionary *)SCDynamicStoreCopyValue(dynRef, (CFStringRef)[NSString stringWithFormat:@"Setup:/Network/Interface/%@/AirPort", nsInterfaceName]); 285 CFRelease(dynRef); 286 if(airportPlist != nil) { 287 NSDictionary *prefNetDict = [airportPlist objectForKey:@"PreferredNetworks"]; 288 289 NSArray<NSString *> *thisSsidarray = [prefNetDict valueForKey:@"SSID_STR"]; 290 for (NSString *ssidkey in thisSsidarray) { 291 QString thisSsid = QString::fromNSString(ssidkey); 292 if(!userProfiles.contains(thisSsid)) { 293 QMap <QString,QString> map; 294 map.insert(thisSsid, QString::fromNSString(nsInterfaceName)); 295 userProfiles.insert(thisSsid, map); 296 } 297 } 298 CFRelease(airportPlist); 299 } 300 301 // remembered networks 302 CWConfiguration *userConfig = [wifiInterface configuration]; 303 NSOrderedSet *networkProfiles = [userConfig networkProfiles]; 304 NSEnumerator *enumerator = [networkProfiles objectEnumerator]; 305 CWNetworkProfile *wProfile; 306 while ((wProfile = [enumerator nextObject])) { 307 QString networkName = QString::fromNSString([wProfile ssid]); 308 309 if (!userProfiles.contains(networkName)) { 310 QMap<QString,QString> map; 311 map.insert(networkName, QString::fromNSString(nsInterfaceName)); 312 userProfiles.insert(networkName, map); 313 } 314 } 315 316 // 802.1X user profiles 317 QString userProfilePath = QDir::homePath() + "/Library/Preferences/com.apple.eap.profiles.plist"; 318 NSDictionary* eapDict = [[[NSDictionary alloc] initWithContentsOfFile:userProfilePath.toNSString()] autorelease]; 319 if(eapDict != nil) { 320 NSString *profileStr= @"Profiles"; 321 NSString *nameStr = @"UserDefinedName"; 322 NSString *networkSsidStr = @"Wireless Network"; 323 for (id profileKey in eapDict) { 324 if ([profileStr isEqualToString:profileKey]) { 325 NSDictionary *itemDict = [eapDict objectForKey:profileKey]; 326 for (id itemKey in itemDict) { 327 328 NSInteger dictSize = [itemKey count]; 329 id objects[dictSize]; 330 id keys[dictSize]; 331 332 [itemKey getObjects:objects andKeys:keys]; 333 QString networkName; 334 QString ssid; 335 for (int i = 0; i < dictSize; i++) { 336 if([nameStr isEqualToString:keys[i]]) { 337 networkName = QString::fromNSString(objects[i]); 338 } 339 if ([networkSsidStr isEqualToString:keys[i]]) { 340 ssid = QString::fromNSString(objects[i]); 341 } 342 if (!userProfiles.contains(networkName) 343 && !ssid.isEmpty()) { 344 QMap<QString,QString> map; 345 map.insert(ssid, QString::fromNSString(nsInterfaceName)); 346 userProfiles.insert(networkName, map); 347 } 348 } 349 } 350 } 351 } 352 } 353 } 354} 355 356QString QScanThread::getSsidFromNetworkName(const QString &name) const 357{ 358 QMutexLocker locker(&mutex); 359 360 for (auto i = userProfiles.cbegin(), end = userProfiles.cend(); i != end; ++i) { 361 for (auto ij = i.value().cbegin(), end = i.value().cend(); ij != end; ++ij) { 362 const QString networkNameHash = QString::number(qHash(QLatin1String("corewlan:") +i.key())); 363 if(name == i.key() || name == networkNameHash) { 364 return ij.key(); 365 } 366 } 367 } 368 return QString(); 369} 370 371QString QScanThread::getNetworkNameFromSsid(const QString &ssid) const 372{ 373 QMutexLocker locker(&mutex); 374 375 for (auto i = userProfiles.cbegin(), end = userProfiles.cend(); i != end; ++i) { 376 if (i.value().contains(ssid)) 377 return i.key(); 378 } 379 return QString(); 380} 381 382bool QScanThread::isKnownSsid(const QString &ssid) const 383{ 384 QMutexLocker locker(&mutex); 385 386 for (auto i = userProfiles.cbegin(), end = userProfiles.cend(); i != end; ++i) { 387 if (i.value().contains(ssid)) 388 return true; 389 } 390 return false; 391} 392 393 394QCoreWlanEngine::QCoreWlanEngine(QObject *parent) 395: QBearerEngineImpl(parent), scanThread(0) 396{ 397 scanThread = new QScanThread(this); 398 connect(scanThread, SIGNAL(networksChanged()), 399 this, SLOT(networksChanged())); 400} 401 402QCoreWlanEngine::~QCoreWlanEngine() 403{ 404 scanThread->wait(); 405 406 qDeleteAll(qExchange(foundConfigurations, {})); 407 [listener remove]; 408 [listener release]; 409} 410 411void QCoreWlanEngine::initialize() 412{ 413 QMutexLocker locker(&mutex); 414 QMacAutoReleasePool pool; 415 416 if ([[CWWiFiClient interfaceNames] count] > 0 && !listener) { 417 listener = [QNSListener alloc] init]; 418 listener.engine = this; 419 hasWifi = true; 420 } else { 421 hasWifi = false; 422 } 423 storeSession = NULL; 424 425 startNetworkChangeLoop(); 426} 427 428 429QString QCoreWlanEngine::getInterfaceFromId(const QString &id) 430{ 431 QMutexLocker locker(&mutex); 432 433 return scanThread->configurationInterface.value(id); 434} 435 436bool QCoreWlanEngine::hasIdentifier(const QString &id) 437{ 438 QMutexLocker locker(&mutex); 439 440 return scanThread->configurationInterface.contains(id); 441} 442 443void QCoreWlanEngine::connectToId(const QString &id) 444{ 445 QMutexLocker locker(&mutex); 446 QMacAutoReleasePool pool; 447 QString interfaceString = getInterfaceFromId(id); 448 449 CWInterface *wifiInterface = 450 [[CWWiFiClient sharedWiFiClient] interfaceWithName:interfaceString.toNSString()]; 451 452 if (wifiInterface.powerOn) { 453 NSError *err = nil; 454 QString wantedSsid; 455 QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id); 456 457 const QString idHash = QString::number(qHash(QLatin1String("corewlan:") + ptr->name)); 458 const QString idHash2 = QString::number(qHash(QLatin1String("corewlan:") + scanThread->getNetworkNameFromSsid(ptr->name))); 459 460 QString wantedNetwork; 461 for (auto i = scanThread->userProfiles.cbegin(), end = scanThread->userProfiles.cend(); i != end; ++i) { 462 wantedNetwork = i.key(); 463 const QString networkNameHash = QString::number(qHash(QLatin1String("corewlan:") + wantedNetwork)); 464 if (id == networkNameHash) { 465 wantedSsid = scanThread->getSsidFromNetworkName(wantedNetwork); 466 break; 467 } 468 } 469 470 NSSet *scanSet = [wifiInterface scanForNetworksWithName:wantedSsid.toNSString() error:&err]; 471 472 if(!err) { 473 for (CWNetwork *apNetwork in scanSet) { 474 NSData *ssidData = [apNetwork ssidData]; 475 bool result = false; 476 477 SecIdentityRef identity = 0; 478 // Check first whether we require IEEE 802.1X authentication for the wanted SSID 479 if (CWKeychainCopyWiFiEAPIdentity(kCWKeychainDomainSystem, ssidData, &identity) == errSecSuccess) { 480 NSString *username = nil; 481 NSString *password = nil; 482 if (CWKeychainFindWiFiEAPUsernameAndPassword(kCWKeychainDomainSystem, ssidData, &username, &password) == errSecSuccess) { 483 result = [wifiInterface associateToEnterpriseNetwork:apNetwork 484 identity:identity username:(NSString *)username password:(NSString *)password 485 error:&err]; 486 [username release]; 487 [password release]; 488 } 489 CFRelease(identity); 490 } else { 491 NSString *password = nil; 492 if (CWKeychainFindWiFiPassword(kCWKeychainDomainSystem, ssidData, &password) == errSecSuccess) { 493 result = [wifiInterface associateToNetwork:apNetwork password:(NSString *)password error:&err]; 494 [password release]; 495 } 496 } 497 498 if (!err) { 499 if (!result) { 500 emit connectionError(id, ConnectError); 501 } else { 502 return; 503 } 504 } else { 505 qDebug() <<"associate ERROR"<< QString::fromNSString([err localizedDescription ]); 506 } 507 } //end scan network 508 } else { 509 qDebug() <<"scan ERROR"<< QString::fromNSString([err localizedDescription ]); 510 } 511 emit connectionError(id, InterfaceLookupError); 512 } 513 514 locker.unlock(); 515 emit connectionError(id, InterfaceLookupError); 516} 517 518void QCoreWlanEngine::disconnectFromId(const QString &id) 519{ 520 QMutexLocker locker(&mutex); 521 522 QString interfaceString = getInterfaceFromId(id); 523 if (interfaceString.isEmpty()) { 524 locker.unlock(); 525 emit connectionError(id, DisconnectionError); 526 return; 527 } 528 QMacAutoReleasePool pool; 529 530 CWInterface *wifiInterface = 531 [[CWWiFiClient sharedWiFiClient] interfaceWithName:interfaceString.toNSString()]; 532 disconnectedInterfaceString = interfaceString; 533 534 [wifiInterface disassociate]; 535 536 QTimer::singleShot(1000, this,SLOT(checkDisconnect())); 537} 538 539void QCoreWlanEngine::checkDisconnect() 540{ 541 QMutexLocker locker(&mutex); 542 if (!disconnectedInterfaceString.isEmpty()) { 543 QMacAutoReleasePool pool; 544 545 CWInterface *wifiInterface = [[CWWiFiClient sharedWiFiClient] 546 interfaceWithName:disconnectedInterfaceString.toNSString()]; 547 548 const QString networkSsid = QString::fromNSString([wifiInterface ssid]); 549 if (!networkSsid.isEmpty()) { 550 const QString id = QString::number(qHash(QLatin1String("corewlan:") + networkSsid)); 551 locker.unlock(); 552 emit connectionError(id, DisconnectionError); 553 locker.relock(); 554 } 555 disconnectedInterfaceString.clear(); 556 } 557} 558 559void QCoreWlanEngine::requestUpdate() 560{ 561 scanThread->getUserConfigurations(); 562 doRequestUpdate(); 563} 564 565void QCoreWlanEngine::doRequestUpdate() 566{ 567 QMutexLocker locker(&mutex); 568 569 QMacAutoReleasePool pool; 570 571 NSArray<NSString *> *wifiInterfaces = [CWWiFiClient interfaceNames]; 572 for (NSString *ifName in wifiInterfaces) { 573 scanThread->interfaceName = QString::fromNSString(ifName); 574 scanThread->start(); 575 } 576 locker.unlock(); 577 if ([wifiInterfaces count] == 0) 578 networksChanged(); 579} 580 581bool QCoreWlanEngine::isWifiReady(const QString &wifiDeviceName) 582{ 583 QMutexLocker locker(&mutex); 584 bool haswifi = false; 585 if(hasWifi) { 586 QMacAutoReleasePool pool; 587 CWInterface *defaultInterface = [[CWWiFiClient sharedWiFiClient] 588 interfaceWithName:wifiDeviceName.toNSString()]; 589 if (defaultInterface.powerOn) { 590 haswifi = true; 591 } 592 } 593 return haswifi; 594} 595 596 597QNetworkSession::State QCoreWlanEngine::sessionStateForId(const QString &id) 598{ 599 QMutexLocker locker(&mutex); 600 QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id); 601 602 if (!ptr) 603 return QNetworkSession::Invalid; 604 605 if (!ptr->isValid) { 606 return QNetworkSession::Invalid; 607 } else if ((ptr->state & QNetworkConfiguration::Active) == QNetworkConfiguration::Active) { 608 return QNetworkSession::Connected; 609 } else if ((ptr->state & QNetworkConfiguration::Discovered) == 610 QNetworkConfiguration::Discovered) { 611 return QNetworkSession::Disconnected; 612 } else if ((ptr->state & QNetworkConfiguration::Defined) == QNetworkConfiguration::Defined) { 613 return QNetworkSession::NotAvailable; 614 } else if ((ptr->state & QNetworkConfiguration::Undefined) == 615 QNetworkConfiguration::Undefined) { 616 return QNetworkSession::NotAvailable; 617 } 618 619 return QNetworkSession::Invalid; 620} 621 622QNetworkConfigurationManager::Capabilities QCoreWlanEngine::capabilities() const 623{ 624 return QNetworkConfigurationManager::ForcedRoaming; 625} 626 627void QCoreWlanEngine::startNetworkChangeLoop() 628{ 629 630 SCDynamicStoreContext dynStoreContext = { 0, this/*(void *)storeSession*/, NULL, NULL, NULL }; 631 storeSession = SCDynamicStoreCreate(NULL, 632 CFSTR("networkChangeCallback"), 633 networkChangeCallback, 634 &dynStoreContext); 635 if (!storeSession ) { 636 qWarning() << "could not open dynamic store: error:" << SCErrorString(SCError()); 637 return; 638 } 639 640 CFMutableArrayRef notificationKeys; 641 notificationKeys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 642 CFMutableArrayRef patternsArray; 643 patternsArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 644 645 CFStringRef storeKey; 646 storeKey = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, 647 kSCDynamicStoreDomainState, 648 kSCEntNetIPv4); 649 CFArrayAppendValue(notificationKeys, storeKey); 650 CFRelease(storeKey); 651 652 storeKey = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, 653 kSCDynamicStoreDomainState, 654 kSCCompAnyRegex, 655 kSCEntNetIPv4); 656 CFArrayAppendValue(patternsArray, storeKey); 657 CFRelease(storeKey); 658 659 if (!SCDynamicStoreSetNotificationKeys(storeSession , notificationKeys, patternsArray)) { 660 qWarning() << "register notification error:"<< SCErrorString(SCError()); 661 CFRelease(storeSession ); 662 CFRelease(notificationKeys); 663 CFRelease(patternsArray); 664 return; 665 } 666 CFRelease(notificationKeys); 667 CFRelease(patternsArray); 668 669 runloopSource = SCDynamicStoreCreateRunLoopSource(NULL, storeSession , 0); 670 if (!runloopSource) { 671 qWarning() << "runloop source error:"<< SCErrorString(SCError()); 672 CFRelease(storeSession ); 673 return; 674 } 675 676 CFRunLoopAddSource(CFRunLoopGetCurrent(), runloopSource, kCFRunLoopDefaultMode); 677 return; 678} 679 680QNetworkSessionPrivate *QCoreWlanEngine::createSessionBackend() 681{ 682 return new QNetworkSessionPrivateImpl; 683} 684 685QNetworkConfigurationPrivatePointer QCoreWlanEngine::defaultConfiguration() 686{ 687 return QNetworkConfigurationPrivatePointer(); 688} 689 690bool QCoreWlanEngine::requiresPolling() const 691{ 692 return true; 693} 694 695void QCoreWlanEngine::networksChanged() 696{ 697 QMutexLocker locker(&mutex); 698 699 QStringList previous = accessPointConfigurations.keys(); 700 701 QList<QNetworkConfigurationPrivate *> foundConfigurations = scanThread->getConfigurations(); 702 while (!foundConfigurations.isEmpty()) { 703 QNetworkConfigurationPrivate *cpPriv = foundConfigurations.takeFirst(); 704 705 previous.removeAll(cpPriv->id); 706 707 if (accessPointConfigurations.contains(cpPriv->id)) { 708 QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(cpPriv->id); 709 710 bool changed = false; 711 712 ptr->mutex.lock(); 713 714 if (ptr->isValid != cpPriv->isValid) { 715 ptr->isValid = cpPriv->isValid; 716 changed = true; 717 } 718 719 if (ptr->name != cpPriv->name) { 720 ptr->name = cpPriv->name; 721 changed = true; 722 } 723 724 if (ptr->bearerType != cpPriv->bearerType) { 725 ptr->bearerType = cpPriv->bearerType; 726 changed = true; 727 } 728 729 if (ptr->state != cpPriv->state) { 730 ptr->state = cpPriv->state; 731 changed = true; 732 } 733 734 ptr->mutex.unlock(); 735 736 if (changed) { 737 locker.unlock(); 738 emit configurationChanged(ptr); 739 locker.relock(); 740 } 741 742 delete cpPriv; 743 } else { 744 QNetworkConfigurationPrivatePointer ptr(cpPriv); 745 746 accessPointConfigurations.insert(ptr->id, ptr); 747 748 locker.unlock(); 749 emit configurationAdded(ptr); 750 locker.relock(); 751 } 752 } 753 754 while (!previous.isEmpty()) { 755 QNetworkConfigurationPrivatePointer ptr = 756 accessPointConfigurations.take(previous.takeFirst()); 757 758 locker.unlock(); 759 emit configurationRemoved(ptr); 760 locker.relock(); 761 } 762 763 locker.unlock(); 764 emit updateCompleted(); 765 766} 767 768quint64 QCoreWlanEngine::bytesWritten(const QString &id) 769{ 770 QMutexLocker locker(&mutex); 771 const QString interfaceStr = getInterfaceFromId(id); 772 return getBytes(interfaceStr,false); 773} 774 775quint64 QCoreWlanEngine::bytesReceived(const QString &id) 776{ 777 QMutexLocker locker(&mutex); 778 const QString interfaceStr = getInterfaceFromId(id); 779 return getBytes(interfaceStr,true); 780} 781 782quint64 QCoreWlanEngine::startTime(const QString &identifier) 783{ 784 QMutexLocker locker(&mutex); 785 QMacAutoReleasePool pool; 786 quint64 timestamp = 0; 787 788 NSString *filePath = @"/Library/Preferences/SystemConfiguration/com.apple.airport.preferences.plist"; 789 NSDictionary* plistDict = [[[NSDictionary alloc] initWithContentsOfFile:filePath] autorelease]; 790 if(plistDict == nil) 791 return timestamp; 792 NSString *input = @"KnownNetworks"; 793 NSString *timeStampStr = @"_timeStamp"; 794 795 NSString *ssidStr = @"SSID_STR"; 796 797 for (id key in plistDict) { 798 if ([input isEqualToString:key]) { 799 800 NSDictionary *knownNetworksDict = [plistDict objectForKey:key]; 801 if(knownNetworksDict == nil) 802 return timestamp; 803 for (id networkKey in knownNetworksDict) { 804 bool isFound = false; 805 NSDictionary *itemDict = [knownNetworksDict objectForKey:networkKey]; 806 if(itemDict == nil) 807 return timestamp; 808 NSInteger dictSize = [itemDict count]; 809 id objects[dictSize]; 810 id keys[dictSize]; 811 812 [itemDict getObjects:objects andKeys:keys]; 813 bool ok = false; 814 for(int i = 0; i < dictSize; i++) { 815 if([ssidStr isEqualToString:keys[i]]) { 816 const QString ident = QString::number(qHash(QLatin1String("corewlan:") + QString::fromNSString(objects[i]))); 817 if(ident == identifier) { 818 ok = true; 819 } 820 } 821 if(ok && [timeStampStr isEqualToString:keys[i]]) { 822 timestamp = (quint64)[objects[i] timeIntervalSince1970]; 823 isFound = true; 824 break; 825 } 826 } 827 if(isFound) 828 break; 829 } 830 } 831 } 832 return timestamp; 833} 834 835quint64 QCoreWlanEngine::getBytes(const QString &interfaceName, bool b) 836{ 837 struct ifaddrs *ifAddressList, *ifAddress; 838 struct if_data *if_data; 839 840 quint64 bytes = 0; 841 ifAddressList = nil; 842 if(getifaddrs(&ifAddressList) == 0) { 843 for(ifAddress = ifAddressList; ifAddress; ifAddress = ifAddress->ifa_next) { 844 if(interfaceName == ifAddress->ifa_name) { 845 if_data = (struct if_data*)ifAddress->ifa_data; 846 if(b) { 847 bytes = if_data->ifi_ibytes; 848 break; 849 } else { 850 bytes = if_data->ifi_obytes; 851 break; 852 } 853 } 854 } 855 freeifaddrs(ifAddressList); 856 } 857 return bytes; 858} 859 860QT_END_NAMESPACE 861 862#endif 863