1/* 2 * Copyright 2020 The WebRTC Project Authors. All rights reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11#import "RTCNetworkMonitor+Private.h" 12 13#import <Network/Network.h> 14 15#import "base/RTCLogging.h" 16#import "helpers/RTCDispatcher+Private.h" 17 18#include "rtc_base/string_utils.h" 19 20namespace { 21 22rtc::AdapterType AdapterTypeFromInterfaceType(nw_interface_type_t interfaceType) { 23 rtc::AdapterType adapterType = rtc::ADAPTER_TYPE_UNKNOWN; 24 switch (interfaceType) { 25 case nw_interface_type_other: 26 adapterType = rtc::ADAPTER_TYPE_UNKNOWN; 27 break; 28 case nw_interface_type_wifi: 29 adapterType = rtc::ADAPTER_TYPE_WIFI; 30 break; 31 case nw_interface_type_cellular: 32 adapterType = rtc::ADAPTER_TYPE_CELLULAR; 33 break; 34 case nw_interface_type_wired: 35 adapterType = rtc::ADAPTER_TYPE_ETHERNET; 36 break; 37 case nw_interface_type_loopback: 38 adapterType = rtc::ADAPTER_TYPE_LOOPBACK; 39 break; 40 default: 41 adapterType = rtc::ADAPTER_TYPE_UNKNOWN; 42 break; 43 } 44 return adapterType; 45} 46 47} // namespace 48 49@implementation RTCNetworkMonitor { 50 webrtc::NetworkMonitorObserver *_observer; 51 nw_path_monitor_t _pathMonitor; 52 dispatch_queue_t _monitorQueue; 53} 54 55- (instancetype)initWithObserver:(webrtc::NetworkMonitorObserver *)observer { 56 RTC_DCHECK(observer); 57 if (self = [super init]) { 58 _observer = observer; 59 if (@available(iOS 12, *)) { 60 _pathMonitor = nw_path_monitor_create(); 61 if (_pathMonitor == nil) { 62 RTCLog(@"nw_path_monitor_create failed."); 63 return nil; 64 } 65 RTCLog(@"NW path monitor created."); 66 __weak RTCNetworkMonitor *weakSelf = self; 67 nw_path_monitor_set_update_handler(_pathMonitor, ^(nw_path_t path) { 68 if (weakSelf == nil) { 69 return; 70 } 71 RTCNetworkMonitor *strongSelf = weakSelf; 72 RTCLog(@"NW path monitor: updated."); 73 nw_path_status_t status = nw_path_get_status(path); 74 if (status == nw_path_status_invalid) { 75 RTCLog(@"NW path monitor status: invalid."); 76 } else if (status == nw_path_status_unsatisfied) { 77 RTCLog(@"NW path monitor status: unsatisfied."); 78 } else if (status == nw_path_status_satisfied) { 79 RTCLog(@"NW path monitor status: satisfied."); 80 } else if (status == nw_path_status_satisfiable) { 81 RTCLog(@"NW path monitor status: satisfiable."); 82 } 83 std::map<std::string, rtc::AdapterType, rtc::AbslStringViewCmp> *map = 84 new std::map<std::string, rtc::AdapterType, rtc::AbslStringViewCmp>(); 85 nw_path_enumerate_interfaces( 86 path, (nw_path_enumerate_interfaces_block_t) ^ (nw_interface_t interface) { 87 const char *name = nw_interface_get_name(interface); 88 nw_interface_type_t interfaceType = nw_interface_get_type(interface); 89 RTCLog(@"NW path monitor available interface: %s", name); 90 rtc::AdapterType adapterType = AdapterTypeFromInterfaceType(interfaceType); 91 map->insert(std::pair<std::string, rtc::AdapterType>(name, adapterType)); 92 }); 93 @synchronized(strongSelf) { 94 webrtc::NetworkMonitorObserver *observer = strongSelf->_observer; 95 if (observer) { 96 observer->OnPathUpdate(std::move(*map)); 97 } 98 } 99 delete map; 100 }); 101 nw_path_monitor_set_queue( 102 _pathMonitor, 103 [RTC_OBJC_TYPE(RTCDispatcher) dispatchQueueForType:RTCDispatcherTypeNetworkMonitor]); 104 nw_path_monitor_start(_pathMonitor); 105 } 106 } 107 return self; 108} 109 110- (void)cancel { 111 if (@available(iOS 12, *)) { 112 nw_path_monitor_cancel(_pathMonitor); 113 } 114} 115- (void)stop { 116 [self cancel]; 117 @synchronized(self) { 118 _observer = nil; 119 } 120} 121 122- (void)dealloc { 123 [self cancel]; 124} 125 126@end 127