diff --git a/rtc_base/network.cc b/rtc_base/network.cc index 454a7780ec..6daa7c38d9 100644 --- a/rtc_base/network.cc +++ b/rtc_base/network.cc @@ -111,6 +111,24 @@ std::string AdapterTypeToString(AdapterType type) { } } +uint16_t ComputeNetworkCostByType(int type) { + switch (type) { + case rtc::ADAPTER_TYPE_ETHERNET: + case rtc::ADAPTER_TYPE_LOOPBACK: + return kNetworkCostMin; + case rtc::ADAPTER_TYPE_WIFI: + return kNetworkCostLow; + case rtc::ADAPTER_TYPE_CELLULAR: + return kNetworkCostHigh; + case rtc::ADAPTER_TYPE_VPN: + // The cost of a VPN should be computed using its underlying network type. + RTC_NOTREACHED(); + return kNetworkCostUnknown; + default: + return kNetworkCostUnknown; + } +} + #if !defined(__native_client__) bool IsIgnoredIPv6(const InterfaceAddress& ip) { if (ip.family() != AF_INET6) { @@ -476,6 +494,7 @@ void BasicNetworkManager::ConvertIfAddrs(struct ifaddrs* interfaces, } AdapterType adapter_type = ADAPTER_TYPE_UNKNOWN; + AdapterType vpn_underlying_adapter_type = ADAPTER_TYPE_UNKNOWN; if (cursor->ifa_flags & IFF_LOOPBACK) { adapter_type = ADAPTER_TYPE_LOOPBACK; } else { @@ -488,6 +507,11 @@ void BasicNetworkManager::ConvertIfAddrs(struct ifaddrs* interfaces, adapter_type = GetAdapterTypeFromName(cursor->ifa_name); } } + + if (adapter_type == ADAPTER_TYPE_VPN && network_monitor_) { + vpn_underlying_adapter_type = + network_monitor_->GetVpnUnderlyingAdapterType(cursor->ifa_name); + } int prefix_length = CountIPMaskBits(mask); prefix = TruncateIP(ip, prefix_length); std::string key = MakeNetworkKey(std::string(cursor->ifa_name), @@ -502,6 +526,7 @@ void BasicNetworkManager::ConvertIfAddrs(struct ifaddrs* interfaces, network->set_scope_id(scope_id); network->AddIP(ip); network->set_ignored(IsIgnoredNetwork(*network)); + network->set_underlying_type_for_vpn(vpn_underlying_adapter_type); if (include_ignored || !network->ignored()) { current_networks[key] = network.get(); networks->push_back(network.release()); @@ -511,6 +536,8 @@ void BasicNetworkManager::ConvertIfAddrs(struct ifaddrs* interfaces, existing_network->AddIP(ip); if (adapter_type != ADAPTER_TYPE_UNKNOWN) { existing_network->set_type(adapter_type); + existing_network->set_underlying_type_for_vpn( + vpn_underlying_adapter_type); } } } @@ -971,13 +998,22 @@ IPAddress Network::GetBestIP() const { return static_cast(selected_ip); } +uint16_t Network::GetCost() const { + AdapterType type = IsVpn() ? underlying_type_for_vpn_ : type_; + return ComputeNetworkCostByType(type); +} + std::string Network::ToString() const { std::stringstream ss; // Print out the first space-terminated token of the network desc, plus // the IP address. - ss << "Net[" << description_.substr(0, description_.find(' ')) - << ":" << prefix_.ToSensitiveString() << "/" << prefix_length_ - << ":" << AdapterTypeToString(type_) << "]"; + ss << "Net[" << description_.substr(0, description_.find(' ')) << ":" + << prefix_.ToSensitiveString() << "/" << prefix_length_ << ":" + << AdapterTypeToString(type_); + if (IsVpn()) { + ss << "/" << AdapterTypeToString(underlying_type_for_vpn_); + } + ss << "]"; return ss.str(); } diff --git a/rtc_base/network.h b/rtc_base/network.h index 2b0f377a3f..49f500c297 100644 --- a/rtc_base/network.h +++ b/rtc_base/network.h @@ -293,7 +293,7 @@ class Network { AdapterType type); Network(const Network&); ~Network(); - + // This signal is fired whenever type() or underlying_type_for_vpn() changes. sigslot::signal1 SignalTypeChanged; const DefaultLocalAddressProvider* default_local_address_provider() { @@ -367,28 +367,37 @@ class Network { void set_ignored(bool ignored) { ignored_ = ignored; } AdapterType type() const { return type_; } + // When type() is ADAPTER_TYPE_VPN, this returns the type of the underlying + // network interface used by the VPN, typically the preferred network type + // (see for example, the method setUnderlyingNetworks(android.net.Network[]) + // on https://developer.android.com/reference/android/net/VpnService.html). + // When this information is unavailable from the OS, ADAPTER_TYPE_UNKNOWN is + // returned. + AdapterType underlying_type_for_vpn() const { + return underlying_type_for_vpn_; + } void set_type(AdapterType type) { if (type_ == type) { return; } type_ = type; + if (type != ADAPTER_TYPE_VPN) { + underlying_type_for_vpn_ = ADAPTER_TYPE_UNKNOWN; + } SignalTypeChanged(this); } - uint16_t GetCost() const { - switch (type_) { - case rtc::ADAPTER_TYPE_ETHERNET: - case rtc::ADAPTER_TYPE_LOOPBACK: - return kNetworkCostMin; - case rtc::ADAPTER_TYPE_WIFI: - case rtc::ADAPTER_TYPE_VPN: - return kNetworkCostLow; - case rtc::ADAPTER_TYPE_CELLULAR: - return kNetworkCostHigh; - default: - return kNetworkCostUnknown; + void set_underlying_type_for_vpn(AdapterType type) { + if (underlying_type_for_vpn_ == type) { + return; } + underlying_type_for_vpn_ = type; + SignalTypeChanged(this); } + + bool IsVpn() const { return type_ == ADAPTER_TYPE_VPN; } + + uint16_t GetCost() const; // A unique id assigned by the network manager, which may be signaled // to the remote side in the candidate. uint16_t id() const { return id_; } @@ -421,6 +430,7 @@ class Network { int scope_id_; bool ignored_; AdapterType type_; + AdapterType underlying_type_for_vpn_ = ADAPTER_TYPE_UNKNOWN; int preference_; bool active_ = true; uint16_t id_ = 0; diff --git a/rtc_base/networkmonitor.cc b/rtc_base/networkmonitor.cc index 0272951351..ad6805acec 100644 --- a/rtc_base/networkmonitor.cc +++ b/rtc_base/networkmonitor.cc @@ -39,6 +39,11 @@ void NetworkMonitorBase::OnMessage(Message* msg) { SignalNetworksChanged(); } +AdapterType NetworkMonitorBase::GetVpnUnderlyingAdapterType( + const std::string& interface_name) { + return ADAPTER_TYPE_UNKNOWN; +} + NetworkMonitorFactory::NetworkMonitorFactory() {} NetworkMonitorFactory::~NetworkMonitorFactory() {} diff --git a/rtc_base/networkmonitor.h b/rtc_base/networkmonitor.h index 254b22575a..a174473002 100644 --- a/rtc_base/networkmonitor.h +++ b/rtc_base/networkmonitor.h @@ -74,6 +74,8 @@ class NetworkMonitorInterface { virtual void OnNetworksChanged() = 0; virtual AdapterType GetAdapterType(const std::string& interface_name) = 0; + virtual AdapterType GetVpnUnderlyingAdapterType( + const std::string& interface_name) = 0; }; class NetworkMonitorBase : public NetworkMonitorInterface, @@ -87,6 +89,9 @@ class NetworkMonitorBase : public NetworkMonitorInterface, void OnMessage(Message* msg) override; + AdapterType GetVpnUnderlyingAdapterType( + const std::string& interface_name) override; + protected: Thread* worker_thread() { return worker_thread_; } diff --git a/sdk/android/api/org/webrtc/NetworkMonitorAutoDetect.java b/sdk/android/api/org/webrtc/NetworkMonitorAutoDetect.java index 55a025715d..112d7cae78 100644 --- a/sdk/android/api/org/webrtc/NetworkMonitorAutoDetect.java +++ b/sdk/android/api/org/webrtc/NetworkMonitorAutoDetect.java @@ -55,6 +55,7 @@ public class NetworkMonitorAutoDetect extends BroadcastReceiver { CONNECTION_2G, CONNECTION_UNKNOWN_CELLULAR, CONNECTION_BLUETOOTH, + CONNECTION_VPN, CONNECTION_NONE } @@ -74,12 +75,15 @@ public class NetworkMonitorAutoDetect extends BroadcastReceiver { public static class NetworkInformation { public final String name; public final ConnectionType type; + // Used to specify the underlying network type if the type is CONNECTION_VPN. + public final ConnectionType underlyingTypeForVpn; public final long handle; public final IPAddress[] ipAddresses; - public NetworkInformation( - String name, ConnectionType type, long handle, IPAddress[] addresses) { + public NetworkInformation(String name, ConnectionType type, ConnectionType underlyingTypeForVpn, + long handle, IPAddress[] addresses) { this.name = name; this.type = type; + this.underlyingTypeForVpn = underlyingTypeForVpn; this.handle = handle; this.ipAddresses = addresses; } @@ -94,6 +98,11 @@ public class NetworkMonitorAutoDetect extends BroadcastReceiver { return type; } + @CalledByNative("NetworkInformation") + private ConnectionType getUnderlyingConnectionTypeForVpn() { + return underlyingTypeForVpn; + } + @CalledByNative("NetworkInformation") private long getHandle() { return handle; @@ -113,11 +122,18 @@ public class NetworkMonitorAutoDetect extends BroadcastReceiver { // Defined from NetworkInfo.subtype, which is one of the TelephonyManager.NETWORK_TYPE_XXXs. // Will be useful to find the maximum bandwidth. private final int subtype; + // When the type is TYPE_VPN, the following two fields specify the similar type and subtype as + // above for the underlying network that is used by the VPN. + private final int underlyingNetworkTypeForVpn; + private final int underlyingNetworkSubtypeForVpn; - public NetworkState(boolean connected, int type, int subtype) { + public NetworkState(boolean connected, int type, int subtype, int underlyingNetworkTypeForVpn, + int underlyingNetworkSubtypeForVpn) { this.connected = connected; this.type = type; this.subtype = subtype; + this.underlyingNetworkTypeForVpn = underlyingNetworkTypeForVpn; + this.underlyingNetworkSubtypeForVpn = underlyingNetworkSubtypeForVpn; } public boolean isConnected() { @@ -131,6 +147,14 @@ public class NetworkMonitorAutoDetect extends BroadcastReceiver { public int getNetworkSubType() { return subtype; } + + public int getUnderlyingNetworkTypeForVpn() { + return underlyingNetworkTypeForVpn; + } + + public int getUnderlyingNetworkSubtypeForVpn() { + return underlyingNetworkSubtypeForVpn; + } } /** * The methods in this class get called when the network changes if the callback @@ -208,7 +232,7 @@ public class NetworkMonitorAutoDetect extends BroadcastReceiver { */ NetworkState getNetworkState() { if (connectivityManager == null) { - return new NetworkState(false, -1, -1); + return new NetworkState(false, -1, -1, -1, -1); } return getNetworkState(connectivityManager.getActiveNetworkInfo()); } @@ -220,19 +244,65 @@ public class NetworkMonitorAutoDetect extends BroadcastReceiver { @SuppressLint("NewApi") NetworkState getNetworkState(Network network) { if (connectivityManager == null) { - return new NetworkState(false, -1, -1); + return new NetworkState(false, -1, -1, -1, -1); } - return getNetworkState(connectivityManager.getNetworkInfo(network)); + NetworkInfo networkInfo = connectivityManager.getNetworkInfo(network); + // The general logic of handling a VPN in this method is as follows. getNetworkInfo will + // return the info of the network with the same id as in |network| when it is registered via + // ConnectivityManager.registerNetworkAgent in Android. |networkInfo| may or may not indicate + // the type TYPE_VPN if |network| is a VPN. To reliably detect the VPN interface, we need to + // query the network capability as below in the case when networkInfo.getType() is not + // TYPE_VPN. On the other hand when networkInfo.getType() is TYPE_VPN, the only solution so + // far to obtain the underlying network information is to query the active network interface. + // However, the active network interface may not be used for the VPN, for example, if the VPN + // is restricted to WiFi by the implementation but the WiFi interface is currently turned + // off and the active interface is the Cell. Using directly the result from + // getActiveNetworkInfo may thus give the wrong interface information, and one should note + // that getActiveNetworkInfo would return the default network interface if the VPN does not + // specify its underlying networks in the implementation. Therefore, we need further compare + // |network| to the active network. If they are not the same network, we will have to fall + // back to report an unknown network. + + // When |network| is in fact a VPN after querying its capability but |networkInfo| is not of + // type TYPE_VPN, |networkInfo| contains the info for the underlying network, and we return a + // NetworkState constructed from it. + if (networkInfo.getType() != ConnectivityManager.TYPE_VPN + && connectivityManager.getNetworkCapabilities(network).hasTransport( + NetworkCapabilities.TRANSPORT_VPN)) { + return new NetworkState(networkInfo.isConnected(), ConnectivityManager.TYPE_VPN, -1, + networkInfo.getType(), networkInfo.getSubtype()); + } + + // When |networkInfo| is of type TYPE_VPN, which implies |network| is a VPN, we return the + // NetworkState of the active network via getActiveNetworkInfo(), if |network| is the active + // network that supports the VPN. Otherwise, NetworkState of an unknown network with type -1 + // will be returned. + if (networkInfo.getType() == ConnectivityManager.TYPE_VPN + && network.equals(connectivityManager.getActiveNetwork())) { + // If a VPN network is in place, we can find the underlying network type via querying the + // active network info thanks to + // https://android.googlesource.com/platform/frameworks/base/+/d6a7980d + NetworkInfo underlyingActiveNetworkInfo = connectivityManager.getActiveNetworkInfo(); + // We use the NetworkInfo of the underlying network if it is not of TYPE_VPN itself. + if (underlyingActiveNetworkInfo.getType() != ConnectivityManager.TYPE_VPN) { + return new NetworkState(networkInfo.isConnected(), ConnectivityManager.TYPE_VPN, -1, + underlyingActiveNetworkInfo.getType(), underlyingActiveNetworkInfo.getSubtype()); + } + } + + return getNetworkState(networkInfo); } /** - * Returns connection type and status information gleaned from networkInfo. + * Returns connection type and status information gleaned from networkInfo. Note that to obtain + * the complete information about a VPN including the type of the underlying network, one should + * use the above method getNetworkState with a Network object. */ - NetworkState getNetworkState(@Nullable NetworkInfo networkInfo) { + private NetworkState getNetworkState(@Nullable NetworkInfo networkInfo) { if (networkInfo == null || !networkInfo.isConnected()) { - return new NetworkState(false, -1, -1); + return new NetworkState(false, -1, -1, -1, -1); } - return new NetworkState(true, networkInfo.getType(), networkInfo.getSubtype()); + return new NetworkState(true, networkInfo.getType(), networkInfo.getSubtype(), -1, -1); } /** @@ -322,12 +392,6 @@ public class NetworkMonitorAutoDetect extends BroadcastReceiver { } NetworkState networkState = getNetworkState(network); - if (networkState.connected && networkState.getNetworkType() == ConnectivityManager.TYPE_VPN) { - // If a VPN network is in place, we can find the underlying network type via querying the - // active network info thanks to - // https://android.googlesource.com/platform/frameworks/base/+/d6a7980d - networkState = getNetworkState(); - } ConnectionType connectionType = getConnectionType(networkState); if (connectionType == ConnectionType.CONNECTION_NONE) { // This may not be an error. The OS may signal a network event with connection type @@ -344,10 +408,14 @@ public class NetworkMonitorAutoDetect extends BroadcastReceiver { + " because it has type " + networkState.getNetworkType() + " and subtype " + networkState.getNetworkSubType()); } + // ConnectionType.CONNECTION_UNKNOWN if the network is not a VPN or the underlying network is + // unknown. + ConnectionType underlyingConnectionTypeForVpn = + getUnderlyingConnectionTypeForVpn(networkState); - NetworkInformation networkInformation = - new NetworkInformation(linkProperties.getInterfaceName(), connectionType, - networkToNetId(network), getIPAddresses(linkProperties)); + NetworkInformation networkInformation = new NetworkInformation( + linkProperties.getInterfaceName(), connectionType, underlyingConnectionTypeForVpn, + networkToNetId(network), getIPAddresses(linkProperties)); return networkInformation; } @@ -504,11 +572,8 @@ public class NetworkMonitorAutoDetect extends BroadcastReceiver { } wifiP2pNetworkInfo = - new NetworkInformation( - wifiP2pGroup.getInterface(), - ConnectionType.CONNECTION_WIFI, - WIFI_P2P_NETWORK_HANDLE, - ipAddresses); + new NetworkInformation(wifiP2pGroup.getInterface(), ConnectionType.CONNECTION_WIFI, + ConnectionType.CONNECTION_NONE, WIFI_P2P_NETWORK_HANDLE, ipAddresses); observer.onNetworkConnect(wifiP2pNetworkInfo); } @@ -683,12 +748,13 @@ public class NetworkMonitorAutoDetect extends BroadcastReceiver { return connectivityManagerDelegate.getDefaultNetId(); } - public static ConnectionType getConnectionType(NetworkState networkState) { - if (!networkState.isConnected()) { + private static ConnectionType getConnectionType( + boolean isConnected, int networkType, int networkSubtype) { + if (!isConnected) { return ConnectionType.CONNECTION_NONE; } - switch (networkState.getNetworkType()) { + switch (networkType) { case ConnectivityManager.TYPE_ETHERNET: return ConnectionType.CONNECTION_ETHERNET; case ConnectivityManager.TYPE_WIFI: @@ -699,7 +765,7 @@ public class NetworkMonitorAutoDetect extends BroadcastReceiver { return ConnectionType.CONNECTION_BLUETOOTH; case ConnectivityManager.TYPE_MOBILE: // Use information from TelephonyManager to classify the connection. - switch (networkState.getNetworkSubType()) { + switch (networkSubtype) { case TelephonyManager.NETWORK_TYPE_GPRS: case TelephonyManager.NETWORK_TYPE_EDGE: case TelephonyManager.NETWORK_TYPE_CDMA: @@ -721,11 +787,27 @@ public class NetworkMonitorAutoDetect extends BroadcastReceiver { default: return ConnectionType.CONNECTION_UNKNOWN_CELLULAR; } + case ConnectivityManager.TYPE_VPN: + return ConnectionType.CONNECTION_VPN; default: return ConnectionType.CONNECTION_UNKNOWN; } } + public static ConnectionType getConnectionType(NetworkState networkState) { + return getConnectionType(networkState.isConnected(), networkState.getNetworkType(), + networkState.getNetworkSubType()); + } + + private static ConnectionType getUnderlyingConnectionTypeForVpn(NetworkState networkState) { + if (networkState.getNetworkType() != ConnectivityManager.TYPE_VPN) { + return ConnectionType.CONNECTION_NONE; + } + return getConnectionType(networkState.isConnected(), + networkState.getUnderlyingNetworkTypeForVpn(), + networkState.getUnderlyingNetworkSubtypeForVpn()); + } + private String getWifiSSID(NetworkState networkState) { if (getConnectionType(networkState) != ConnectionType.CONNECTION_WIFI) return ""; diff --git a/sdk/android/instrumentationtests/src/org/webrtc/NetworkMonitorTest.java b/sdk/android/instrumentationtests/src/org/webrtc/NetworkMonitorTest.java index a5b27f86f5..e4a0e6ae12 100644 --- a/sdk/android/instrumentationtests/src/org/webrtc/NetworkMonitorTest.java +++ b/sdk/android/instrumentationtests/src/org/webrtc/NetworkMonitorTest.java @@ -81,10 +81,13 @@ public class NetworkMonitorTest { private boolean activeNetworkExists; private int networkType; private int networkSubtype; + private int underlyingNetworkTypeForVpn; + private int underlyingNetworkSubtypeForVpn; @Override public NetworkState getNetworkState() { - return new NetworkState(activeNetworkExists, networkType, networkSubtype); + return new NetworkState(activeNetworkExists, networkType, networkSubtype, + underlyingNetworkTypeForVpn, underlyingNetworkSubtypeForVpn); } // Dummy implementations to avoid NullPointerExceptions in default implementations: @@ -101,7 +104,7 @@ public class NetworkMonitorTest { @Override public NetworkState getNetworkState(Network network) { - return new NetworkState(false, -1, -1); + return new NetworkState(false, -1, -1, -1, -1); } public void setActiveNetworkExists(boolean networkExists) { @@ -115,6 +118,14 @@ public class NetworkMonitorTest { public void setNetworkSubtype(int networkSubtype) { this.networkSubtype = networkSubtype; } + + public void setUnderlyingNetworkType(int underlyingNetworkTypeForVpn) { + this.underlyingNetworkTypeForVpn = underlyingNetworkTypeForVpn; + } + + public void setUnderlyingNetworkSubype(int underlyingNetworkSubtypeForVpn) { + this.underlyingNetworkSubtypeForVpn = underlyingNetworkSubtypeForVpn; + } } /** diff --git a/sdk/android/src/jni/androidnetworkmonitor.cc b/sdk/android/src/jni/androidnetworkmonitor.cc index 84a545a14e..cfd51e851f 100644 --- a/sdk/android/src/jni/androidnetworkmonitor.cc +++ b/sdk/android/src/jni/androidnetworkmonitor.cc @@ -60,6 +60,9 @@ static NetworkType GetNetworkTypeFromJava( if (enum_name == "CONNECTION_BLUETOOTH") { return NetworkType::NETWORK_BLUETOOTH; } + if (enum_name == "CONNECTION_VPN") { + return NetworkType::NETWORK_VPN; + } if (enum_name == "CONNECTION_NONE") { return NetworkType::NETWORK_NONE; } @@ -80,6 +83,7 @@ static rtc::AdapterType AdapterTypeFromNetworkType(NetworkType network_type) { case NETWORK_2G: case NETWORK_UNKNOWN_CELLULAR: return rtc::ADAPTER_TYPE_CELLULAR; + case NETWORK_VPN: case NETWORK_BLUETOOTH: // There is no corresponding mapping for bluetooth networks. // Map it to VPN for now. @@ -123,6 +127,9 @@ static NetworkInformation GetNetworkInformationFromJava( Java_NetworkInformation_getHandle(jni, j_network_info)); network_info.type = GetNetworkTypeFromJava( jni, Java_NetworkInformation_getConnectionType(jni, j_network_info)); + network_info.underlying_type_for_vpn = GetNetworkTypeFromJava( + jni, Java_NetworkInformation_getUnderlyingConnectionTypeForVpn( + jni, j_network_info)); ScopedJavaLocalRef j_ip_addresses = Java_NetworkInformation_getIpAddresses(jni, j_network_info); network_info.ip_addresses = JavaToNativeVector( @@ -147,7 +154,11 @@ NetworkInformation& NetworkInformation::operator=(NetworkInformation&&) = std::string NetworkInformation::ToString() const { std::stringstream ss; ss << "NetInfo[name " << interface_name << "; handle " << handle << "; type " - << type << "; address"; + << type; + if (type == NETWORK_VPN) { + ss << "; underlying_type_for_vpn " << underlying_type_for_vpn; + } + ss << "; address"; for (const rtc::IPAddress address : ip_addresses) { ss << " " << address.ToString(); } @@ -316,6 +327,10 @@ void AndroidNetworkMonitor::OnNetworkConnected_w( RTC_LOG(LS_INFO) << "Network connected: " << network_info.ToString(); adapter_type_by_name_[network_info.interface_name] = AdapterTypeFromNetworkType(network_info.type); + if (network_info.type == NETWORK_VPN) { + vpn_underlying_adapter_type_by_name_[network_info.interface_name] = + AdapterTypeFromNetworkType(network_info.underlying_type_for_vpn); + } network_info_by_handle_[network_info.handle] = network_info; for (const rtc::IPAddress& address : network_info.ip_addresses) { network_handle_by_address_[address] = network_info.handle; @@ -363,6 +378,15 @@ rtc::AdapterType AndroidNetworkMonitor::GetAdapterType( return type; } +rtc::AdapterType AndroidNetworkMonitor::GetVpnUnderlyingAdapterType( + const std::string& if_name) { + auto iter = vpn_underlying_adapter_type_by_name_.find(if_name); + rtc::AdapterType type = (iter == vpn_underlying_adapter_type_by_name_.end()) + ? rtc::ADAPTER_TYPE_UNKNOWN + : iter->second; + return type; +} + AndroidNetworkMonitorFactory::AndroidNetworkMonitorFactory() : j_application_context_(nullptr) {} diff --git a/sdk/android/src/jni/androidnetworkmonitor.h b/sdk/android/src/jni/androidnetworkmonitor.h index 58b6686bf9..563d5bd5e4 100644 --- a/sdk/android/src/jni/androidnetworkmonitor.h +++ b/sdk/android/src/jni/androidnetworkmonitor.h @@ -35,6 +35,7 @@ enum NetworkType { NETWORK_2G, NETWORK_UNKNOWN_CELLULAR, NETWORK_BLUETOOTH, + NETWORK_VPN, NETWORK_NONE }; @@ -44,6 +45,7 @@ struct NetworkInformation { std::string interface_name; NetworkHandle handle; NetworkType type; + NetworkType underlying_type_for_vpn; std::vector ip_addresses; NetworkInformation(); @@ -73,6 +75,8 @@ class AndroidNetworkMonitor : public rtc::NetworkMonitorBase, int socket_fd, const rtc::IPAddress& address) override; rtc::AdapterType GetAdapterType(const std::string& if_name) override; + rtc::AdapterType GetVpnUnderlyingAdapterType( + const std::string& if_name) override; void OnNetworkConnected(const NetworkInformation& network_info); void OnNetworkDisconnected(NetworkHandle network_handle); // Always expected to be called on the network thread. @@ -100,6 +104,7 @@ class AndroidNetworkMonitor : public rtc::NetworkMonitorBase, rtc::ThreadChecker thread_checker_; bool started_ = false; std::map adapter_type_by_name_; + std::map vpn_underlying_adapter_type_by_name_; std::map network_handle_by_address_; std::map network_info_by_handle_; };