|  | // Copyright 2017 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "net/nqe/socket_watcher.h" | 
|  |  | 
|  | #include "base/bind.h" | 
|  | #include "base/run_loop.h" | 
|  | #include "base/test/simple_test_tick_clock.h" | 
|  | #include "base/threading/thread_task_runner_handle.h" | 
|  | #include "base/time/time.h" | 
|  | #include "net/base/address_list.h" | 
|  | #include "net/base/ip_address.h" | 
|  | #include "net/socket/socket_performance_watcher.h" | 
|  | #include "net/socket/socket_performance_watcher_factory.h" | 
|  | #include "net/test/test_with_scoped_task_environment.h" | 
|  | #include "testing/gtest/include/gtest/gtest.h" | 
|  |  | 
|  | namespace net { | 
|  |  | 
|  | namespace nqe { | 
|  |  | 
|  | namespace internal { | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | class NetworkQualitySocketWatcherTest : public TestWithScopedTaskEnvironment { | 
|  | protected: | 
|  | NetworkQualitySocketWatcherTest() { ResetExpectedCallbackParams(); } | 
|  | ~NetworkQualitySocketWatcherTest() override { ResetExpectedCallbackParams(); } | 
|  |  | 
|  | static void OnUpdatedRTTAvailableStoreParams( | 
|  | SocketPerformanceWatcherFactory::Protocol protocol, | 
|  | const base::TimeDelta& rtt, | 
|  | const base::Optional<IPHash>& host) { | 
|  | // Need to verify before another callback is executed, or explicitly call | 
|  | // |ResetCallbackParams()|. | 
|  | ASSERT_FALSE(callback_executed_); | 
|  | callback_rtt_ = rtt; | 
|  | callback_host_ = host; | 
|  | callback_executed_ = true; | 
|  | } | 
|  |  | 
|  | static void OnUpdatedRTTAvailable( | 
|  | SocketPerformanceWatcherFactory::Protocol protocol, | 
|  | const base::TimeDelta& rtt, | 
|  | const base::Optional<IPHash>& host) { | 
|  | // Need to verify before another callback is executed, or explicitly call | 
|  | // |ResetCallbackParams()|. | 
|  | ASSERT_FALSE(callback_executed_); | 
|  | callback_executed_ = true; | 
|  | } | 
|  |  | 
|  | static void SetShouldNotifyRTTCallback(bool value) { | 
|  | should_notify_rtt_callback_ = value; | 
|  | } | 
|  |  | 
|  | static bool ShouldNotifyRTTCallback(base::TimeTicks now) { | 
|  | return should_notify_rtt_callback_; | 
|  | } | 
|  |  | 
|  | static void VerifyCallbackParams(const base::TimeDelta& rtt, | 
|  | const base::Optional<IPHash>& host) { | 
|  | ASSERT_TRUE(callback_executed_); | 
|  | EXPECT_EQ(rtt, callback_rtt_); | 
|  | if (host) | 
|  | EXPECT_EQ(host, callback_host_); | 
|  | else | 
|  | EXPECT_FALSE(callback_host_.has_value()); | 
|  | ResetExpectedCallbackParams(); | 
|  | } | 
|  |  | 
|  | static void ResetExpectedCallbackParams() { | 
|  | callback_rtt_ = base::TimeDelta::FromMilliseconds(0); | 
|  | callback_host_ = base::nullopt; | 
|  | callback_executed_ = false; | 
|  | should_notify_rtt_callback_ = false; | 
|  | } | 
|  |  | 
|  | static base::TimeDelta callback_rtt() { return callback_rtt_; } | 
|  |  | 
|  | private: | 
|  | static base::TimeDelta callback_rtt_; | 
|  | static base::Optional<IPHash> callback_host_; | 
|  | static bool callback_executed_; | 
|  | static bool should_notify_rtt_callback_; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(NetworkQualitySocketWatcherTest); | 
|  | }; | 
|  |  | 
|  | base::TimeDelta NetworkQualitySocketWatcherTest::callback_rtt_ = | 
|  | base::TimeDelta::FromMilliseconds(0); | 
|  |  | 
|  | base::Optional<IPHash> NetworkQualitySocketWatcherTest::callback_host_ = | 
|  | base::nullopt; | 
|  |  | 
|  | bool NetworkQualitySocketWatcherTest::callback_executed_ = false; | 
|  |  | 
|  | bool NetworkQualitySocketWatcherTest::should_notify_rtt_callback_ = false; | 
|  |  | 
|  | // Verify that the buffer size is never exceeded. | 
|  | TEST_F(NetworkQualitySocketWatcherTest, NotificationsThrottled) { | 
|  | base::SimpleTestTickClock tick_clock; | 
|  | tick_clock.SetNowTicks(base::TimeTicks::Now()); | 
|  |  | 
|  | // Use a public IP address so that the socket watcher runs the RTT callback. | 
|  | IPAddressList ip_list; | 
|  | IPAddress ip_address; | 
|  | ASSERT_TRUE(ip_address.AssignFromIPLiteral("157.0.0.1")); | 
|  | ip_list.push_back(ip_address); | 
|  | AddressList address_list = | 
|  | AddressList::CreateFromIPAddressList(ip_list, "canonical.example.com"); | 
|  |  | 
|  | SocketWatcher socket_watcher( | 
|  | SocketPerformanceWatcherFactory::PROTOCOL_TCP, address_list, | 
|  | base::TimeDelta::FromMilliseconds(2000), false, | 
|  | base::ThreadTaskRunnerHandle::Get(), base::Bind(OnUpdatedRTTAvailable), | 
|  | base::Bind(ShouldNotifyRTTCallback), &tick_clock); | 
|  |  | 
|  | EXPECT_TRUE(socket_watcher.ShouldNotifyUpdatedRTT()); | 
|  | socket_watcher.OnUpdatedRTTAvailable(base::TimeDelta::FromSeconds(10)); | 
|  | base::RunLoop().RunUntilIdle(); | 
|  | ResetExpectedCallbackParams(); | 
|  |  | 
|  | EXPECT_FALSE(socket_watcher.ShouldNotifyUpdatedRTT()); | 
|  |  | 
|  | tick_clock.Advance(base::TimeDelta::FromMilliseconds(1000)); | 
|  | // Minimum interval between consecutive notifications is 2000 msec. | 
|  | EXPECT_FALSE(socket_watcher.ShouldNotifyUpdatedRTT()); | 
|  |  | 
|  | // Advance the clock by 1000 msec more so that the current time is at least | 
|  | // 2000 msec more than the last time |socket_watcher| received a notification. | 
|  | tick_clock.Advance(base::TimeDelta::FromMilliseconds(1000)); | 
|  | EXPECT_TRUE(socket_watcher.ShouldNotifyUpdatedRTT()); | 
|  | ResetExpectedCallbackParams(); | 
|  | socket_watcher.OnUpdatedRTTAvailable(base::TimeDelta::FromSeconds(10)); | 
|  |  | 
|  | EXPECT_FALSE(socket_watcher.ShouldNotifyUpdatedRTT()); | 
|  |  | 
|  | // RTT notification is allowed by the global check. | 
|  | SetShouldNotifyRTTCallback(true); | 
|  | EXPECT_TRUE(socket_watcher.ShouldNotifyUpdatedRTT()); | 
|  | } | 
|  |  | 
|  | TEST_F(NetworkQualitySocketWatcherTest, QuicFirstNotificationDropped) { | 
|  | base::SimpleTestTickClock tick_clock; | 
|  | tick_clock.SetNowTicks(base::TimeTicks::Now()); | 
|  |  | 
|  | // Use a public IP address so that the socket watcher runs the RTT callback. | 
|  | IPAddressList ip_list; | 
|  | IPAddress ip_address; | 
|  | ASSERT_TRUE(ip_address.AssignFromIPLiteral("157.0.0.1")); | 
|  | ip_list.push_back(ip_address); | 
|  | AddressList address_list = | 
|  | AddressList::CreateFromIPAddressList(ip_list, "canonical.example.com"); | 
|  |  | 
|  | SocketWatcher socket_watcher( | 
|  | SocketPerformanceWatcherFactory::PROTOCOL_QUIC, address_list, | 
|  | base::TimeDelta::FromMilliseconds(2000), false, | 
|  | base::ThreadTaskRunnerHandle::Get(), | 
|  | base::Bind(OnUpdatedRTTAvailableStoreParams), | 
|  | base::Bind(ShouldNotifyRTTCallback), &tick_clock); | 
|  |  | 
|  | EXPECT_TRUE(socket_watcher.ShouldNotifyUpdatedRTT()); | 
|  | socket_watcher.OnUpdatedRTTAvailable(base::TimeDelta::FromSeconds(10)); | 
|  | base::RunLoop().RunUntilIdle(); | 
|  | // First notification from a QUIC connection should be dropped, and it should | 
|  | // be possible to notify the |socket_watcher| again. | 
|  | EXPECT_TRUE(NetworkQualitySocketWatcherTest::callback_rtt().is_zero()); | 
|  | EXPECT_TRUE(socket_watcher.ShouldNotifyUpdatedRTT()); | 
|  | ResetExpectedCallbackParams(); | 
|  |  | 
|  | socket_watcher.OnUpdatedRTTAvailable(base::TimeDelta::FromSeconds(2)); | 
|  | base::RunLoop().RunUntilIdle(); | 
|  | EXPECT_EQ(base::TimeDelta::FromSeconds(2), | 
|  | NetworkQualitySocketWatcherTest::callback_rtt()); | 
|  | ResetExpectedCallbackParams(); | 
|  |  | 
|  | EXPECT_FALSE(socket_watcher.ShouldNotifyUpdatedRTT()); | 
|  |  | 
|  | tick_clock.Advance(base::TimeDelta::FromMilliseconds(1000)); | 
|  | // Minimum interval between consecutive notifications is 2000 msec. | 
|  | EXPECT_FALSE(socket_watcher.ShouldNotifyUpdatedRTT()); | 
|  |  | 
|  | // Advance the clock by 1000 msec more so that the current time is at least | 
|  | // 2000 msec more than the last time |socket_watcher| received a notification. | 
|  | tick_clock.Advance(base::TimeDelta::FromMilliseconds(1000)); | 
|  | EXPECT_TRUE(socket_watcher.ShouldNotifyUpdatedRTT()); | 
|  | } | 
|  |  | 
|  | TEST_F(NetworkQualitySocketWatcherTest, PrivateAddressRTTNotNotified) { | 
|  | base::SimpleTestTickClock tick_clock; | 
|  | tick_clock.SetNowTicks(base::TimeTicks::Now()); | 
|  |  | 
|  | const struct { | 
|  | std::string ip_address; | 
|  | bool expect_should_notify_rtt; | 
|  | } tests[] = { | 
|  | {"157.0.0.1", true},    {"127.0.0.1", false}, | 
|  | {"192.168.0.1", false}, {"::1", false}, | 
|  | {"0.0.0.0", false},     {"2607:f8b0:4006:819::200e", true}, | 
|  | }; | 
|  |  | 
|  | for (const auto& test : tests) { | 
|  | IPAddressList ip_list; | 
|  | IPAddress ip_address; | 
|  | ASSERT_TRUE(ip_address.AssignFromIPLiteral(test.ip_address)); | 
|  | ip_list.push_back(ip_address); | 
|  | AddressList address_list = | 
|  | AddressList::CreateFromIPAddressList(ip_list, "canonical.example.com"); | 
|  |  | 
|  | SocketWatcher socket_watcher( | 
|  | SocketPerformanceWatcherFactory::PROTOCOL_TCP, address_list, | 
|  | base::TimeDelta::FromMilliseconds(2000), false, | 
|  | base::ThreadTaskRunnerHandle::Get(), base::Bind(OnUpdatedRTTAvailable), | 
|  | base::Bind(ShouldNotifyRTTCallback), &tick_clock); | 
|  |  | 
|  | EXPECT_EQ(test.expect_should_notify_rtt, | 
|  | socket_watcher.ShouldNotifyUpdatedRTT()); | 
|  | socket_watcher.OnUpdatedRTTAvailable(base::TimeDelta::FromSeconds(10)); | 
|  | base::RunLoop().RunUntilIdle(); | 
|  | ResetExpectedCallbackParams(); | 
|  |  | 
|  | EXPECT_FALSE(socket_watcher.ShouldNotifyUpdatedRTT()); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_F(NetworkQualitySocketWatcherTest, RemoteHostIPHashComputedCorrectly) { | 
|  | base::SimpleTestTickClock tick_clock; | 
|  | tick_clock.SetNowTicks(base::TimeTicks::Now()); | 
|  | const struct { | 
|  | std::string ip_address; | 
|  | uint64_t host; | 
|  | } tests[] = { | 
|  | {"112.112.112.100", 0x0000000070707064UL},  // IPv4. | 
|  | {"112.112.112.250", 0x00000000707070faUL}, | 
|  | {"2001:0db8:85a3:0000:0000:8a2e:0370:7334", | 
|  | 0x20010db885a30000UL},                                 // IPv6. | 
|  | {"2001:db8:85a3::8a2e:370:7334", 0x20010db885a30000UL}  // Shortened IPv6. | 
|  | }; | 
|  |  | 
|  | for (const auto& test : tests) { | 
|  | IPAddressList ip_list; | 
|  | IPAddress ip_address; | 
|  | ASSERT_TRUE(ip_address.AssignFromIPLiteral(test.ip_address)); | 
|  | ip_list.push_back(ip_address); | 
|  | AddressList address_list = | 
|  | AddressList::CreateFromIPAddressList(ip_list, "canonical.example.com"); | 
|  |  | 
|  | SocketWatcher socket_watcher( | 
|  | SocketPerformanceWatcherFactory::PROTOCOL_TCP, address_list, | 
|  | base::TimeDelta::FromMilliseconds(2000), false, | 
|  | base::ThreadTaskRunnerHandle::Get(), | 
|  | base::Bind(OnUpdatedRTTAvailableStoreParams), | 
|  | base::Bind(ShouldNotifyRTTCallback), &tick_clock); | 
|  | EXPECT_TRUE(socket_watcher.ShouldNotifyUpdatedRTT()); | 
|  | socket_watcher.OnUpdatedRTTAvailable(base::TimeDelta::FromSeconds(10)); | 
|  | base::RunLoop().RunUntilIdle(); | 
|  | VerifyCallbackParams(base::TimeDelta::FromSeconds(10), test.host); | 
|  | EXPECT_FALSE(socket_watcher.ShouldNotifyUpdatedRTT()); | 
|  | } | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | }  // namespace internal | 
|  |  | 
|  | }  // namespace nqe | 
|  |  | 
|  | }  // namespace net |