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 absl::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 run_rtt_callback_(allow_rtt_private_address ||
61 address.IsPubliclyRoutable()),
62 tick_clock_(tick_clock),
63 host_(CalculateIPHash(address)) {
64 DCHECK(tick_clock_);
65 DCHECK(last_rtt_notification_.is_null());
66 }
67
68 SocketWatcher::~SocketWatcher() = default;
69
ShouldNotifyUpdatedRTT() const70 bool SocketWatcher::ShouldNotifyUpdatedRTT() const {
71 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
72
73 if (!run_rtt_callback_)
74 return false;
75
76 const base::TimeTicks now = tick_clock_->NowTicks();
77
78 if (task_runner_->RunsTasksInCurrentSequence()) {
79 // Enables socket watcher to send more frequent RTT observations when very
80 // few sockets are receiving data.
81 if (should_notify_rtt_callback_.Run(now))
82 return true;
83 }
84
85 // Do not allow incoming notifications if the last notification was more
86 // recent than |rtt_notifications_minimum_interval_| ago. This helps in
87 // reducing the overhead of obtaining the RTT values.
88 // Enables a socket watcher to send RTT observation, helps in reducing
89 // starvation by allowing every socket watcher to notify at least one RTT
90 // notification every |rtt_notifications_minimum_interval_| duration.
91 return now - last_rtt_notification_ >= rtt_notifications_minimum_interval_;
92 }
93
OnUpdatedRTTAvailable(const base::TimeDelta & rtt)94 void SocketWatcher::OnUpdatedRTTAvailable(const base::TimeDelta& rtt) {
95 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
96
97 // tcp_socket_posix may sometimes report RTT as 1 microsecond when the RTT was
98 // actually invalid. See:
99 // https://cs.chromium.org/chromium/src/net/socket/tcp_socket_posix.cc?rcl=7ad660e34f2a996e381a85b2a515263003b0c171&l=106.
100 if (rtt <= base::Microseconds(1))
101 return;
102
103 if (!first_quic_rtt_notification_received_ &&
104 protocol_ == SocketPerformanceWatcherFactory::PROTOCOL_QUIC) {
105 // First RTT sample from QUIC connections may be synthetically generated,
106 // and may not reflect the actual network quality.
107 first_quic_rtt_notification_received_ = true;
108 return;
109 }
110
111 last_rtt_notification_ = tick_clock_->NowTicks();
112 task_runner_->PostTask(
113 FROM_HERE,
114 base::BindOnce(updated_rtt_observation_callback_, protocol_, rtt, host_));
115 }
116
OnConnectionChanged()117 void SocketWatcher::OnConnectionChanged() {
118 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
119 }
120
121 } // namespace net::nqe::internal
122