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:checks",
|
||||
"../../rtc_base:rtc_base_approved",
|
||||
"../../system_wrappers:field_trial",
|
||||
"../../system_wrappers:metrics",
|
||||
"//third_party/abseil-cpp/absl/types:optional",
|
||||
]
|
||||
@ -1453,6 +1454,7 @@ if (is_android) {
|
||||
testonly = true
|
||||
|
||||
sources = [
|
||||
"native_unittests/android_network_monitor_unittest.cc",
|
||||
"native_unittests/application_context_provider.cc",
|
||||
"native_unittests/application_context_provider.h",
|
||||
"native_unittests/audio_device/audio_device_unittest.cc",
|
||||
@ -1498,9 +1500,11 @@ if (is_android) {
|
||||
"../../modules/utility",
|
||||
"../../pc:libjingle_peerconnection",
|
||||
"../../rtc_base:checks",
|
||||
"../../rtc_base:rtc_base_approved",
|
||||
"../../rtc_base:rtc_base",
|
||||
"../../rtc_base/system:inline",
|
||||
"../../system_wrappers",
|
||||
"../../system_wrappers:field_trial",
|
||||
"../../test:field_trial",
|
||||
"../../test:fileutils",
|
||||
"../../test:test_support",
|
||||
"../../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/native_api/jni/java_types.h"
|
||||
#include "sdk/android/src/jni/jni_helpers.h"
|
||||
#include "system_wrappers/include/field_trial.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace jni {
|
||||
@ -135,6 +136,22 @@ static NetworkInformation GetNetworkInformationFromJava(
|
||||
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(const NetworkInformation&) = default;
|
||||
@ -179,6 +196,9 @@ void AndroidNetworkMonitor::Start() {
|
||||
return;
|
||||
}
|
||||
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
|
||||
// use this as a NetworkBinder to bind sockets on a particular network when
|
||||
@ -196,6 +216,7 @@ void AndroidNetworkMonitor::Stop() {
|
||||
return;
|
||||
}
|
||||
started_ = false;
|
||||
find_network_handle_without_ipv6_temporary_part_ = false;
|
||||
|
||||
// Once the network monitor stops, it will clear all network information and
|
||||
// it won't find the network handle to bind anyway.
|
||||
@ -219,7 +240,8 @@ rtc::NetworkBindingResult AndroidNetworkMonitor::BindSocketToNetwork(
|
||||
RTC_CHECK(thread_checker_.IsCurrent());
|
||||
|
||||
// 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();
|
||||
const bool network_binding_supported =
|
||||
Java_NetworkMonitor_networkBindingSupported(env, j_network_monitor_);
|
||||
@ -230,13 +252,13 @@ rtc::NetworkBindingResult AndroidNetworkMonitor::BindSocketToNetwork(
|
||||
return rtc::NetworkBindingResult::NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
auto iter = network_handle_by_address_.find(address);
|
||||
if (iter == network_handle_by_address_.end()) {
|
||||
absl::optional<NetworkHandle> network_handle =
|
||||
FindNetworkHandleFromAddress(address);
|
||||
if (!network_handle) {
|
||||
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;
|
||||
}
|
||||
|
||||
@ -267,10 +289,10 @@ rtc::NetworkBindingResult AndroidNetworkMonitor::BindSocketToNetwork(
|
||||
RTC_LOG(LS_ERROR) << "Symbol marshmallowSetNetworkForSocket is not found";
|
||||
return rtc::NetworkBindingResult::NOT_IMPLEMENTED;
|
||||
}
|
||||
rv = marshmallowSetNetworkForSocket(network_handle, socket_fd);
|
||||
rv = marshmallowSetNetworkForSocket(*network_handle, socket_fd);
|
||||
} else {
|
||||
// NOTE: This relies on Android implementation details, but it won't change
|
||||
// because Lollipop is already released.
|
||||
// NOTE: This relies on Android implementation details, but it won't
|
||||
// change because Lollipop is already released.
|
||||
typedef int (*LollipopSetNetworkForSocket)(unsigned net, int socket);
|
||||
static LollipopSetNetworkForSocket lollipopSetNetworkForSocket;
|
||||
// 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 ";
|
||||
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
|
||||
// the less descriptive ERR_FAILED.
|
||||
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) {
|
||||
RTC_LOG(LS_INFO) << "Network disconnected for handle " << handle;
|
||||
worker_thread()->Invoke<void>(
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/types/optional.h"
|
||||
#include "rtc_base/network_monitor.h"
|
||||
#include "rtc_base/thread_checker.h"
|
||||
#include "sdk/android/src/jni/jni_helpers.h"
|
||||
@ -61,8 +62,8 @@ struct NetworkInformation {
|
||||
class AndroidNetworkMonitor : public rtc::NetworkMonitorBase,
|
||||
public rtc::NetworkBinderInterface {
|
||||
public:
|
||||
explicit AndroidNetworkMonitor(JNIEnv* env,
|
||||
const JavaRef<jobject>& j_application_context);
|
||||
AndroidNetworkMonitor(JNIEnv* env,
|
||||
const JavaRef<jobject>& j_application_context);
|
||||
~AndroidNetworkMonitor() override;
|
||||
|
||||
// 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<jobjectArray>& j_network_infos);
|
||||
|
||||
// Visible for testing.
|
||||
absl::optional<NetworkHandle> FindNetworkHandleFromAddress(
|
||||
const rtc::IPAddress& address) const;
|
||||
|
||||
private:
|
||||
void OnNetworkConnected_w(const NetworkInformation& network_info);
|
||||
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<rtc::IPAddress, NetworkHandle> network_handle_by_address_;
|
||||
std::map<NetworkHandle, NetworkInformation> network_info_by_handle_;
|
||||
bool find_network_handle_without_ipv6_temporary_part_;
|
||||
};
|
||||
|
||||
class AndroidNetworkMonitorFactory : public rtc::NetworkMonitorFactory {
|
||||
|
Reference in New Issue
Block a user