blob: 73c5c1050362a6bf03adf5620e7362deadf5c582 [file] [log] [blame]
/*
* Copyright 2020 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#import "RTCNetworkMonitor+Private.h"
#import <Network/Network.h>
#import "base/RTCLogging.h"
#import "helpers/RTCDispatcher+Private.h"
#include "rtc_base/string_utils.h"
namespace {
rtc::AdapterType AdapterTypeFromInterfaceType(nw_interface_type_t interfaceType) {
rtc::AdapterType adapterType = rtc::ADAPTER_TYPE_UNKNOWN;
switch (interfaceType) {
case nw_interface_type_other:
adapterType = rtc::ADAPTER_TYPE_UNKNOWN;
break;
case nw_interface_type_wifi:
adapterType = rtc::ADAPTER_TYPE_WIFI;
break;
case nw_interface_type_cellular:
adapterType = rtc::ADAPTER_TYPE_CELLULAR;
break;
case nw_interface_type_wired:
adapterType = rtc::ADAPTER_TYPE_ETHERNET;
break;
case nw_interface_type_loopback:
adapterType = rtc::ADAPTER_TYPE_LOOPBACK;
break;
default:
adapterType = rtc::ADAPTER_TYPE_UNKNOWN;
break;
}
return adapterType;
}
} // namespace
@implementation RTCNetworkMonitor {
webrtc::NetworkMonitorObserver *_observer;
nw_path_monitor_t _pathMonitor;
dispatch_queue_t _monitorQueue;
}
- (instancetype)initWithObserver:(webrtc::NetworkMonitorObserver *)observer {
RTC_DCHECK(observer);
self = [super init];
if (self) {
_observer = observer;
if (@available(iOS 12, *)) {
_pathMonitor = nw_path_monitor_create();
if (_pathMonitor == nil) {
RTCLog(@"nw_path_monitor_create failed.");
return nil;
}
RTCLog(@"NW path monitor created.");
__weak RTCNetworkMonitor *weakSelf = self;
nw_path_monitor_set_update_handler(_pathMonitor, ^(nw_path_t path) {
if (weakSelf == nil) {
return;
}
RTCNetworkMonitor *strongSelf = weakSelf;
RTCLog(@"NW path monitor: updated.");
nw_path_status_t status = nw_path_get_status(path);
if (status == nw_path_status_invalid) {
RTCLog(@"NW path monitor status: invalid.");
} else if (status == nw_path_status_unsatisfied) {
RTCLog(@"NW path monitor status: unsatisfied.");
} else if (status == nw_path_status_satisfied) {
RTCLog(@"NW path monitor status: satisfied.");
} else if (status == nw_path_status_satisfiable) {
RTCLog(@"NW path monitor status: satisfiable.");
}
std::map<std::string, rtc::AdapterType, rtc::AbslStringViewCmp> *map =
new std::map<std::string, rtc::AdapterType, rtc::AbslStringViewCmp>();
nw_path_enumerate_interfaces(
path, (nw_path_enumerate_interfaces_block_t) ^ (nw_interface_t interface) {
const char *name = nw_interface_get_name(interface);
nw_interface_type_t interfaceType = nw_interface_get_type(interface);
RTCLog(@"NW path monitor available interface: %s", name);
rtc::AdapterType adapterType = AdapterTypeFromInterfaceType(interfaceType);
map->insert(std::pair<std::string, rtc::AdapterType>(name, adapterType));
return true;
});
@synchronized(strongSelf) {
webrtc::NetworkMonitorObserver *observer = strongSelf->_observer;
if (observer) {
observer->OnPathUpdate(std::move(*map));
}
}
delete map;
});
nw_path_monitor_set_queue(
_pathMonitor,
[RTC_OBJC_TYPE(RTCDispatcher) dispatchQueueForType:RTCDispatcherTypeNetworkMonitor]);
nw_path_monitor_start(_pathMonitor);
}
}
return self;
}
- (void)cancel {
if (@available(iOS 12, *)) {
nw_path_monitor_cancel(_pathMonitor);
}
}
- (void)stop {
[self cancel];
@synchronized(self) {
_observer = nil;
}
}
- (void)dealloc {
[self cancel];
}
@end