|  | // Copyright (c) 2015 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "net/quic/quic_chromium_packet_reader.h" | 
|  |  | 
|  | #include "base/bind.h" | 
|  | #include "base/location.h" | 
|  | #include "base/metrics/histogram_macros.h" | 
|  | #include "base/single_thread_task_runner.h" | 
|  | #include "base/threading/thread_task_runner_handle.h" | 
|  | #include "net/base/net_errors.h" | 
|  | #include "net/third_party/quic/platform/api/quic_clock.h" | 
|  |  | 
|  | namespace net { | 
|  |  | 
|  | QuicChromiumPacketReader::QuicChromiumPacketReader( | 
|  | DatagramClientSocket* socket, | 
|  | quic::QuicClock* clock, | 
|  | Visitor* visitor, | 
|  | int yield_after_packets, | 
|  | quic::QuicTime::Delta yield_after_duration, | 
|  | const NetLogWithSource& net_log) | 
|  | : socket_(socket), | 
|  | visitor_(visitor), | 
|  | read_pending_(false), | 
|  | num_packets_read_(0), | 
|  | clock_(clock), | 
|  | yield_after_packets_(yield_after_packets), | 
|  | yield_after_duration_(yield_after_duration), | 
|  | yield_after_(quic::QuicTime::Infinite()), | 
|  | read_buffer_(base::MakeRefCounted<IOBufferWithSize>( | 
|  | static_cast<size_t>(quic::kMaxPacketSize))), | 
|  | net_log_(net_log), | 
|  | weak_factory_(this) {} | 
|  |  | 
|  | QuicChromiumPacketReader::~QuicChromiumPacketReader() {} | 
|  |  | 
|  | void QuicChromiumPacketReader::StartReading() { | 
|  | for (;;) { | 
|  | if (read_pending_) | 
|  | return; | 
|  |  | 
|  | if (num_packets_read_ == 0) | 
|  | yield_after_ = clock_->Now() + yield_after_duration_; | 
|  |  | 
|  | DCHECK(socket_); | 
|  | read_pending_ = true; | 
|  | int rv = | 
|  | socket_->Read(read_buffer_.get(), read_buffer_->size(), | 
|  | base::BindOnce(&QuicChromiumPacketReader::OnReadComplete, | 
|  | weak_factory_.GetWeakPtr())); | 
|  | UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.AsyncRead", rv == ERR_IO_PENDING); | 
|  | if (rv == ERR_IO_PENDING) { | 
|  | num_packets_read_ = 0; | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (++num_packets_read_ > yield_after_packets_ || | 
|  | clock_->Now() > yield_after_) { | 
|  | num_packets_read_ = 0; | 
|  | // Data was read, process it. | 
|  | // Schedule the work through the message loop to 1) prevent infinite | 
|  | // recursion and 2) avoid blocking the thread for too long. | 
|  | base::ThreadTaskRunnerHandle::Get()->PostTask( | 
|  | FROM_HERE, base::BindOnce(&QuicChromiumPacketReader::OnReadComplete, | 
|  | weak_factory_.GetWeakPtr(), rv)); | 
|  | } else { | 
|  | if (!ProcessReadResult(rv)) { | 
|  | return; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | size_t QuicChromiumPacketReader::EstimateMemoryUsage() const { | 
|  | // Return the size of |read_buffer_|. | 
|  | return quic::kMaxPacketSize; | 
|  | } | 
|  |  | 
|  | bool QuicChromiumPacketReader::ProcessReadResult(int result) { | 
|  | read_pending_ = false; | 
|  | if (result == 0) | 
|  | result = ERR_CONNECTION_CLOSED; | 
|  |  | 
|  | if (result < 0) { | 
|  | visitor_->OnReadError(result, socket_); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | quic::QuicReceivedPacket packet(read_buffer_->data(), result, clock_->Now()); | 
|  | IPEndPoint local_address; | 
|  | IPEndPoint peer_address; | 
|  | socket_->GetLocalAddress(&local_address); | 
|  | socket_->GetPeerAddress(&peer_address); | 
|  | return visitor_->OnPacket( | 
|  | packet, | 
|  | quic::QuicSocketAddress(quic::QuicSocketAddressImpl(local_address)), | 
|  | quic::QuicSocketAddress(quic::QuicSocketAddressImpl(peer_address))); | 
|  | } | 
|  |  | 
|  | void QuicChromiumPacketReader::OnReadComplete(int result) { | 
|  | if (ProcessReadResult(result)) { | 
|  | StartReading(); | 
|  | } | 
|  | } | 
|  |  | 
|  | }  // namespace net |