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:
Honghai Zhang
2019-11-05 11:46:40 -08:00
committed by Commit Bot
parent 7350a90237
commit 3c0e86a87d
4 changed files with 196 additions and 13 deletions

View File

@ -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",

View 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

View File

@ -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>(

View File

@ -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 {