xref: /aosp_15_r20/external/cronet/net/quic/quic_chromium_packet_reader.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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,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     const NetLogWithSource& net_log)
33     : socket_(std::move(socket)),
34       visitor_(visitor),
35       clock_(clock),
36       yield_after_packets_(yield_after_packets),
37       yield_after_duration_(yield_after_duration),
38       yield_after_(quic::QuicTime::Infinite()),
39       read_buffer_(base::MakeRefCounted<IOBufferWithSize>(kReadBufferSize)),
40       net_log_(net_log),
41       report_ecn_(base::FeatureList::IsEnabled(net::features::kReceiveEcn)) {}
42 
43 QuicChromiumPacketReader::~QuicChromiumPacketReader() = default;
44 
StartReading()45 void QuicChromiumPacketReader::StartReading() {
46   for (;;) {
47     if (read_pending_)
48       return;
49 
50     if (num_packets_read_ == 0)
51       yield_after_ = clock_->Now() + yield_after_duration_;
52 
53     CHECK(socket_);
54     read_pending_ = true;
55     int rv =
56         socket_->Read(read_buffer_.get(), read_buffer_->size(),
57                       base::BindOnce(&QuicChromiumPacketReader::OnReadComplete,
58                                      weak_factory_.GetWeakPtr()));
59     UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.AsyncRead", rv == ERR_IO_PENDING);
60     if (rv == ERR_IO_PENDING) {
61       num_packets_read_ = 0;
62       return;
63     }
64 
65     if (++num_packets_read_ > yield_after_packets_ ||
66         clock_->Now() > yield_after_) {
67       num_packets_read_ = 0;
68       // Data was read, process it.
69       // Schedule the work through the message loop to 1) prevent infinite
70       // recursion and 2) avoid blocking the thread for too long.
71       base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
72           FROM_HERE, base::BindOnce(&QuicChromiumPacketReader::OnReadComplete,
73                                     weak_factory_.GetWeakPtr(), rv));
74     } else {
75       if (!ProcessReadResult(rv)) {
76         return;
77       }
78     }
79   }
80 }
81 
CloseSocket()82 void QuicChromiumPacketReader::CloseSocket() {
83   socket_->Close();
84 }
85 
86 static_assert(static_cast<EcnCodePoint>(quic::ECN_NOT_ECT) == ECN_NOT_ECT &&
87                   static_cast<EcnCodePoint>(quic::ECN_ECT1) == ECN_ECT1 &&
88                   static_cast<EcnCodePoint>(quic::ECN_ECT0) == ECN_ECT0 &&
89                   static_cast<EcnCodePoint>(quic::ECN_CE) == ECN_CE,
90               "Mismatch ECN codepoint values");
ProcessReadResult(int result)91 bool QuicChromiumPacketReader::ProcessReadResult(int result) {
92   read_pending_ = false;
93   if (result <= 0 && net_log_.IsCapturing()) {
94     net_log_.AddEventWithIntParams(NetLogEventType::QUIC_READ_ERROR,
95                                    "net_error", result);
96   }
97   if (result == 0) {
98     // 0-length UDP packets are legal but useless, ignore them.
99     return true;
100   }
101   if (result == ERR_MSG_TOO_BIG) {
102     // This indicates that we received a UDP packet larger than our receive
103     // buffer, ignore it.
104     return true;
105   }
106   if (result < 0) {
107     // Report all other errors to the visitor.
108     return visitor_->OnReadError(result, socket_.get());
109   }
110 
111   quic::QuicEcnCodepoint ecn = quic::ECN_NOT_ECT;
112   if (report_ecn_) {
113     DscpAndEcn tos = socket_->GetLastTos();
114     ecn = static_cast<quic::QuicEcnCodepoint>(tos.ecn);
115   }
116   quic::QuicReceivedPacket packet(read_buffer_->data(), result, clock_->Now(),
117                                   /*owns_buffer=*/false, /*ttl=*/0,
118                                   /*ttl_valid=*/true,
119                                   /*packet_headers=*/nullptr,
120                                   /*headers_length=*/0,
121                                   /*owns_header_buffer=*/false, ecn);
122   IPEndPoint local_address;
123   IPEndPoint peer_address;
124   socket_->GetLocalAddress(&local_address);
125   socket_->GetPeerAddress(&peer_address);
126   auto self = weak_factory_.GetWeakPtr();
127   // Notifies the visitor that |this| reader gets a new packet, which may delete
128   // |this| if |this| is a connectivity probing reader.
129   return visitor_->OnPacket(packet, ToQuicSocketAddress(local_address),
130                             ToQuicSocketAddress(peer_address)) &&
131          self;
132 }
133 
OnReadComplete(int result)134 void QuicChromiumPacketReader::OnReadComplete(int result) {
135   if (ProcessReadResult(result)) {
136     StartReading();
137   }
138 }
139 
140 }  // namespace net
141