quic_connection_helper.cc revision a36e5920737c6adbddd3e43b760e5de8431db6e0
1// Copyright (c) 2012 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_connection_helper.h"
6
7#include "base/location.h"
8#include "base/logging.h"
9#include "base/task_runner.h"
10#include "base/time/time.h"
11#include "net/base/io_buffer.h"
12#include "net/base/net_errors.h"
13#include "net/quic/quic_utils.h"
14
15namespace net {
16
17QuicConnectionHelper::QuicConnectionHelper(base::TaskRunner* task_runner,
18                                           const QuicClock* clock,
19                                           QuicRandom* random_generator,
20                                           DatagramClientSocket* socket)
21    : weak_factory_(this),
22      task_runner_(task_runner),
23      socket_(socket),
24      clock_(clock),
25      random_generator_(random_generator),
26      send_alarm_registered_(false),
27      timeout_alarm_registered_(false),
28      retransmission_alarm_registered_(false),
29      retransmission_alarm_running_(false),
30      ack_alarm_registered_(false),
31      ack_alarm_time_(QuicTime::Zero()) {
32}
33
34QuicConnectionHelper::~QuicConnectionHelper() {
35}
36
37void QuicConnectionHelper::SetConnection(QuicConnection* connection) {
38  connection_ = connection;
39}
40
41const QuicClock* QuicConnectionHelper::GetClock() const {
42  return clock_;
43}
44
45QuicRandom* QuicConnectionHelper::GetRandomGenerator() {
46  return random_generator_;
47}
48
49int QuicConnectionHelper::WritePacketToWire(
50    const QuicEncryptedPacket& packet,
51    int* error) {
52  if (connection_->ShouldSimulateLostPacket()) {
53    DLOG(INFO) << "Dropping packet due to fake packet loss.";
54    *error = 0;
55    return packet.length();
56  }
57
58  scoped_refptr<StringIOBuffer> buf(
59      new StringIOBuffer(std::string(packet.data(),
60                                     packet.length())));
61  int rv = socket_->Write(buf.get(),
62                          packet.length(),
63                          base::Bind(&QuicConnectionHelper::OnWriteComplete,
64                                     weak_factory_.GetWeakPtr()));
65  if (rv >= 0) {
66    *error = 0;
67  } else {
68    *error = rv;
69    rv = -1;
70  }
71  return rv;
72}
73
74bool QuicConnectionHelper::IsWriteBlockedDataBuffered() {
75  // Chrome sockets' Write() methods buffer the data until the Write is
76  // permitted.
77  return true;
78}
79
80bool QuicConnectionHelper::IsWriteBlocked(int error) {
81  return error == ERR_IO_PENDING;
82}
83
84void QuicConnectionHelper::SetRetransmissionAlarm(QuicTime::Delta delay) {
85  if (!retransmission_alarm_registered_) {
86    task_runner_->PostDelayedTask(
87        FROM_HERE,
88        base::Bind(&QuicConnectionHelper::OnRetransmissionAlarm,
89                   weak_factory_.GetWeakPtr()),
90        base::TimeDelta::FromMicroseconds(delay.ToMicroseconds()));
91  }
92}
93
94void QuicConnectionHelper::SetAckAlarm(QuicTime::Delta delay) {
95  ack_alarm_time_ = clock_->Now().Add(delay);
96  if (!ack_alarm_registered_) {
97    task_runner_->PostDelayedTask(
98        FROM_HERE,
99        base::Bind(&QuicConnectionHelper::OnAckAlarm,
100                   weak_factory_.GetWeakPtr()),
101        base::TimeDelta::FromMicroseconds(delay.ToMicroseconds()));
102  }
103  ack_alarm_registered_ = true;
104}
105
106void QuicConnectionHelper::ClearAckAlarm() {
107  ack_alarm_time_ = QuicTime::Zero();
108}
109
110void QuicConnectionHelper::SetSendAlarm(QuicTime alarm_time) {
111  send_alarm_registered_ = true;
112  int64 delay_us = alarm_time.Subtract(clock_->Now()).ToMicroseconds();
113  if (delay_us < 0) {
114    delay_us = 0;
115  }
116  task_runner_->PostDelayedTask(
117      FROM_HERE,
118      base::Bind(&QuicConnectionHelper::OnSendAlarm,
119                 weak_factory_.GetWeakPtr()),
120      base::TimeDelta::FromMicroseconds(delay_us));
121}
122
123void QuicConnectionHelper::SetTimeoutAlarm(QuicTime::Delta delay) {
124  // CheckForTimeout will call SetTimeoutAlarm for the remaining time if alarm
125  // goes off before the delay.
126  if (timeout_alarm_registered_)
127    return;
128  timeout_alarm_registered_ = true;
129  task_runner_->PostDelayedTask(
130      FROM_HERE,
131      base::Bind(&QuicConnectionHelper::OnTimeoutAlarm,
132                 weak_factory_.GetWeakPtr()),
133      base::TimeDelta::FromMicroseconds(delay.ToMicroseconds()));
134}
135
136bool QuicConnectionHelper::IsSendAlarmSet() {
137  return send_alarm_registered_;
138}
139
140void QuicConnectionHelper::UnregisterSendAlarmIfRegistered() {
141  send_alarm_registered_ = false;
142}
143
144void QuicConnectionHelper::OnRetransmissionAlarm() {
145  QuicTime when = connection_->OnRetransmissionTimeout();
146  if (!when.IsInitialized()) {
147    return;
148  }
149  QuicTime now = clock_->Now();
150  QuicTime::Delta delta(when.Subtract(now));
151  if (delta < QuicTime::Delta::FromSeconds(0)) {
152    delta = QuicTime::Delta::FromSeconds(0);
153  }
154  SetRetransmissionAlarm(delta);
155}
156
157void QuicConnectionHelper::OnSendAlarm() {
158  if (send_alarm_registered_) {
159    send_alarm_registered_ = false;
160    connection_->OnCanWrite();
161  }
162}
163
164void QuicConnectionHelper::OnTimeoutAlarm() {
165  timeout_alarm_registered_ = false;
166  connection_->CheckForTimeout();
167}
168
169void QuicConnectionHelper::OnAckAlarm() {
170  ack_alarm_registered_ = false;
171  // Alarm may have been cleared.
172  if (!ack_alarm_time_.IsInitialized()) {
173    return;
174  }
175
176  // Alarm may have been reset to a later time.
177  QuicTime now = clock_->Now();
178  if (now < ack_alarm_time_) {
179    SetAckAlarm(ack_alarm_time_.Subtract(now));
180    return;
181  }
182
183  ack_alarm_time_ = QuicTime::Zero();
184  connection_->SendAck();
185}
186
187void QuicConnectionHelper::OnWriteComplete(int result) {
188  // TODO(rch): Inform the connection about the result.
189  connection_->OnCanWrite();
190}
191
192}  // namespace net
193