Support VPN adapter type in WebRTC Android.
The VPN adapter type is not effectively supported in WebRTC Android for
1) the network monitor may not obtain the VPN adapter type from the OS,
e.g. via NetworkInfo.getType, 2) and VPN adapter type is replaced
by the adapter type of an underlying network by the network monitor in
the current implementation. Specifically, WebRTC Android would
previously classify VPNs as either type ADAPTER_TYPE_UNKNOWN, or the
type of the currently active network (which we assume the VPN is
using).
In this CL, VPNs are classified as ADAPTER_TYPE_VPN whenever possible,
and the underlying network type, if available from the VPN, is
separately stored and used to prioritize ICE candidates in network path
selection.
This allows ADAPTER_TYPE_VPN to be used in networkIgnoreMask to ignore
VPNs when gathering ICE candidates.
Bug: webrtc:9168
Change-Id: I9513c76a114ba967437b699e71223a4a2f13f34a
Reviewed-on: https://webrtc-review.googlesource.com/70960
Commit-Queue: Qingsi Wang <qingsi@google.com>
Reviewed-by: Taylor Brandstetter <deadbeef@webrtc.org>
Reviewed-by: Sami Kalliomäki <sakal@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#23061}
diff --git a/rtc_base/network.cc b/rtc_base/network.cc
index 454a778..6daa7c3 100644
--- a/rtc_base/network.cc
+++ b/rtc_base/network.cc
@@ -111,6 +111,24 @@
}
}
+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 @@
}
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 @@
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 @@
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 @@
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 @@
return static_cast<IPAddress>(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 2b0f377..49f500c 100644
--- a/rtc_base/network.h
+++ b/rtc_base/network.h
@@ -293,7 +293,7 @@
AdapterType type);
Network(const Network&);
~Network();
-
+ // This signal is fired whenever type() or underlying_type_for_vpn() changes.
sigslot::signal1<const Network*> SignalTypeChanged;
const DefaultLocalAddressProvider* default_local_address_provider() {
@@ -367,28 +367,37 @@
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 @@
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 0272951..ad6805a 100644
--- a/rtc_base/networkmonitor.cc
+++ b/rtc_base/networkmonitor.cc
@@ -39,6 +39,11 @@
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 254b225..a174473 100644
--- a/rtc_base/networkmonitor.h
+++ b/rtc_base/networkmonitor.h
@@ -74,6 +74,8 @@
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 @@
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 55a0257..112d7ca 100644
--- a/sdk/android/api/org/webrtc/NetworkMonitorAutoDetect.java
+++ b/sdk/android/api/org/webrtc/NetworkMonitorAutoDetect.java
@@ -55,6 +55,7 @@
CONNECTION_2G,
CONNECTION_UNKNOWN_CELLULAR,
CONNECTION_BLUETOOTH,
+ CONNECTION_VPN,
CONNECTION_NONE
}
@@ -74,12 +75,15 @@
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;
}
@@ -95,6 +99,11 @@
}
@CalledByNative("NetworkInformation")
+ private ConnectionType getUnderlyingConnectionTypeForVpn() {
+ return underlyingTypeForVpn;
+ }
+
+ @CalledByNative("NetworkInformation")
private long getHandle() {
return handle;
}
@@ -113,11 +122,18 @@
// 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 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 @@
*/
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 @@
@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 @@
}
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 @@
+ " 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 @@
}
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 @@
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 @@
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 @@
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 a5b27f8..e4a0e6a 100644
--- a/sdk/android/instrumentationtests/src/org/webrtc/NetworkMonitorTest.java
+++ b/sdk/android/instrumentationtests/src/org/webrtc/NetworkMonitorTest.java
@@ -81,10 +81,13 @@
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 @@
@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 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 84a545a..cfd51e8 100644
--- a/sdk/android/src/jni/androidnetworkmonitor.cc
+++ b/sdk/android/src/jni/androidnetworkmonitor.cc
@@ -60,6 +60,9 @@
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 @@
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 @@
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<jobjectArray> j_ip_addresses =
Java_NetworkInformation_getIpAddresses(jni, j_network_info);
network_info.ip_addresses = JavaToNativeVector<rtc::IPAddress>(
@@ -147,7 +154,11 @@
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 @@
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 @@
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 58b6686..563d5bd 100644
--- a/sdk/android/src/jni/androidnetworkmonitor.h
+++ b/sdk/android/src/jni/androidnetworkmonitor.h
@@ -35,6 +35,7 @@
NETWORK_2G,
NETWORK_UNKNOWN_CELLULAR,
NETWORK_BLUETOOTH,
+ NETWORK_VPN,
NETWORK_NONE
};
@@ -44,6 +45,7 @@
std::string interface_name;
NetworkHandle handle;
NetworkType type;
+ NetworkType underlying_type_for_vpn;
std::vector<rtc::IPAddress> ip_addresses;
NetworkInformation();
@@ -73,6 +75,8 @@
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 @@
rtc::ThreadChecker thread_checker_;
bool started_ = false;
std::map<std::string, rtc::AdapterType> adapter_type_by_name_;
+ std::map<std::string, rtc::AdapterType> vpn_underlying_adapter_type_by_name_;
std::map<rtc::IPAddress, NetworkHandle> network_handle_by_address_;
std::map<NetworkHandle, NetworkInformation> network_info_by_handle_;
};