• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/net_errors.h"
12 #include "net/quic/address_utils.h"
13 #include "net/third_party/quiche/src/quiche/quic/core/quic_clock.h"
14 
15 namespace net {
16 
17 namespace {
18 // Add 1 because some of our UDP socket implementations do not read successfully
19 // when the packet length is equal to the read buffer size.
20 const size_t kReadBufferSize =
21     static_cast<size_t>(quic::kMaxIncomingPacketSize + 1);
22 }  // namespace
23 
QuicChromiumPacketReader(DatagramClientSocket * socket,const quic::QuicClock * clock,Visitor * visitor,int yield_after_packets,quic::QuicTime::Delta yield_after_duration,const NetLogWithSource & net_log)24 QuicChromiumPacketReader::QuicChromiumPacketReader(
25     DatagramClientSocket* socket,
26     const quic::QuicClock* clock,
27     Visitor* visitor,
28     int yield_after_packets,
29     quic::QuicTime::Delta yield_after_duration,
30     const NetLogWithSource& net_log)
31     : socket_(socket),
32       visitor_(visitor),
33       clock_(clock),
34       yield_after_packets_(yield_after_packets),
35       yield_after_duration_(yield_after_duration),
36       yield_after_(quic::QuicTime::Infinite()),
37       read_buffer_(base::MakeRefCounted<IOBufferWithSize>(kReadBufferSize)),
38       net_log_(net_log) {}
39 
40 QuicChromiumPacketReader::~QuicChromiumPacketReader() = default;
41 
StartReading()42 void QuicChromiumPacketReader::StartReading() {
43   for (;;) {
44     if (read_pending_)
45       return;
46 
47     if (num_packets_read_ == 0)
48       yield_after_ = clock_->Now() + yield_after_duration_;
49 
50     CHECK(socket_);
51     read_pending_ = true;
52     int rv =
53         socket_->Read(read_buffer_.get(), read_buffer_->size(),
54                       base::BindOnce(&QuicChromiumPacketReader::OnReadComplete,
55                                      weak_factory_.GetWeakPtr()));
56     UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.AsyncRead", rv == ERR_IO_PENDING);
57     if (rv == ERR_IO_PENDING) {
58       num_packets_read_ = 0;
59       return;
60     }
61 
62     if (++num_packets_read_ > yield_after_packets_ ||
63         clock_->Now() > yield_after_) {
64       num_packets_read_ = 0;
65       // Data was read, process it.
66       // Schedule the work through the message loop to 1) prevent infinite
67       // recursion and 2) avoid blocking the thread for too long.
68       base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
69           FROM_HERE, base::BindOnce(&QuicChromiumPacketReader::OnReadComplete,
70                                     weak_factory_.GetWeakPtr(), rv));
71     } else {
72       if (!ProcessReadResult(rv)) {
73         return;
74       }
75     }
76   }
77 }
78 
ProcessReadResult(int result)79 bool QuicChromiumPacketReader::ProcessReadResult(int result) {
80   read_pending_ = false;
81   if (result <= 0 && net_log_.IsCapturing()) {
82     net_log_.AddEventWithIntParams(NetLogEventType::QUIC_READ_ERROR,
83                                    "net_error", result);
84   }
85   if (result == 0) {
86     // 0-length UDP packets are legal but useless, ignore them.
87     return true;
88   }
89   if (result == ERR_MSG_TOO_BIG) {
90     // This indicates that we received a UDP packet larger than our receive
91     // buffer, ignore it.
92     return true;
93   }
94   if (result < 0) {
95     // Report all other errors to the visitor.
96     return visitor_->OnReadError(result, socket_);
97   }
98 
99   quic::QuicReceivedPacket packet(read_buffer_->data(), result, clock_->Now());
100   IPEndPoint local_address;
101   IPEndPoint peer_address;
102   socket_->GetLocalAddress(&local_address);
103   socket_->GetPeerAddress(&peer_address);
104   auto self = weak_factory_.GetWeakPtr();
105   // Notifies the visitor that |this| reader gets a new packet, which may delete
106   // |this| if |this| is a connectivity probing reader.
107   return visitor_->OnPacket(packet, ToQuicSocketAddress(local_address),
108                             ToQuicSocketAddress(peer_address)) &&
109          self;
110 }
111 
OnReadComplete(int result)112 void QuicChromiumPacketReader::OnReadComplete(int result) {
113   if (ProcessReadResult(result))
114     StartReading();
115 }
116 
117 }  // namespace net
118