diff --git a/rtc_base/network.cc b/rtc_base/network.cc index 13a5ef86d4..8aabdcb7e6 100644 --- a/rtc_base/network.cc +++ b/rtc_base/network.cc @@ -806,6 +806,11 @@ bool BasicNetworkManager::IsIgnoredNetwork(const Network& network) const { } #endif + if (network_monitor_ && + !network_monitor_->IsAdapterAvailable(network.name())) { + return true; + } + // Ignore any networks with a 0.x.y.z IP if (network.prefix().family() == AF_INET) { return (network.prefix().v4AddressAsHostOrderInteger() < 0x01000000); diff --git a/rtc_base/network_monitor.h b/rtc_base/network_monitor.h index b57a20003f..1098219ee0 100644 --- a/rtc_base/network_monitor.h +++ b/rtc_base/network_monitor.h @@ -77,15 +77,34 @@ class NetworkMonitorInterface { // Implementations should call this method on the base when networks change, // and the base will fire SignalNetworksChanged on the right thread. + // TODO(deadbeef): This is an implementation detail of NetworkMonitorBase, + // it doesn't belong here. virtual void OnNetworksChanged() = 0; virtual AdapterType GetAdapterType(const std::string& interface_name) = 0; virtual AdapterType GetVpnUnderlyingAdapterType( const std::string& interface_name) = 0; + virtual NetworkPreference GetNetworkPreference( const std::string& interface_name) = 0; + + // Is this interface available to use? WebRTC shouldn't attempt to use it if + // this returns false. + // + // It's possible for this status to change, in which case + // SignalNetworksChanged will be fired. + // + // These specific use case this was added for was a phone with two SIM cards, + // where attempting to use all interfaces returned from getifaddrs caused the + // connection to be dropped. + virtual bool IsAdapterAvailable(const std::string& interface_name) { + return true; + } }; +// TODO(deadbeef): This class has marginal value, all it does is post a task +// to call SignalNetworksChanged on the worker thread. Should fold it into +// AndroidNetworkMonitor. class NetworkMonitorBase : public NetworkMonitorInterface, public MessageHandler, public sigslot::has_slots<> { diff --git a/rtc_base/network_unittest.cc b/rtc_base/network_unittest.cc index 42fb3d9dbb..fac8c254b5 100644 --- a/rtc_base/network_unittest.cc +++ b/rtc_base/network_unittest.cc @@ -12,9 +12,11 @@ #include +#include #include #include +#include "absl/algorithm/container.h" #include "absl/strings/match.h" #include "rtc_base/checks.h" #include "rtc_base/net_helpers.h" @@ -61,8 +63,18 @@ class FakeNetworkMonitor : public NetworkMonitorBase { return NetworkPreference::NEUTRAL; } + bool IsAdapterAvailable(const std::string& if_name) override { + return absl::c_count(unavailable_adapters_, if_name) == 0; + } + + // Used to test IsAdapterAvailable. + void set_unavailable_adapters(std::vector unavailable_adapters) { + unavailable_adapters_ = unavailable_adapters; + } + private: bool started_ = false; + std::vector unavailable_adapters_; }; class FakeNetworkMonitorFactory : public NetworkMonitorFactory { @@ -914,6 +926,41 @@ TEST_F(NetworkTest, TestGetAdapterTypeFromNameMatching) { ReleaseIfAddrs(addr_list); #endif } + +// Test that an adapter won't be included in the network list if there's a +// network monitor that says it's unavailable. +TEST_F(NetworkTest, TestNetworkMonitorIsAdapterAvailable) { + char if_name1[20] = "pdp_ip0"; + char if_name2[20] = "pdp_ip1"; + ifaddrs* list = nullptr; + list = AddIpv6Address(list, if_name1, "1000:2000:3000:4000:0:0:0:1", + "FFFF:FFFF:FFFF:FFFF::", 0); + list = AddIpv6Address(list, if_name2, "1000:2000:3000:4000:0:0:0:2", + "FFFF:FFFF:FFFF:FFFF::", 0); + NetworkManager::NetworkList result; + + // Sanity check that both interfaces are included by default. + FakeNetworkMonitorFactory factory; + BasicNetworkManager manager(&factory); + manager.StartUpdating(); + CallConvertIfAddrs(manager, list, /*include_ignored=*/false, &result); + EXPECT_EQ(2u, result.size()); + bool changed; + // This ensures we release the objects created in CallConvertIfAddrs. + MergeNetworkList(manager, result, &changed); + result.clear(); + + // Now simulate one interface being unavailable. + FakeNetworkMonitor* network_monitor = GetNetworkMonitor(manager); + network_monitor->set_unavailable_adapters({if_name1}); + CallConvertIfAddrs(manager, list, /*include_ignored=*/false, &result); + EXPECT_EQ(1u, result.size()); + EXPECT_EQ(if_name2, result[0]->name()); + + MergeNetworkList(manager, result, &changed); + ReleaseIfAddrs(list); +} + #endif // defined(WEBRTC_POSIX) // Test MergeNetworkList successfully combines all IPs for the same diff --git a/sdk/BUILD.gn b/sdk/BUILD.gn index 6092d96e02..729271594e 100644 --- a/sdk/BUILD.gn +++ b/sdk/BUILD.gn @@ -337,6 +337,35 @@ if (is_ios || is_mac) { "../rtc_base:rtc_base_approved", ] } + + rtc_source_set("network_monitor_observer") { + visibility = [ ":*" ] + + sources = [ "objc/native/src/network_monitor_observer.h" ] + + deps = [ "../rtc_base" ] + } + + rtc_library("network_monitor_objc") { + visibility = [ "*" ] + + sources = [ + "objc/components/network/RTCNetworkMonitor+Private.h", + "objc/components/network/RTCNetworkMonitor.h", + "objc/components/network/RTCNetworkMonitor.mm", + ] + + configs += [ ":used_from_extension" ] + + frameworks = [ "Network.framework" ] + + deps = [ + ":base_objc", + ":helpers_objc", + ":network_monitor_observer", + "../rtc_base/system:gcd_helpers", + ] + } } rtc_library("videosource_objc") { @@ -1266,6 +1295,7 @@ if (is_ios || is_mac) { "objc/components/audio/RTCAudioSessionConfiguration.h", "objc/components/capturer/RTCCameraVideoCapturer.h", "objc/components/capturer/RTCFileVideoCapturer.h", + "objc/components/network/RTCNetworkMonitor.h", "objc/components/renderer/metal/RTCMTLVideoView.h", "objc/components/renderer/opengl/RTCEAGLVideoView.h", "objc/components/renderer/opengl/RTCVideoViewShading.h", @@ -1540,6 +1570,8 @@ if (is_ios || is_mac) { visibility = [ "*" ] allow_poison = [ "audio_codecs" ] # TODO(bugs.webrtc.org/8396): Remove. sources = [ + "objc/native/api/network_monitor_factory.h", + "objc/native/api/network_monitor_factory.mm", "objc/native/api/video_capturer.h", "objc/native/api/video_capturer.mm", "objc/native/api/video_decoder_factory.h", @@ -1571,9 +1603,30 @@ if (is_ios || is_mac) { "../common_video", "../rtc_base", ] + if (is_ios) { + deps += [ ":native_network_monitor" ] + } absl_deps = [ "//third_party/abseil-cpp/absl/memory" ] } + if (is_ios) { + rtc_library("native_network_monitor") { + visibility = [ "*" ] + + sources = [ + "objc/native/src/objc_network_monitor.h", + "objc/native/src/objc_network_monitor.mm", + ] + + deps = [ + ":network_monitor_objc", + ":network_monitor_observer", + "../rtc_base", + "../rtc_base/synchronization:sequence_checker", + ] + } + } + rtc_library("native_video") { sources = [ "objc/native/src/objc_frame_buffer.h", diff --git a/sdk/objc/api/peerconnection/RTCFieldTrials.h b/sdk/objc/api/peerconnection/RTCFieldTrials.h index 61443e8bb2..7477ad020f 100644 --- a/sdk/objc/api/peerconnection/RTCFieldTrials.h +++ b/sdk/objc/api/peerconnection/RTCFieldTrials.h @@ -21,6 +21,7 @@ RTC_EXTERN NSString * const kRTCFieldTrialFlexFec03AdvertisedKey; RTC_EXTERN NSString * const kRTCFieldTrialFlexFec03Key; RTC_EXTERN NSString * const kRTCFieldTrialH264HighProfileKey; RTC_EXTERN NSString * const kRTCFieldTrialMinimizeResamplingOnMobileKey; +RTC_EXTERN NSString *const kRTCFieldTrialUseNWPathMonitor; /** The valid value for field trials above. */ RTC_EXTERN NSString * const kRTCFieldTrialEnabledValue; diff --git a/sdk/objc/api/peerconnection/RTCFieldTrials.mm b/sdk/objc/api/peerconnection/RTCFieldTrials.mm index 4a30db2f70..c52dfe4e45 100644 --- a/sdk/objc/api/peerconnection/RTCFieldTrials.mm +++ b/sdk/objc/api/peerconnection/RTCFieldTrials.mm @@ -25,6 +25,7 @@ NSString * const kRTCFieldTrialFlexFec03Key = @"WebRTC-FlexFEC-03"; NSString * const kRTCFieldTrialH264HighProfileKey = @"WebRTC-H264HighProfile"; NSString * const kRTCFieldTrialMinimizeResamplingOnMobileKey = @"WebRTC-Audio-MinimizeResamplingOnMobile"; +NSString *const kRTCFieldTrialUseNWPathMonitor = @"WebRTC-Network-UseNWPathMonitor"; NSString * const kRTCFieldTrialEnabledValue = @"Enabled"; static std::unique_ptr gFieldTrialInitString; diff --git a/sdk/objc/api/peerconnection/RTCPeerConnectionFactory.mm b/sdk/objc/api/peerconnection/RTCPeerConnectionFactory.mm index 4ce38dbd7f..3fa5159ec3 100644 --- a/sdk/objc/api/peerconnection/RTCPeerConnectionFactory.mm +++ b/sdk/objc/api/peerconnection/RTCPeerConnectionFactory.mm @@ -25,6 +25,9 @@ #import "base/RTCVideoDecoderFactory.h" #import "base/RTCVideoEncoderFactory.h" #import "helpers/NSString+StdString.h" +#include "sdk/objc/native/api/network_monitor_factory.h" +#include "system_wrappers/include/field_trial.h" + #ifndef HAVE_NO_MEDIA #import "components/video_codec/RTCVideoDecoderFactoryH264.h" #import "components/video_codec/RTCVideoEncoderFactoryH264.h" @@ -135,6 +138,9 @@ dependencies.network_thread = _networkThread.get(); dependencies.worker_thread = _workerThread.get(); dependencies.signaling_thread = _signalingThread.get(); + if (webrtc::field_trial::IsEnabled("WebRTC-Network-UseNWPathMonitor")) { + dependencies.network_monitor_factory = webrtc::CreateNetworkMonitorFactory(); + } _nativeFactory = webrtc::CreateModularPeerConnectionFactory(std::move(dependencies)); NSAssert(_nativeFactory, @"Failed to initialize PeerConnectionFactory!"); } @@ -179,6 +185,9 @@ dependencies.network_thread = _networkThread.get(); dependencies.worker_thread = _workerThread.get(); dependencies.signaling_thread = _signalingThread.get(); + if (webrtc::field_trial::IsEnabled("WebRTC-Network-UseNWPathMonitor")) { + dependencies.network_monitor_factory = webrtc::CreateNetworkMonitorFactory(); + } #ifndef HAVE_NO_MEDIA dependencies.task_queue_factory = webrtc::CreateDefaultTaskQueueFactory(); cricket::MediaEngineDependencies media_deps; diff --git a/sdk/objc/components/network/RTCNetworkMonitor+Private.h b/sdk/objc/components/network/RTCNetworkMonitor+Private.h new file mode 100644 index 0000000000..efb37bb63b --- /dev/null +++ b/sdk/objc/components/network/RTCNetworkMonitor+Private.h @@ -0,0 +1,23 @@ +/* + * 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.h" + +#include "sdk/objc/native/src/network_monitor_observer.h" + +@interface RTCNetworkMonitor () + +/** |observer| is a raw pointer and should be kept alive + * for this object's lifetime. + */ +- (instancetype)initWithObserver:(webrtc::NetworkMonitorObserver *)observer + NS_DESIGNATED_INITIALIZER; + +@end diff --git a/sdk/objc/components/network/RTCNetworkMonitor.h b/sdk/objc/components/network/RTCNetworkMonitor.h new file mode 100644 index 0000000000..21d22f5463 --- /dev/null +++ b/sdk/objc/components/network/RTCNetworkMonitor.h @@ -0,0 +1,24 @@ +/* + * 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 + +NS_ASSUME_NONNULL_BEGIN + +/** Listens for NWPathMonitor updates and forwards the results to a C++ + * observer. + */ +@interface RTCNetworkMonitor : NSObject + +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/sdk/objc/components/network/RTCNetworkMonitor.mm b/sdk/objc/components/network/RTCNetworkMonitor.mm new file mode 100644 index 0000000000..8ac7d3a0d2 --- /dev/null +++ b/sdk/objc/components/network/RTCNetworkMonitor.mm @@ -0,0 +1,109 @@ +/* + * 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 + +#import "base/RTCLogging.h" +#import "helpers/RTCDispatcher+Private.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); + if (self = [super init]) { + _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 *map = + new std::map(); + 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(name, adapterType)); + }); + strongSelf->_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)dealloc { + if (@available(iOS 12, *)) { + nw_path_monitor_cancel(_pathMonitor); + } +} + +@end diff --git a/sdk/objc/helpers/RTCDispatcher.h b/sdk/objc/helpers/RTCDispatcher.h index f8580f95fa..e148af6dea 100644 --- a/sdk/objc/helpers/RTCDispatcher.h +++ b/sdk/objc/helpers/RTCDispatcher.h @@ -20,6 +20,8 @@ typedef NS_ENUM(NSInteger, RTCDispatcherQueueType) { RTCDispatcherTypeCaptureSession, // Used for operations on AVAudioSession. RTCDispatcherTypeAudioSession, + // Used for operations on NWPathMonitor. + RTCDispatcherTypeNetworkMonitor, }; /** Dispatcher that asynchronously dispatches blocks to a specific diff --git a/sdk/objc/helpers/RTCDispatcher.m b/sdk/objc/helpers/RTCDispatcher.m index 2e83573adc..4df19bc297 100644 --- a/sdk/objc/helpers/RTCDispatcher.m +++ b/sdk/objc/helpers/RTCDispatcher.m @@ -12,6 +12,7 @@ static dispatch_queue_t kAudioSessionQueue = nil; static dispatch_queue_t kCaptureSessionQueue = nil; +static dispatch_queue_t kNetworkMonitorQueue = nil; @implementation RTC_OBJC_TYPE (RTCDispatcher) @@ -24,6 +25,8 @@ static dispatch_queue_t kCaptureSessionQueue = nil; kCaptureSessionQueue = dispatch_queue_create( "org.webrtc.RTCDispatcherCaptureSession", DISPATCH_QUEUE_SERIAL); + kNetworkMonitorQueue = + dispatch_queue_create("org.webrtc.RTCDispatcherNetworkMonitor", DISPATCH_QUEUE_SERIAL); }); } @@ -54,6 +57,8 @@ static dispatch_queue_t kCaptureSessionQueue = nil; return kCaptureSessionQueue; case RTCDispatcherTypeAudioSession: return kAudioSessionQueue; + case RTCDispatcherTypeNetworkMonitor: + return kNetworkMonitorQueue; } } diff --git a/sdk/objc/native/api/network_monitor_factory.h b/sdk/objc/native/api/network_monitor_factory.h new file mode 100644 index 0000000000..903c66893d --- /dev/null +++ b/sdk/objc/native/api/network_monitor_factory.h @@ -0,0 +1,24 @@ +/* + * 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. + */ + +#ifndef SDK_OBJC_NATIVE_API_NETWORK_MONITOR_FACTORY_H_ +#define SDK_OBJC_NATIVE_API_NETWORK_MONITOR_FACTORY_H_ + +#include + +#include "rtc_base/network_monitor_factory.h" + +namespace webrtc { + +std::unique_ptr CreateNetworkMonitorFactory(); + +} // namespace webrtc + +#endif // SDK_OBJC_NATIVE_API_NETWORK_MONITOR_FACTORY_H_ diff --git a/sdk/objc/native/api/network_monitor_factory.mm b/sdk/objc/native/api/network_monitor_factory.mm new file mode 100644 index 0000000000..de762a9a0f --- /dev/null +++ b/sdk/objc/native/api/network_monitor_factory.mm @@ -0,0 +1,30 @@ +/* + * 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. + */ + +#include "network_monitor_factory.h" + +#if defined(WEBRTC_IOS) +#include "sdk/objc/native/src/objc_network_monitor.h" +#endif + +#include "rtc_base/logging.h" + +namespace webrtc { + +std::unique_ptr CreateNetworkMonitorFactory() { + RTC_LOG(LS_INFO) << __FUNCTION__; +#if defined(WEBRTC_IOS) + return std::make_unique(); +#else + return nullptr; +#endif +} + +} diff --git a/sdk/objc/native/src/network_monitor_observer.h b/sdk/objc/native/src/network_monitor_observer.h new file mode 100644 index 0000000000..85fd3b992f --- /dev/null +++ b/sdk/objc/native/src/network_monitor_observer.h @@ -0,0 +1,39 @@ +/* + * 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. + */ + +#ifndef SDK_OBJC_NATIVE_SRC_NETWORK_MONITOR_OBSERVER_H_ +#define SDK_OBJC_NATIVE_SRC_NETWORK_MONITOR_OBSERVER_H_ + +#include +#include + +#include "rtc_base/network_constants.h" +#include "rtc_base/thread.h" + +namespace webrtc { + +// Observer interface for listening to NWPathMonitor updates. +class NetworkMonitorObserver { + public: + // Called when a path update occurs, on network monitor dispatch queue. + // + // |adapter_type_by_name| is a map from interface name (i.e. "pdp_ip0") to + // adapter type, for all available interfaces on the current path. If an + // interface name isn't present it can be assumed to be unavailable. + virtual void OnPathUpdate( + std::map adapter_type_by_name) = 0; + + protected: + virtual ~NetworkMonitorObserver() {} +}; + +} // namespace webrtc + +#endif // SDK_OBJC_NATIVE_SRC_AUDIO_AUDIO_SESSION_OBSERVER_H_ diff --git a/sdk/objc/native/src/objc_network_monitor.h b/sdk/objc/native/src/objc_network_monitor.h new file mode 100644 index 0000000000..cffe3a2f8f --- /dev/null +++ b/sdk/objc/native/src/objc_network_monitor.h @@ -0,0 +1,72 @@ +/* + * 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. + */ + +#ifndef SDK_OBJC_NATIVE_SRC_OBJC_NETWORK_MONITOR_H_ +#define SDK_OBJC_NATIVE_SRC_OBJC_NETWORK_MONITOR_H_ + +#include + +#include "sdk/objc/components/network/RTCNetworkMonitor+Private.h" +#include "sdk/objc/native/src/network_monitor_observer.h" + +#include "rtc_base/async_invoker.h" +#include "rtc_base/network_monitor.h" +#include "rtc_base/network_monitor_factory.h" +#include "rtc_base/synchronization/sequence_checker.h" +#include "rtc_base/thread.h" +#include "rtc_base/thread_annotations.h" + +namespace webrtc { + +class ObjCNetworkMonitorFactory : public rtc::NetworkMonitorFactory { + public: + ObjCNetworkMonitorFactory() = default; + ~ObjCNetworkMonitorFactory() override = default; + + rtc::NetworkMonitorInterface* CreateNetworkMonitor() override; +}; + +class ObjCNetworkMonitor : public rtc::NetworkMonitorInterface, + public NetworkMonitorObserver { + public: + ObjCNetworkMonitor() = default; + ~ObjCNetworkMonitor() override; + + void Start() override; + void Stop() override; + + // TODO(deadbeef): Remove this once it's been removed from + // NetworkMonitorInterface. + void OnNetworksChanged() override {} + + rtc::AdapterType GetAdapterType(const std::string& interface_name) override; + rtc::AdapterType GetVpnUnderlyingAdapterType( + const std::string& interface_name) override; + rtc::NetworkPreference GetNetworkPreference( + const std::string& interface_name) override; + bool IsAdapterAvailable(const std::string& interface_name) override; + + // NetworkMonitorObserver override. + // Fans out updates to observers on the correct thread. + void OnPathUpdate( + std::map adapter_type_by_name) override; + + private: + rtc::Thread* thread_ = nullptr; + bool started_ = false; + std::map adapter_type_by_name_ + RTC_GUARDED_BY(thread_); + rtc::AsyncInvoker invoker_; + RTCNetworkMonitor* network_monitor_ = nil; +}; + +} // namespace webrtc + +#endif // SDK_OBJC_NATIVE_SRC_OBJC_NETWORK_MONITOR_H_ diff --git a/sdk/objc/native/src/objc_network_monitor.mm b/sdk/objc/native/src/objc_network_monitor.mm new file mode 100644 index 0000000000..e0e50ed1c8 --- /dev/null +++ b/sdk/objc/native/src/objc_network_monitor.mm @@ -0,0 +1,86 @@ +/* + * 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. + */ + +#include "sdk/objc/native/src/objc_network_monitor.h" + +#include + +#include "rtc_base/logging.h" + +namespace webrtc { + +rtc::NetworkMonitorInterface* ObjCNetworkMonitorFactory::CreateNetworkMonitor() { + return new ObjCNetworkMonitor(); +} + +ObjCNetworkMonitor::~ObjCNetworkMonitor() { + network_monitor_ = nil; +} + +void ObjCNetworkMonitor::Start() { + if (started_) { + return; + } + thread_ = rtc::Thread::Current(); + RTC_DCHECK_RUN_ON(thread_); + network_monitor_ = [[RTCNetworkMonitor alloc] initWithObserver:this]; + if (network_monitor_ == nil) { + RTC_LOG(LS_WARNING) << "Failed to create RTCNetworkMonitor; not available on this OS?"; + } + started_ = true; +} + +void ObjCNetworkMonitor::Stop() { + RTC_DCHECK_RUN_ON(thread_); + if (!started_) { + return; + } + network_monitor_ = nil; + started_ = false; +} + +rtc::AdapterType ObjCNetworkMonitor::GetAdapterType(const std::string& interface_name) { + RTC_DCHECK_RUN_ON(thread_); + if (adapter_type_by_name_.find(interface_name) == adapter_type_by_name_.end()) { + return rtc::ADAPTER_TYPE_UNKNOWN; + } + return adapter_type_by_name_.at(interface_name); +} + +rtc::AdapterType ObjCNetworkMonitor::GetVpnUnderlyingAdapterType( + const std::string& interface_name) { + return rtc::ADAPTER_TYPE_UNKNOWN; +} + +rtc::NetworkPreference ObjCNetworkMonitor::GetNetworkPreference(const std::string& interface_name) { + return rtc::NetworkPreference::NEUTRAL; +} + +bool ObjCNetworkMonitor::IsAdapterAvailable(const std::string& interface_name) { + RTC_DCHECK_RUN_ON(thread_); + if (adapter_type_by_name_.empty()) { + // If we have no path update, assume everything's available, because it's + // preferable for WebRTC to try all interfaces rather than none at all. + return true; + } + return adapter_type_by_name_.find(interface_name) != adapter_type_by_name_.end(); +} + +void ObjCNetworkMonitor::OnPathUpdate( + std::map adapter_type_by_name) { + RTC_DCHECK(network_monitor_ != nil); + invoker_.AsyncInvoke(RTC_FROM_HERE, thread_, [this, adapter_type_by_name] { + RTC_DCHECK_RUN_ON(thread_); + adapter_type_by_name_ = adapter_type_by_name; + SignalNetworksChanged(); + }); +} + +} // namespace webrtc