1*6777b538SAndroid Build Coastguard Worker // Copyright 2016 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker
5*6777b538SAndroid Build Coastguard Worker #include "net/nqe/socket_watcher.h"
6*6777b538SAndroid Build Coastguard Worker
7*6777b538SAndroid Build Coastguard Worker #include "base/functional/bind.h"
8*6777b538SAndroid Build Coastguard Worker #include "base/location.h"
9*6777b538SAndroid Build Coastguard Worker #include "base/task/single_thread_task_runner.h"
10*6777b538SAndroid Build Coastguard Worker #include "base/time/tick_clock.h"
11*6777b538SAndroid Build Coastguard Worker #include "base/time/time.h"
12*6777b538SAndroid Build Coastguard Worker #include "net/base/ip_address.h"
13*6777b538SAndroid Build Coastguard Worker
14*6777b538SAndroid Build Coastguard Worker namespace net::nqe::internal {
15*6777b538SAndroid Build Coastguard Worker
16*6777b538SAndroid Build Coastguard Worker namespace {
17*6777b538SAndroid Build Coastguard Worker
18*6777b538SAndroid Build Coastguard Worker // Generate a compact representation for |ip_addr|. For IPv4, all 32 bits
19*6777b538SAndroid Build Coastguard Worker // are used and for IPv6, the first 64 bits are used as the remote host
20*6777b538SAndroid Build Coastguard Worker // identifier.
CalculateIPHash(const IPAddress & ip_addr)21*6777b538SAndroid Build Coastguard Worker std::optional<IPHash> CalculateIPHash(const IPAddress& ip_addr) {
22*6777b538SAndroid Build Coastguard Worker IPAddressBytes bytes = ip_addr.bytes();
23*6777b538SAndroid Build Coastguard Worker
24*6777b538SAndroid Build Coastguard Worker // For IPv4, the first four bytes are taken. For IPv6, the first 8 bytes are
25*6777b538SAndroid Build Coastguard Worker // taken. For IPv4MappedIPv6, the last 4 bytes are taken.
26*6777b538SAndroid Build Coastguard Worker int index_min = ip_addr.IsIPv4MappedIPv6() ? 12 : 0;
27*6777b538SAndroid Build Coastguard Worker int index_max;
28*6777b538SAndroid Build Coastguard Worker if (ip_addr.IsIPv4MappedIPv6())
29*6777b538SAndroid Build Coastguard Worker index_max = 16;
30*6777b538SAndroid Build Coastguard Worker else
31*6777b538SAndroid Build Coastguard Worker index_max = ip_addr.IsIPv4() ? 4 : 8;
32*6777b538SAndroid Build Coastguard Worker
33*6777b538SAndroid Build Coastguard Worker DCHECK_LE(index_min, index_max);
34*6777b538SAndroid Build Coastguard Worker DCHECK_GE(8, index_max - index_min);
35*6777b538SAndroid Build Coastguard Worker
36*6777b538SAndroid Build Coastguard Worker uint64_t result = 0ULL;
37*6777b538SAndroid Build Coastguard Worker for (int i = index_min; i < index_max; ++i) {
38*6777b538SAndroid Build Coastguard Worker result = result << 8;
39*6777b538SAndroid Build Coastguard Worker result |= bytes[i];
40*6777b538SAndroid Build Coastguard Worker }
41*6777b538SAndroid Build Coastguard Worker return result;
42*6777b538SAndroid Build Coastguard Worker }
43*6777b538SAndroid Build Coastguard Worker
44*6777b538SAndroid Build Coastguard Worker } // namespace
45*6777b538SAndroid Build Coastguard Worker
SocketWatcher(SocketPerformanceWatcherFactory::Protocol protocol,const IPAddress & address,base::TimeDelta min_notification_interval,bool allow_rtt_private_address,scoped_refptr<base::SingleThreadTaskRunner> task_runner,OnUpdatedRTTAvailableCallback updated_rtt_observation_callback,ShouldNotifyRTTCallback should_notify_rtt_callback,const base::TickClock * tick_clock)46*6777b538SAndroid Build Coastguard Worker SocketWatcher::SocketWatcher(
47*6777b538SAndroid Build Coastguard Worker SocketPerformanceWatcherFactory::Protocol protocol,
48*6777b538SAndroid Build Coastguard Worker const IPAddress& address,
49*6777b538SAndroid Build Coastguard Worker base::TimeDelta min_notification_interval,
50*6777b538SAndroid Build Coastguard Worker bool allow_rtt_private_address,
51*6777b538SAndroid Build Coastguard Worker scoped_refptr<base::SingleThreadTaskRunner> task_runner,
52*6777b538SAndroid Build Coastguard Worker OnUpdatedRTTAvailableCallback updated_rtt_observation_callback,
53*6777b538SAndroid Build Coastguard Worker ShouldNotifyRTTCallback should_notify_rtt_callback,
54*6777b538SAndroid Build Coastguard Worker const base::TickClock* tick_clock)
55*6777b538SAndroid Build Coastguard Worker : protocol_(protocol),
56*6777b538SAndroid Build Coastguard Worker task_runner_(std::move(task_runner)),
57*6777b538SAndroid Build Coastguard Worker updated_rtt_observation_callback_(updated_rtt_observation_callback),
58*6777b538SAndroid Build Coastguard Worker should_notify_rtt_callback_(should_notify_rtt_callback),
59*6777b538SAndroid Build Coastguard Worker rtt_notifications_minimum_interval_(min_notification_interval),
60*6777b538SAndroid Build Coastguard Worker allow_rtt_private_address_(allow_rtt_private_address),
61*6777b538SAndroid Build Coastguard Worker run_rtt_callback_(allow_rtt_private_address ||
62*6777b538SAndroid Build Coastguard Worker address.IsPubliclyRoutable()),
63*6777b538SAndroid Build Coastguard Worker tick_clock_(tick_clock),
64*6777b538SAndroid Build Coastguard Worker host_(CalculateIPHash(address)) {
65*6777b538SAndroid Build Coastguard Worker DCHECK(tick_clock_);
66*6777b538SAndroid Build Coastguard Worker DCHECK(last_rtt_notification_.is_null());
67*6777b538SAndroid Build Coastguard Worker }
68*6777b538SAndroid Build Coastguard Worker
69*6777b538SAndroid Build Coastguard Worker SocketWatcher::~SocketWatcher() = default;
70*6777b538SAndroid Build Coastguard Worker
ShouldNotifyUpdatedRTT() const71*6777b538SAndroid Build Coastguard Worker bool SocketWatcher::ShouldNotifyUpdatedRTT() const {
72*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
73*6777b538SAndroid Build Coastguard Worker
74*6777b538SAndroid Build Coastguard Worker if (!run_rtt_callback_)
75*6777b538SAndroid Build Coastguard Worker return false;
76*6777b538SAndroid Build Coastguard Worker
77*6777b538SAndroid Build Coastguard Worker const base::TimeTicks now = tick_clock_->NowTicks();
78*6777b538SAndroid Build Coastguard Worker
79*6777b538SAndroid Build Coastguard Worker if (task_runner_->RunsTasksInCurrentSequence()) {
80*6777b538SAndroid Build Coastguard Worker // Enables socket watcher to send more frequent RTT observations when very
81*6777b538SAndroid Build Coastguard Worker // few sockets are receiving data.
82*6777b538SAndroid Build Coastguard Worker if (should_notify_rtt_callback_.Run(now))
83*6777b538SAndroid Build Coastguard Worker return true;
84*6777b538SAndroid Build Coastguard Worker }
85*6777b538SAndroid Build Coastguard Worker
86*6777b538SAndroid Build Coastguard Worker // Do not allow incoming notifications if the last notification was more
87*6777b538SAndroid Build Coastguard Worker // recent than |rtt_notifications_minimum_interval_| ago. This helps in
88*6777b538SAndroid Build Coastguard Worker // reducing the overhead of obtaining the RTT values.
89*6777b538SAndroid Build Coastguard Worker // Enables a socket watcher to send RTT observation, helps in reducing
90*6777b538SAndroid Build Coastguard Worker // starvation by allowing every socket watcher to notify at least one RTT
91*6777b538SAndroid Build Coastguard Worker // notification every |rtt_notifications_minimum_interval_| duration.
92*6777b538SAndroid Build Coastguard Worker return now - last_rtt_notification_ >= rtt_notifications_minimum_interval_;
93*6777b538SAndroid Build Coastguard Worker }
94*6777b538SAndroid Build Coastguard Worker
OnUpdatedRTTAvailable(const base::TimeDelta & rtt)95*6777b538SAndroid Build Coastguard Worker void SocketWatcher::OnUpdatedRTTAvailable(const base::TimeDelta& rtt) {
96*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
97*6777b538SAndroid Build Coastguard Worker
98*6777b538SAndroid Build Coastguard Worker // tcp_socket_posix may sometimes report RTT as 1 microsecond when the RTT was
99*6777b538SAndroid Build Coastguard Worker // actually invalid. See:
100*6777b538SAndroid Build Coastguard Worker // https://cs.chromium.org/chromium/src/net/socket/tcp_socket_posix.cc?rcl=7ad660e34f2a996e381a85b2a515263003b0c171&l=106.
101*6777b538SAndroid Build Coastguard Worker // Connections to private address eg localhost because they typically have
102*6777b538SAndroid Build Coastguard Worker // small rtt.
103*6777b538SAndroid Build Coastguard Worker if (!allow_rtt_private_address_ && rtt <= base::Microseconds(1)) {
104*6777b538SAndroid Build Coastguard Worker return;
105*6777b538SAndroid Build Coastguard Worker }
106*6777b538SAndroid Build Coastguard Worker
107*6777b538SAndroid Build Coastguard Worker if (!first_quic_rtt_notification_received_ &&
108*6777b538SAndroid Build Coastguard Worker protocol_ == SocketPerformanceWatcherFactory::PROTOCOL_QUIC) {
109*6777b538SAndroid Build Coastguard Worker // First RTT sample from QUIC connections may be synthetically generated,
110*6777b538SAndroid Build Coastguard Worker // and may not reflect the actual network quality.
111*6777b538SAndroid Build Coastguard Worker first_quic_rtt_notification_received_ = true;
112*6777b538SAndroid Build Coastguard Worker return;
113*6777b538SAndroid Build Coastguard Worker }
114*6777b538SAndroid Build Coastguard Worker
115*6777b538SAndroid Build Coastguard Worker last_rtt_notification_ = tick_clock_->NowTicks();
116*6777b538SAndroid Build Coastguard Worker task_runner_->PostTask(
117*6777b538SAndroid Build Coastguard Worker FROM_HERE,
118*6777b538SAndroid Build Coastguard Worker base::BindOnce(updated_rtt_observation_callback_, protocol_, rtt, host_));
119*6777b538SAndroid Build Coastguard Worker }
120*6777b538SAndroid Build Coastguard Worker
OnConnectionChanged()121*6777b538SAndroid Build Coastguard Worker void SocketWatcher::OnConnectionChanged() {
122*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
123*6777b538SAndroid Build Coastguard Worker }
124*6777b538SAndroid Build Coastguard Worker
125*6777b538SAndroid Build Coastguard Worker } // namespace net::nqe::internal
126