Add a field trial to use only the higher 64 bits to find network handle from an ipv6 address.
Bug: webrtc:11067 Change-Id: Ib4f069981f7641f67436757a8592ab0f168a9a6e Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/158800 Commit-Queue: Honghai Zhang <honghaiz@webrtc.org> Reviewed-by: Qingsi Wang <qingsi@webrtc.org> Reviewed-by: Alex Glaznev <glaznev@webrtc.org> Cr-Commit-Position: refs/heads/master@{#29697}
This commit is contained in:

committed by
Commit Bot

parent
7350a90237
commit
3c0e86a87d
@ -557,6 +557,7 @@ if (current_os == "linux" || is_android) {
|
|||||||
"../../rtc_base",
|
"../../rtc_base",
|
||||||
"../../rtc_base:checks",
|
"../../rtc_base:checks",
|
||||||
"../../rtc_base:rtc_base_approved",
|
"../../rtc_base:rtc_base_approved",
|
||||||
|
"../../system_wrappers:field_trial",
|
||||||
"../../system_wrappers:metrics",
|
"../../system_wrappers:metrics",
|
||||||
"//third_party/abseil-cpp/absl/types:optional",
|
"//third_party/abseil-cpp/absl/types:optional",
|
||||||
]
|
]
|
||||||
@ -1453,6 +1454,7 @@ if (is_android) {
|
|||||||
testonly = true
|
testonly = true
|
||||||
|
|
||||||
sources = [
|
sources = [
|
||||||
|
"native_unittests/android_network_monitor_unittest.cc",
|
||||||
"native_unittests/application_context_provider.cc",
|
"native_unittests/application_context_provider.cc",
|
||||||
"native_unittests/application_context_provider.h",
|
"native_unittests/application_context_provider.h",
|
||||||
"native_unittests/audio_device/audio_device_unittest.cc",
|
"native_unittests/audio_device/audio_device_unittest.cc",
|
||||||
@ -1498,9 +1500,11 @@ if (is_android) {
|
|||||||
"../../modules/utility",
|
"../../modules/utility",
|
||||||
"../../pc:libjingle_peerconnection",
|
"../../pc:libjingle_peerconnection",
|
||||||
"../../rtc_base:checks",
|
"../../rtc_base:checks",
|
||||||
"../../rtc_base:rtc_base_approved",
|
"../../rtc_base:rtc_base",
|
||||||
"../../rtc_base/system:inline",
|
"../../rtc_base/system:inline",
|
||||||
"../../system_wrappers",
|
"../../system_wrappers",
|
||||||
|
"../../system_wrappers:field_trial",
|
||||||
|
"../../test:field_trial",
|
||||||
"../../test:fileutils",
|
"../../test:fileutils",
|
||||||
"../../test:test_support",
|
"../../test:test_support",
|
||||||
"../../testing/gtest",
|
"../../testing/gtest",
|
||||||
|
125
sdk/android/native_unittests/android_network_monitor_unittest.cc
Normal file
125
sdk/android/native_unittests/android_network_monitor_unittest.cc
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019 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/android/src/jni/android_network_monitor.h"
|
||||||
|
|
||||||
|
#include "rtc_base/ip_address.h"
|
||||||
|
#include "sdk/android/native_unittests/application_context_provider.h"
|
||||||
|
#include "sdk/android/src/jni/jni_helpers.h"
|
||||||
|
#include "system_wrappers/include/field_trial.h"
|
||||||
|
#include "test/field_trial.h"
|
||||||
|
#include "test/gtest.h"
|
||||||
|
|
||||||
|
namespace webrtc {
|
||||||
|
namespace test {
|
||||||
|
static const uint32_t kTestIpv4Address = 0xC0A80011; // 192.168.0.17
|
||||||
|
// The following two ipv6 addresses only diff by the last 64 bits.
|
||||||
|
static const char kTestIpv6Address1[] = "2a00:8a00:a000:1190:0000:0001:000:252";
|
||||||
|
static const char kTestIpv6Address2[] = "2a00:8a00:a000:1190:0000:0002:000:253";
|
||||||
|
|
||||||
|
jni::NetworkInformation CreateNetworkInformation(
|
||||||
|
const std::string& interface_name,
|
||||||
|
jni::NetworkHandle network_handle,
|
||||||
|
const rtc::IPAddress& ip_address) {
|
||||||
|
jni::NetworkInformation net_info;
|
||||||
|
net_info.interface_name = interface_name;
|
||||||
|
net_info.handle = network_handle;
|
||||||
|
net_info.type = jni::NETWORK_WIFI;
|
||||||
|
net_info.ip_addresses.push_back(ip_address);
|
||||||
|
return net_info;
|
||||||
|
}
|
||||||
|
|
||||||
|
rtc::IPAddress GetIpAddressFromIpv6String(const std::string& str) {
|
||||||
|
rtc::IPAddress ipv6;
|
||||||
|
RTC_CHECK(rtc::IPFromString(str, &ipv6));
|
||||||
|
return ipv6;
|
||||||
|
}
|
||||||
|
|
||||||
|
class AndroidNetworkMonitorTest : public ::testing::Test {
|
||||||
|
public:
|
||||||
|
AndroidNetworkMonitorTest() {
|
||||||
|
JNIEnv* env = AttachCurrentThreadIfNeeded();
|
||||||
|
ScopedJavaLocalRef<jobject> context = test::GetAppContextForTest(env);
|
||||||
|
network_monitor_ =
|
||||||
|
std::make_unique<jni::AndroidNetworkMonitor>(env, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetUp() {
|
||||||
|
// Reset network monitor states.
|
||||||
|
network_monitor_->Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::unique_ptr<jni::AndroidNetworkMonitor> network_monitor_;
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(AndroidNetworkMonitorTest, TestFindNetworkHandleUsingIpv4Address) {
|
||||||
|
jni::NetworkHandle ipv4_handle = 100;
|
||||||
|
rtc::IPAddress ipv4_address(kTestIpv4Address);
|
||||||
|
jni::NetworkInformation net_info =
|
||||||
|
CreateNetworkInformation("wlan0", ipv4_handle, ipv4_address);
|
||||||
|
std::vector<jni::NetworkInformation> net_infos(1, net_info);
|
||||||
|
network_monitor_->SetNetworkInfos(net_infos);
|
||||||
|
|
||||||
|
auto network_handle =
|
||||||
|
network_monitor_->FindNetworkHandleFromAddress(ipv4_address);
|
||||||
|
|
||||||
|
ASSERT_TRUE(network_handle.has_value());
|
||||||
|
EXPECT_EQ(ipv4_handle, *network_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(AndroidNetworkMonitorTest, TestFindNetworkHandleUsingFullIpv6Address) {
|
||||||
|
jni::NetworkHandle ipv6_handle = 200;
|
||||||
|
rtc::IPAddress ipv6_address1 = GetIpAddressFromIpv6String(kTestIpv6Address1);
|
||||||
|
rtc::IPAddress ipv6_address2 = GetIpAddressFromIpv6String(kTestIpv6Address2);
|
||||||
|
// Set up an IPv6 network.
|
||||||
|
jni::NetworkInformation net_info =
|
||||||
|
CreateNetworkInformation("wlan0", ipv6_handle, ipv6_address1);
|
||||||
|
std::vector<jni::NetworkInformation> net_infos(1, net_info);
|
||||||
|
network_monitor_->SetNetworkInfos(net_infos);
|
||||||
|
|
||||||
|
auto network_handle1 =
|
||||||
|
network_monitor_->FindNetworkHandleFromAddress(ipv6_address1);
|
||||||
|
auto network_handle2 =
|
||||||
|
network_monitor_->FindNetworkHandleFromAddress(ipv6_address2);
|
||||||
|
|
||||||
|
ASSERT_TRUE(network_handle1.has_value());
|
||||||
|
EXPECT_EQ(ipv6_handle, *network_handle1);
|
||||||
|
EXPECT_TRUE(!network_handle2);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(AndroidNetworkMonitorTest,
|
||||||
|
TestFindNetworkHandleIgnoringIpv6TemporaryPart) {
|
||||||
|
ScopedFieldTrials field_trials(
|
||||||
|
"WebRTC-FindNetworkHandleWithoutIpv6TemporaryPart/Enabled/");
|
||||||
|
// Start() updates the states introduced by the field trial.
|
||||||
|
network_monitor_->Start();
|
||||||
|
jni::NetworkHandle ipv6_handle = 200;
|
||||||
|
rtc::IPAddress ipv6_address1 = GetIpAddressFromIpv6String(kTestIpv6Address1);
|
||||||
|
rtc::IPAddress ipv6_address2 = GetIpAddressFromIpv6String(kTestIpv6Address2);
|
||||||
|
// Set up an IPv6 network.
|
||||||
|
jni::NetworkInformation net_info =
|
||||||
|
CreateNetworkInformation("wlan0", ipv6_handle, ipv6_address1);
|
||||||
|
std::vector<jni::NetworkInformation> net_infos(1, net_info);
|
||||||
|
network_monitor_->SetNetworkInfos(net_infos);
|
||||||
|
|
||||||
|
auto network_handle1 =
|
||||||
|
network_monitor_->FindNetworkHandleFromAddress(ipv6_address1);
|
||||||
|
auto network_handle2 =
|
||||||
|
network_monitor_->FindNetworkHandleFromAddress(ipv6_address2);
|
||||||
|
|
||||||
|
ASSERT_TRUE(network_handle1.has_value());
|
||||||
|
EXPECT_EQ(ipv6_handle, *network_handle1);
|
||||||
|
ASSERT_TRUE(network_handle2.has_value());
|
||||||
|
EXPECT_EQ(ipv6_handle, *network_handle2);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace test
|
||||||
|
} // namespace webrtc
|
@ -25,6 +25,7 @@
|
|||||||
#include "sdk/android/generated_base_jni/NetworkMonitor_jni.h"
|
#include "sdk/android/generated_base_jni/NetworkMonitor_jni.h"
|
||||||
#include "sdk/android/native_api/jni/java_types.h"
|
#include "sdk/android/native_api/jni/java_types.h"
|
||||||
#include "sdk/android/src/jni/jni_helpers.h"
|
#include "sdk/android/src/jni/jni_helpers.h"
|
||||||
|
#include "system_wrappers/include/field_trial.h"
|
||||||
|
|
||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
namespace jni {
|
namespace jni {
|
||||||
@ -135,6 +136,22 @@ static NetworkInformation GetNetworkInformationFromJava(
|
|||||||
return network_info;
|
return network_info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool AddressMatch(const rtc::IPAddress& ip1, const rtc::IPAddress& ip2) {
|
||||||
|
if (ip1.family() != ip2.family()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (ip1.family() == AF_INET) {
|
||||||
|
return ip1.ipv4_address().s_addr == ip2.ipv4_address().s_addr;
|
||||||
|
}
|
||||||
|
if (ip1.family() == AF_INET6) {
|
||||||
|
// The last 64-bits of an ipv6 address are temporary address and it could
|
||||||
|
// change over time. So we only compare the first 64-bits.
|
||||||
|
return memcmp(ip1.ipv6_address().s6_addr, ip2.ipv6_address().s6_addr,
|
||||||
|
sizeof(in6_addr) / 2) == 0;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
NetworkInformation::NetworkInformation() = default;
|
NetworkInformation::NetworkInformation() = default;
|
||||||
|
|
||||||
NetworkInformation::NetworkInformation(const NetworkInformation&) = default;
|
NetworkInformation::NetworkInformation(const NetworkInformation&) = default;
|
||||||
@ -179,6 +196,9 @@ void AndroidNetworkMonitor::Start() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
started_ = true;
|
started_ = true;
|
||||||
|
find_network_handle_without_ipv6_temporary_part_ =
|
||||||
|
webrtc::field_trial::IsEnabled(
|
||||||
|
"WebRTC-FindNetworkHandleWithoutIpv6TemporaryPart");
|
||||||
|
|
||||||
// This is kind of magic behavior, but doing this allows the SocketServer to
|
// This is kind of magic behavior, but doing this allows the SocketServer to
|
||||||
// use this as a NetworkBinder to bind sockets on a particular network when
|
// use this as a NetworkBinder to bind sockets on a particular network when
|
||||||
@ -196,6 +216,7 @@ void AndroidNetworkMonitor::Stop() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
started_ = false;
|
started_ = false;
|
||||||
|
find_network_handle_without_ipv6_temporary_part_ = false;
|
||||||
|
|
||||||
// Once the network monitor stops, it will clear all network information and
|
// Once the network monitor stops, it will clear all network information and
|
||||||
// it won't find the network handle to bind anyway.
|
// it won't find the network handle to bind anyway.
|
||||||
@ -219,7 +240,8 @@ rtc::NetworkBindingResult AndroidNetworkMonitor::BindSocketToNetwork(
|
|||||||
RTC_CHECK(thread_checker_.IsCurrent());
|
RTC_CHECK(thread_checker_.IsCurrent());
|
||||||
|
|
||||||
// Android prior to Lollipop didn't have support for binding sockets to
|
// Android prior to Lollipop didn't have support for binding sockets to
|
||||||
// networks. This may also occur if there is no connectivity manager service.
|
// networks. This may also occur if there is no connectivity manager
|
||||||
|
// service.
|
||||||
JNIEnv* env = AttachCurrentThreadIfNeeded();
|
JNIEnv* env = AttachCurrentThreadIfNeeded();
|
||||||
const bool network_binding_supported =
|
const bool network_binding_supported =
|
||||||
Java_NetworkMonitor_networkBindingSupported(env, j_network_monitor_);
|
Java_NetworkMonitor_networkBindingSupported(env, j_network_monitor_);
|
||||||
@ -230,13 +252,13 @@ rtc::NetworkBindingResult AndroidNetworkMonitor::BindSocketToNetwork(
|
|||||||
return rtc::NetworkBindingResult::NOT_IMPLEMENTED;
|
return rtc::NetworkBindingResult::NOT_IMPLEMENTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto iter = network_handle_by_address_.find(address);
|
absl::optional<NetworkHandle> network_handle =
|
||||||
if (iter == network_handle_by_address_.end()) {
|
FindNetworkHandleFromAddress(address);
|
||||||
|
if (!network_handle) {
|
||||||
return rtc::NetworkBindingResult::ADDRESS_NOT_FOUND;
|
return rtc::NetworkBindingResult::ADDRESS_NOT_FOUND;
|
||||||
}
|
}
|
||||||
NetworkHandle network_handle = iter->second;
|
|
||||||
|
|
||||||
if (network_handle == 0 /* NETWORK_UNSPECIFIED */) {
|
if (*network_handle == 0 /* NETWORK_UNSPECIFIED */) {
|
||||||
return rtc::NetworkBindingResult::NOT_IMPLEMENTED;
|
return rtc::NetworkBindingResult::NOT_IMPLEMENTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -267,10 +289,10 @@ rtc::NetworkBindingResult AndroidNetworkMonitor::BindSocketToNetwork(
|
|||||||
RTC_LOG(LS_ERROR) << "Symbol marshmallowSetNetworkForSocket is not found";
|
RTC_LOG(LS_ERROR) << "Symbol marshmallowSetNetworkForSocket is not found";
|
||||||
return rtc::NetworkBindingResult::NOT_IMPLEMENTED;
|
return rtc::NetworkBindingResult::NOT_IMPLEMENTED;
|
||||||
}
|
}
|
||||||
rv = marshmallowSetNetworkForSocket(network_handle, socket_fd);
|
rv = marshmallowSetNetworkForSocket(*network_handle, socket_fd);
|
||||||
} else {
|
} else {
|
||||||
// NOTE: This relies on Android implementation details, but it won't change
|
// NOTE: This relies on Android implementation details, but it won't
|
||||||
// because Lollipop is already released.
|
// change because Lollipop is already released.
|
||||||
typedef int (*LollipopSetNetworkForSocket)(unsigned net, int socket);
|
typedef int (*LollipopSetNetworkForSocket)(unsigned net, int socket);
|
||||||
static LollipopSetNetworkForSocket lollipopSetNetworkForSocket;
|
static LollipopSetNetworkForSocket lollipopSetNetworkForSocket;
|
||||||
// This is not threadsafe, but we are running this only on the worker
|
// This is not threadsafe, but we are running this only on the worker
|
||||||
@ -296,10 +318,10 @@ rtc::NetworkBindingResult AndroidNetworkMonitor::BindSocketToNetwork(
|
|||||||
RTC_LOG(LS_ERROR) << "Symbol lollipopSetNetworkForSocket is not found ";
|
RTC_LOG(LS_ERROR) << "Symbol lollipopSetNetworkForSocket is not found ";
|
||||||
return rtc::NetworkBindingResult::NOT_IMPLEMENTED;
|
return rtc::NetworkBindingResult::NOT_IMPLEMENTED;
|
||||||
}
|
}
|
||||||
rv = lollipopSetNetworkForSocket(network_handle, socket_fd);
|
rv = lollipopSetNetworkForSocket(*network_handle, socket_fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If |network| has since disconnected, |rv| will be ENONET. Surface this as
|
// If |network| has since disconnected, |rv| will be ENONET. Surface this as
|
||||||
// ERR_NETWORK_CHANGED, rather than MapSystemError(ENONET) which gives back
|
// ERR_NETWORK_CHANGED, rather than MapSystemError(ENONET) which gives back
|
||||||
// the less descriptive ERR_FAILED.
|
// the less descriptive ERR_FAILED.
|
||||||
if (rv == 0) {
|
if (rv == 0) {
|
||||||
@ -335,6 +357,32 @@ void AndroidNetworkMonitor::OnNetworkConnected_w(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
absl::optional<NetworkHandle>
|
||||||
|
AndroidNetworkMonitor::FindNetworkHandleFromAddress(
|
||||||
|
const rtc::IPAddress& ip_address) const {
|
||||||
|
RTC_LOG(LS_INFO) << "Find network handle for address: "
|
||||||
|
<< ip_address.ToString();
|
||||||
|
if (find_network_handle_without_ipv6_temporary_part_) {
|
||||||
|
for (auto const& iter : network_info_by_handle_) {
|
||||||
|
const std::vector<rtc::IPAddress>& addresses = iter.second.ip_addresses;
|
||||||
|
auto address_it = std::find_if(addresses.begin(), addresses.end(),
|
||||||
|
[ip_address](rtc::IPAddress address) {
|
||||||
|
return AddressMatch(ip_address, address);
|
||||||
|
});
|
||||||
|
if (address_it != addresses.end()) {
|
||||||
|
return absl::make_optional(iter.first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return absl::nullopt;
|
||||||
|
} else {
|
||||||
|
auto iter = network_handle_by_address_.find(ip_address);
|
||||||
|
if (iter == network_handle_by_address_.end()) {
|
||||||
|
return absl::nullopt;
|
||||||
|
}
|
||||||
|
return absl::make_optional(iter->second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void AndroidNetworkMonitor::OnNetworkDisconnected(NetworkHandle handle) {
|
void AndroidNetworkMonitor::OnNetworkDisconnected(NetworkHandle handle) {
|
||||||
RTC_LOG(LS_INFO) << "Network disconnected for handle " << handle;
|
RTC_LOG(LS_INFO) << "Network disconnected for handle " << handle;
|
||||||
worker_thread()->Invoke<void>(
|
worker_thread()->Invoke<void>(
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "absl/types/optional.h"
|
||||||
#include "rtc_base/network_monitor.h"
|
#include "rtc_base/network_monitor.h"
|
||||||
#include "rtc_base/thread_checker.h"
|
#include "rtc_base/thread_checker.h"
|
||||||
#include "sdk/android/src/jni/jni_helpers.h"
|
#include "sdk/android/src/jni/jni_helpers.h"
|
||||||
@ -61,8 +62,8 @@ struct NetworkInformation {
|
|||||||
class AndroidNetworkMonitor : public rtc::NetworkMonitorBase,
|
class AndroidNetworkMonitor : public rtc::NetworkMonitorBase,
|
||||||
public rtc::NetworkBinderInterface {
|
public rtc::NetworkBinderInterface {
|
||||||
public:
|
public:
|
||||||
explicit AndroidNetworkMonitor(JNIEnv* env,
|
AndroidNetworkMonitor(JNIEnv* env,
|
||||||
const JavaRef<jobject>& j_application_context);
|
const JavaRef<jobject>& j_application_context);
|
||||||
~AndroidNetworkMonitor() override;
|
~AndroidNetworkMonitor() override;
|
||||||
|
|
||||||
// TODO(sakal): Remove once down stream dependencies have been updated.
|
// TODO(sakal): Remove once down stream dependencies have been updated.
|
||||||
@ -94,6 +95,10 @@ class AndroidNetworkMonitor : public rtc::NetworkMonitorBase,
|
|||||||
const JavaRef<jobject>& j_caller,
|
const JavaRef<jobject>& j_caller,
|
||||||
const JavaRef<jobjectArray>& j_network_infos);
|
const JavaRef<jobjectArray>& j_network_infos);
|
||||||
|
|
||||||
|
// Visible for testing.
|
||||||
|
absl::optional<NetworkHandle> FindNetworkHandleFromAddress(
|
||||||
|
const rtc::IPAddress& address) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void OnNetworkConnected_w(const NetworkInformation& network_info);
|
void OnNetworkConnected_w(const NetworkInformation& network_info);
|
||||||
void OnNetworkDisconnected_w(NetworkHandle network_handle);
|
void OnNetworkDisconnected_w(NetworkHandle network_handle);
|
||||||
@ -107,6 +112,7 @@ class AndroidNetworkMonitor : public rtc::NetworkMonitorBase,
|
|||||||
std::map<std::string, rtc::AdapterType> vpn_underlying_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<rtc::IPAddress, NetworkHandle> network_handle_by_address_;
|
||||||
std::map<NetworkHandle, NetworkInformation> network_info_by_handle_;
|
std::map<NetworkHandle, NetworkInformation> network_info_by_handle_;
|
||||||
|
bool find_network_handle_without_ipv6_temporary_part_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class AndroidNetworkMonitorFactory : public rtc::NetworkMonitorFactory {
|
class AndroidNetworkMonitorFactory : public rtc::NetworkMonitorFactory {
|
||||||
|
Reference in New Issue
Block a user