Files
amnezia-client/client/platforms/macos/macosnetworkwatcher.mm
T

218 lines
6.7 KiB
Plaintext
Raw Normal View History

2021-10-23 04:26:47 -07:00
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "macosnetworkwatcher.h"
#include "leakdetector.h"
#include "logger.h"
#import <CoreWLAN/CoreWLAN.h>
2023-07-15 14:19:48 -07:00
#import <Network/Network.h>
2021-10-23 04:26:47 -07:00
namespace {
2023-07-15 14:19:48 -07:00
Logger logger("MacOSNetworkWatcher");
2021-10-23 04:26:47 -07:00
}
@interface MacOSNetworkWatcherDelegate : NSObject <CWEventDelegate> {
MacOSNetworkWatcher* m_watcher;
}
@end
@implementation MacOSNetworkWatcherDelegate
- (id)initWithObject:(MacOSNetworkWatcher*)watcher {
self = [super init];
if (self) {
m_watcher = watcher;
}
return self;
}
- (void)bssidDidChangeForWiFiInterfaceWithName:(NSString*)interfaceName {
logger.debug() << "BSSID changed!" << QString::fromNSString(interfaceName);
if (m_watcher) {
m_watcher->checkInterface();
}
}
@end
2025-04-03 22:12:54 +03:00
void PowerNotificationsListener::registerForNotifications()
{
rootPowerDomain = IORegisterForSystemPower(this, &notifyPortRef, sleepWakeupCallBack, &notifierObj);
if (rootPowerDomain == IO_OBJECT_NULL) {
logger.debug() << "Failed to register for system power notifications!";
return;
}
logger.debug() << "IORegisterForSystemPower OK! Root port:" << rootPowerDomain;
// add the notification port to the application runloop
CFRunLoopAddSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(notifyPortRef), kCFRunLoopCommonModes);
}
static void PowerNotificationsListener::sleepWakeupCallBack(void *refParam, io_service_t service, natural_t messageType, void *messageArgument)
{
Q_UNUSED(service)
auto listener = static_cast<PowerNotificationsListener *>(refParam);
switch (messageType) {
case kIOMessageCanSystemSleep:
/* Idle sleep is about to kick in. This message will not be sent for forced sleep.
* Applications have a chance to prevent sleep by calling IOCancelPowerChange.
* Most applications should not prevent idle sleep. Power Management waits up to
* 30 seconds for you to either allow or deny idle sleep. If you dont acknowledge
* this power change by calling either IOAllowPowerChange or IOCancelPowerChange,
* the system will wait 30 seconds then go to sleep.
*/
logger.debug() << "System power message: can system sleep?";
// Uncomment to cancel idle sleep
// IOCancelPowerChange(thiz->rootPowerDomain, reinterpret_cast<long>(messageArgument));
// Allow idle sleep
IOAllowPowerChange(listener->rootPowerDomain, reinterpret_cast<long>(messageArgument));
break;
case kIOMessageSystemWillNotSleep:
/* Announces that the system has retracted a previous attempt to sleep; it
* follows `kIOMessageCanSystemSleep`.
*/
logger.debug() << "System power message: system will NOT sleep.";
break;
case kIOMessageSystemWillSleep:
/* The system WILL go to sleep. If you do not call IOAllowPowerChange or
* IOCancelPowerChange to acknowledge this message, sleep will be delayed by
* 30 seconds.
*
* NOTE: If you call IOCancelPowerChange to deny sleep it returns kIOReturnSuccess,
* however the system WILL still go to sleep.
*/
logger.debug() << "System power message: system WILL sleep.";
IOAllowPowerChange(listener->rootPowerDomain, reinterpret_cast<long>(messageArgument));
break;
case kIOMessageSystemWillPowerOn:
/* Announces that the system is beginning to power the device tree; most devices
* are still unavailable at this point.
*/
/* From the documentation:
*
* - kIOMessageSystemWillPowerOn is delivered at early wakeup time, before most hardware
* has been powered on. Be aware that any attempts to access disk, network, the display,
* etc. may result in errors or blocking your process until those resources become
* available.
*
* So we do NOT log this event.
*/
break;
case kIOMessageSystemHasPoweredOn:
/* Announces that the system and its devices have woken up. */
logger.debug() << "System power message: system has powered on.";
break;
default:
logger.debug() << "System power message: other event: " << messageType;
/* Not a system sleep and wake notification. */
break;
}
}
2023-07-15 14:19:48 -07:00
MacOSNetworkWatcher::MacOSNetworkWatcher(QObject* parent) : IOSNetworkWatcher(parent) {
MZ_COUNT_CTOR(MacOSNetworkWatcher);
2021-10-23 04:26:47 -07:00
}
MacOSNetworkWatcher::~MacOSNetworkWatcher() {
2023-07-15 14:19:48 -07:00
MZ_COUNT_DTOR(MacOSNetworkWatcher);
2021-10-23 04:26:47 -07:00
if (m_delegate) {
CWWiFiClient* client = CWWiFiClient.sharedWiFiClient;
if (!client) {
logger.debug() << "Unable to retrieve the CWWiFiClient shared instance";
return;
}
[client stopMonitoringAllEventsAndReturnError:nullptr];
[static_cast<MacOSNetworkWatcherDelegate*>(m_delegate) dealloc];
m_delegate = nullptr;
}
}
void MacOSNetworkWatcher::start() {
NetworkWatcherImpl::start();
checkInterface();
if (m_delegate) {
logger.debug() << "Delegate already registered";
return;
}
2025-04-03 22:12:54 +03:00
m_powerlistener.registerForNotifications();
2021-10-23 04:26:47 -07:00
CWWiFiClient* client = CWWiFiClient.sharedWiFiClient;
if (!client) {
logger.error() << "Unable to retrieve the CWWiFiClient shared instance";
return;
}
logger.debug() << "Registering delegate";
m_delegate = [[MacOSNetworkWatcherDelegate alloc] initWithObject:this];
[client setDelegate:static_cast<MacOSNetworkWatcherDelegate*>(m_delegate)];
[client startMonitoringEventWithType:CWEventTypeBSSIDDidChange error:nullptr];
}
void MacOSNetworkWatcher::checkInterface() {
logger.debug() << "Checking interface";
if (!isActive()) {
logger.debug() << "Feature disabled";
return;
}
CWWiFiClient* client = CWWiFiClient.sharedWiFiClient;
if (!client) {
logger.debug() << "Unable to retrieve the CWWiFiClient shared instance";
return;
}
CWInterface* interface = [client interface];
if (!interface) {
logger.debug() << "No default wifi interface";
return;
}
if (![interface powerOn]) {
logger.debug() << "The interface is off";
return;
}
NSString* ssidNS = [interface ssid];
if (!ssidNS) {
logger.debug() << "WiFi is not in used";
return;
}
QString ssid = QString::fromNSString(ssidNS);
if (ssid.isEmpty()) {
logger.debug() << "WiFi doesn't have a valid SSID";
return;
}
CWSecurity security = [interface security];
if (security == kCWSecurityNone || security == kCWSecurityWEP) {
logger.debug() << "Unsecured network found!";
emit unsecuredNetwork(ssid, ssid);
return;
}
logger.debug() << "Secure WiFi interface";
}
2023-07-15 14:19:48 -07:00