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