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