1 // Copyright (c) 2015 The Chromium Authors. All rights reserved.
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/bind.h"
8 #include "base/location.h"
9 #include "base/metrics/histogram_macros.h"
10 #include "base/single_thread_task_runner.h"
11 #include "base/threading/thread_task_runner_handle.h"
12 #include "net/base/net_errors.h"
13 #include "net/quic/address_utils.h"
14 #include "net/third_party/quiche/src/quic/core/quic_clock.h"
15 
16 namespace net {
17 
QuicChromiumPacketReader(DatagramClientSocket * socket,const quic::QuicClock * clock,Visitor * visitor,int yield_after_packets,quic::QuicTime::Delta yield_after_duration,const NetLogWithSource & net_log)18 QuicChromiumPacketReader::QuicChromiumPacketReader(
19     DatagramClientSocket* socket,
20     const quic::QuicClock* clock,
21     Visitor* visitor,
22     int yield_after_packets,
23     quic::QuicTime::Delta yield_after_duration,
24     const NetLogWithSource& net_log)
25     : socket_(socket),
26       visitor_(visitor),
27       read_pending_(false),
28       num_packets_read_(0),
29       clock_(clock),
30       yield_after_packets_(yield_after_packets),
31       yield_after_duration_(yield_after_duration),
32       yield_after_(quic::QuicTime::Infinite()),
33       read_buffer_(base::MakeRefCounted<IOBufferWithSize>(
34           static_cast<size_t>(quic::kMaxIncomingPacketSize))),
35       net_log_(net_log) {}
36 
~QuicChromiumPacketReader()37 QuicChromiumPacketReader::~QuicChromiumPacketReader() {}
38 
StartReading()39 void QuicChromiumPacketReader::StartReading() {
40   for (;;) {
41     if (read_pending_)
42       return;
43 
44     if (num_packets_read_ == 0)
45       yield_after_ = clock_->Now() + yield_after_duration_;
46 
47     CHECK(socket_);
48     read_pending_ = true;
49     int rv =
50         socket_->Read(read_buffer_.get(), read_buffer_->size(),
51                       base::BindOnce(&QuicChromiumPacketReader::OnReadComplete,
52                                      weak_factory_.GetWeakPtr()));
53     UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.AsyncRead", rv == ERR_IO_PENDING);
54     if (rv == ERR_IO_PENDING) {
55       num_packets_read_ = 0;
56       return;
57     }
58 
59     if (++num_packets_read_ > yield_after_packets_ ||
60         clock_->Now() > yield_after_) {
61       num_packets_read_ = 0;
62       // Data was read, process it.
63       // Schedule the work through the message loop to 1) prevent infinite
64       // recursion and 2) avoid blocking the thread for too long.
65       base::ThreadTaskRunnerHandle::Get()->PostTask(
66           FROM_HERE, base::BindOnce(&QuicChromiumPacketReader::OnReadComplete,
67                                     weak_factory_.GetWeakPtr(), rv));
68     } else {
69       if (!ProcessReadResult(rv)) {
70         return;
71       }
72     }
73   }
74 }
75 
EstimateMemoryUsage() const76 size_t QuicChromiumPacketReader::EstimateMemoryUsage() const {
77   return read_buffer_->size();
78 }
79 
ProcessReadResult(int result)80 bool QuicChromiumPacketReader::ProcessReadResult(int result) {
81   read_pending_ = false;
82   if (result == 0)
83     result = ERR_CONNECTION_CLOSED;
84 
85   if (result < 0) {
86     visitor_->OnReadError(result, socket_);
87     return false;
88   }
89 
90   quic::QuicReceivedPacket packet(read_buffer_->data(), result, clock_->Now());
91   IPEndPoint local_address;
92   IPEndPoint peer_address;
93   socket_->GetLocalAddress(&local_address);
94   socket_->GetPeerAddress(&peer_address);
95   auto self = weak_factory_.GetWeakPtr();
96   // Notifies the visitor that |this| reader gets a new packet, which may delete
97   // |this| if |this| is a connectivity probing reader.
98   return visitor_->OnPacket(packet, ToQuicSocketAddress(local_address),
99                             ToQuicSocketAddress(peer_address)) &&
100          self;
101 }
102 
OnReadComplete(int result)103 void QuicChromiumPacketReader::OnReadComplete(int result) {
104   if (ProcessReadResult(result))
105     StartReading();
106 }
107 
108 }  // namespace net
109