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/metrics/sparse_histogram.h"
10#include "base/task_runner.h"
11#include "base/time/time.h"
12#include "net/base/io_buffer.h"
13#include "net/base/net_errors.h"
14#include "net/quic/quic_utils.h"
15
16namespace net {
17
18namespace {
19
20class QuicChromeAlarm : public QuicAlarm {
21 public:
22  QuicChromeAlarm(const QuicClock* clock,
23                  base::TaskRunner* task_runner,
24                  QuicAlarm::Delegate* delegate)
25      : QuicAlarm(delegate),
26        clock_(clock),
27        task_runner_(task_runner),
28        task_deadline_(QuicTime::Zero()),
29        weak_factory_(this) {}
30
31 protected:
32  virtual void SetImpl() OVERRIDE {
33    DCHECK(deadline().IsInitialized());
34    if (task_deadline_.IsInitialized()) {
35      if (task_deadline_ <= deadline()) {
36        // Since tasks can not be un-posted, OnAlarm will be invoked which
37        // will notice that deadline has not yet been reached, and will set
38        // the alarm for the new deadline.
39        return;
40      }
41      // The scheduled task is after new deadline.  Invalidate the weak ptrs
42      // so that task does not execute when we're not expecting it.
43      weak_factory_.InvalidateWeakPtrs();
44    }
45
46    int64 delay_us = deadline().Subtract(clock_->Now()).ToMicroseconds();
47    if (delay_us < 0) {
48      delay_us = 0;
49    }
50    task_runner_->PostDelayedTask(
51        FROM_HERE,
52        base::Bind(&QuicChromeAlarm::OnAlarm, weak_factory_.GetWeakPtr()),
53        base::TimeDelta::FromMicroseconds(delay_us));
54    task_deadline_ = deadline();
55  }
56
57  virtual void CancelImpl() OVERRIDE {
58    DCHECK(!deadline().IsInitialized());
59    // Since tasks can not be un-posted, OnAlarm will be invoked which
60    // will notice that deadline is not Initialized and will do nothing.
61  }
62
63 private:
64  void OnAlarm() {
65    DCHECK(task_deadline_.IsInitialized());
66    task_deadline_ = QuicTime::Zero();
67    // The alarm may have been cancelled.
68    if (!deadline().IsInitialized()) {
69      return;
70    }
71
72    // The alarm may have been re-set to a later time.
73    if (clock_->Now() < deadline()) {
74      SetImpl();
75      return;
76    }
77
78    Fire();
79  }
80
81  const QuicClock* clock_;
82  base::TaskRunner* task_runner_;
83  // If a task has been posted to the message loop, this is the time it
84  // was scheduled to fire.  Tracking this allows us to avoid posting a
85  // new tast if the new deadline is in the future, but permits us to
86  // post a new task when the new deadline now earlier than when
87  // previously posted.
88  QuicTime task_deadline_;
89  base::WeakPtrFactory<QuicChromeAlarm> weak_factory_;
90};
91
92}  // namespace
93
94QuicConnectionHelper::QuicConnectionHelper(base::TaskRunner* task_runner,
95                                           const QuicClock* clock,
96                                           QuicRandom* random_generator)
97    : task_runner_(task_runner),
98      clock_(clock),
99      random_generator_(random_generator),
100      weak_factory_(this) {
101}
102
103QuicConnectionHelper::~QuicConnectionHelper() {
104}
105
106const QuicClock* QuicConnectionHelper::GetClock() const {
107  return clock_;
108}
109
110QuicRandom* QuicConnectionHelper::GetRandomGenerator() {
111  return random_generator_;
112}
113
114QuicAlarm* QuicConnectionHelper::CreateAlarm(QuicAlarm::Delegate* delegate) {
115  return new QuicChromeAlarm(clock_, task_runner_, delegate);
116}
117
118}  // namespace net
119