// Copyright (c) 2012 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_connection_helper.h" #include "base/location.h" #include "base/logging.h" #include "base/task_runner.h" #include "base/time/time.h" #include "net/base/io_buffer.h" #include "net/base/net_errors.h" #include "net/quic/quic_utils.h" namespace net { namespace { class QuicChromeAlarm : public QuicAlarm { public: QuicChromeAlarm(const QuicClock* clock, base::TaskRunner* task_runner, QuicAlarm::Delegate* delegate) : QuicAlarm(delegate), clock_(clock), task_runner_(task_runner), task_posted_(false), weak_factory_(this) {} protected: virtual void SetImpl() OVERRIDE { DCHECK(deadline().IsInitialized()); if (task_posted_) { // Since tasks can not be un-posted, OnAlarm will be invoked which // will notice that deadline has not yet been reached, and will set // the alarm for the new deadline. return; } int64 delay_us = deadline().Subtract(clock_->Now()).ToMicroseconds(); if (delay_us < 0) { delay_us = 0; } task_runner_->PostDelayedTask( FROM_HERE, base::Bind(&QuicChromeAlarm::OnAlarm, weak_factory_.GetWeakPtr()), base::TimeDelta::FromMicroseconds(delay_us)); task_posted_ = true; } virtual void CancelImpl() OVERRIDE { DCHECK(!deadline().IsInitialized()); // Since tasks can not be un-posted, OnAlarm will be invoked which // will notice that deadline is not Initialized and will do nothing. } private: void OnAlarm() { DCHECK(task_posted_); task_posted_ = false; // The alarm may have been cancelled. if (!deadline().IsInitialized()) { return; } // The alarm may have been re-set to a later time. if (clock_->Now() < deadline()) { SetImpl(); return; } Fire(); } const QuicClock* clock_; base::TaskRunner* task_runner_; bool task_posted_; base::WeakPtrFactory weak_factory_; }; } // namespace QuicConnectionHelper::QuicConnectionHelper(base::TaskRunner* task_runner, const QuicClock* clock, QuicRandom* random_generator, DatagramClientSocket* socket) : weak_factory_(this), task_runner_(task_runner), socket_(socket), clock_(clock), random_generator_(random_generator) { } QuicConnectionHelper::~QuicConnectionHelper() { } void QuicConnectionHelper::SetConnection(QuicConnection* connection) { connection_ = connection; } const QuicClock* QuicConnectionHelper::GetClock() const { return clock_; } QuicRandom* QuicConnectionHelper::GetRandomGenerator() { return random_generator_; } int QuicConnectionHelper::WritePacketToWire( const QuicEncryptedPacket& packet, int* error) { if (connection_->ShouldSimulateLostPacket()) { DLOG(INFO) << "Dropping packet due to fake packet loss."; *error = 0; return packet.length(); } scoped_refptr buf( new StringIOBuffer(std::string(packet.data(), packet.length()))); int rv = socket_->Write(buf.get(), packet.length(), base::Bind(&QuicConnectionHelper::OnWriteComplete, weak_factory_.GetWeakPtr())); if (rv >= 0) { *error = 0; } else { *error = rv; rv = -1; } return rv; } bool QuicConnectionHelper::IsWriteBlockedDataBuffered() { // Chrome sockets' Write() methods buffer the data until the Write is // permitted. return true; } bool QuicConnectionHelper::IsWriteBlocked(int error) { return error == ERR_IO_PENDING; } QuicAlarm* QuicConnectionHelper::CreateAlarm(QuicAlarm::Delegate* delegate) { return new QuicChromeAlarm(clock_, task_runner_, delegate); } void QuicConnectionHelper::OnWriteComplete(int result) { // TODO(rch): Inform the connection about the result. connection_->OnCanWrite(); } } // namespace net