1 // Copyright 2015 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/quic/quic_chromium_packet_reader.h"
6
7 #include "base/functional/bind.h"
8 #include "base/location.h"
9 #include "base/metrics/histogram_macros.h"
10 #include "base/task/single_thread_task_runner.h"
11 #include "net/base/features.h"
12 #include "net/base/net_errors.h"
13 #include "net/quic/address_utils.h"
14 #include "net/third_party/quiche/src/quiche/quic/core/quic_clock.h"
15 #include "net/third_party/quiche/src/quiche/quic/core/quic_types.h"
16
17 namespace net {
18
19 namespace {
20 // Add 1 because some of our UDP socket implementations do not read successfully
21 // when the packet length is equal to the read buffer size.
22 const size_t kReadBufferSize =
23 static_cast<size_t>(quic::kMaxIncomingPacketSize + 1);
24 } // namespace
25
QuicChromiumPacketReader(std::unique_ptr<DatagramClientSocket> socket,const quic::QuicClock * clock,Visitor * visitor,int yield_after_packets,quic::QuicTime::Delta yield_after_duration,bool report_ecn,const NetLogWithSource & net_log)26 QuicChromiumPacketReader::QuicChromiumPacketReader(
27 std::unique_ptr<DatagramClientSocket> socket,
28 const quic::QuicClock* clock,
29 Visitor* visitor,
30 int yield_after_packets,
31 quic::QuicTime::Delta yield_after_duration,
32 bool report_ecn,
33 const NetLogWithSource& net_log)
34 : socket_(std::move(socket)),
35 visitor_(visitor),
36 clock_(clock),
37 yield_after_packets_(yield_after_packets),
38 yield_after_duration_(yield_after_duration),
39 yield_after_(quic::QuicTime::Infinite()),
40 read_buffer_(base::MakeRefCounted<IOBufferWithSize>(kReadBufferSize)),
41 net_log_(net_log),
42 report_ecn_(report_ecn) {}
43
44 QuicChromiumPacketReader::~QuicChromiumPacketReader() = default;
45
StartReading()46 void QuicChromiumPacketReader::StartReading() {
47 for (;;) {
48 if (read_pending_)
49 return;
50
51 if (num_packets_read_ == 0)
52 yield_after_ = clock_->Now() + yield_after_duration_;
53
54 CHECK(socket_);
55 read_pending_ = true;
56 int rv =
57 socket_->Read(read_buffer_.get(), read_buffer_->size(),
58 base::BindOnce(&QuicChromiumPacketReader::OnReadComplete,
59 weak_factory_.GetWeakPtr()));
60 UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.AsyncRead", rv == ERR_IO_PENDING);
61 if (rv == ERR_IO_PENDING) {
62 num_packets_read_ = 0;
63 return;
64 }
65
66 if (++num_packets_read_ > yield_after_packets_ ||
67 clock_->Now() > yield_after_) {
68 num_packets_read_ = 0;
69 // Data was read, process it.
70 // Schedule the work through the message loop to 1) prevent infinite
71 // recursion and 2) avoid blocking the thread for too long.
72 base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
73 FROM_HERE, base::BindOnce(&QuicChromiumPacketReader::OnReadComplete,
74 weak_factory_.GetWeakPtr(), rv));
75 } else {
76 if (!ProcessReadResult(rv)) {
77 return;
78 }
79 }
80 }
81 }
82
CloseSocket()83 void QuicChromiumPacketReader::CloseSocket() {
84 socket_->Close();
85 }
86
87 static_assert(static_cast<EcnCodePoint>(quic::ECN_NOT_ECT) == ECN_NOT_ECT &&
88 static_cast<EcnCodePoint>(quic::ECN_ECT1) == ECN_ECT1 &&
89 static_cast<EcnCodePoint>(quic::ECN_ECT0) == ECN_ECT0 &&
90 static_cast<EcnCodePoint>(quic::ECN_CE) == ECN_CE,
91 "Mismatch ECN codepoint values");
ProcessReadResult(int result)92 bool QuicChromiumPacketReader::ProcessReadResult(int result) {
93 read_pending_ = false;
94 if (result <= 0 && net_log_.IsCapturing()) {
95 net_log_.AddEventWithIntParams(NetLogEventType::QUIC_READ_ERROR,
96 "net_error", result);
97 }
98 if (result == 0) {
99 // 0-length UDP packets are legal but useless, ignore them.
100 return true;
101 }
102 if (result == ERR_MSG_TOO_BIG) {
103 // This indicates that we received a UDP packet larger than our receive
104 // buffer, ignore it.
105 return true;
106 }
107 if (result < 0) {
108 // Report all other errors to the visitor.
109 return visitor_->OnReadError(result, socket_.get());
110 }
111
112 quic::QuicEcnCodepoint ecn = quic::ECN_NOT_ECT;
113 if (report_ecn_) {
114 DscpAndEcn tos = socket_->GetLastTos();
115 ecn = static_cast<quic::QuicEcnCodepoint>(tos.ecn);
116 }
117 quic::QuicReceivedPacket packet(read_buffer_->data(), result, clock_->Now(),
118 /*owns_buffer=*/false, /*ttl=*/0,
119 /*ttl_valid=*/true,
120 /*packet_headers=*/nullptr,
121 /*headers_length=*/0,
122 /*owns_header_buffer=*/false, ecn);
123 IPEndPoint local_address;
124 IPEndPoint peer_address;
125 socket_->GetLocalAddress(&local_address);
126 socket_->GetPeerAddress(&peer_address);
127 auto self = weak_factory_.GetWeakPtr();
128 // Notifies the visitor that |this| reader gets a new packet, which may delete
129 // |this| if |this| is a connectivity probing reader.
130 return visitor_->OnPacket(packet, ToQuicSocketAddress(local_address),
131 ToQuicSocketAddress(peer_address)) &&
132 self;
133 }
134
OnReadComplete(int result)135 void QuicChromiumPacketReader::OnReadComplete(int result) {
136 if (ProcessReadResult(result)) {
137 StartReading();
138 }
139 }
140
141 } // namespace net
142