Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / net / quic / quic_flow_controller.cc
1 // Copyright 2014 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_flow_controller.h"
6
7 #include "base/basictypes.h"
8 #include "net/quic/quic_connection.h"
9 #include "net/quic/quic_flags.h"
10 #include "net/quic/quic_protocol.h"
11
12 namespace net {
13
14 #define ENDPOINT (is_server_ ? "Server: " : " Client: ")
15
16 QuicFlowController::QuicFlowController(QuicVersion version,
17                                        QuicStreamId id,
18                                        bool is_server,
19                                        uint64 send_window_offset,
20                                        uint64 receive_window_offset,
21                                        uint64 max_receive_window)
22       : id_(id),
23         is_enabled_(true),
24         is_server_(is_server),
25         bytes_consumed_(0),
26         bytes_buffered_(0),
27         bytes_sent_(0),
28         send_window_offset_(send_window_offset),
29         receive_window_offset_(receive_window_offset),
30         max_receive_window_(max_receive_window),
31         last_blocked_send_window_offset_(0) {
32   DVLOG(1) << ENDPOINT << "Created flow controller for stream " << id_
33            << ", setting initial receive window offset to: "
34            << receive_window_offset_
35            << ", max receive window to: "
36            << max_receive_window_
37            << ", setting send window offset to: " << send_window_offset_;
38   if (version < QUIC_VERSION_17) {
39     DVLOG(1) << ENDPOINT << "Disabling QuicFlowController for stream " << id_
40              << ", QUIC version " << version;
41     Disable();
42   }
43 }
44
45 void QuicFlowController::AddBytesConsumed(uint64 bytes_consumed) {
46   if (!IsEnabled()) {
47     return;
48   }
49
50   bytes_consumed_ += bytes_consumed;
51   DVLOG(1) << ENDPOINT << "Stream " << id_ << " consumed: " << bytes_consumed_;
52 }
53
54 void QuicFlowController::AddBytesBuffered(uint64 bytes_buffered) {
55   if (!IsEnabled()) {
56     return;
57   }
58
59   bytes_buffered_ += bytes_buffered;
60   DVLOG(1) << ENDPOINT << "Stream " << id_ << " buffered: " << bytes_buffered_;
61 }
62
63 void QuicFlowController::RemoveBytesBuffered(uint64 bytes_buffered) {
64   if (!IsEnabled()) {
65     return;
66   }
67
68   if (bytes_buffered_ < bytes_buffered) {
69     LOG(DFATAL) << "Trying to remove " << bytes_buffered << " bytes, when only "
70                 << bytes_buffered_ << " bytes are buffered";
71     bytes_buffered_ = 0;
72     return;
73   }
74
75   bytes_buffered_ -= bytes_buffered;
76   DVLOG(1) << ENDPOINT << "Stream " << id_ << " buffered: " << bytes_buffered_;
77 }
78
79 void QuicFlowController::AddBytesSent(uint64 bytes_sent) {
80   if (!IsEnabled()) {
81     return;
82   }
83
84   if (bytes_sent_ + bytes_sent > send_window_offset_) {
85     LOG(DFATAL) << ENDPOINT << "Stream " << id_ << " Trying to send an extra "
86                 << bytes_sent << " bytes, when bytes_sent = " << bytes_sent_
87                 << ", and send_window_offset_ = " << send_window_offset_;
88     bytes_sent_ = send_window_offset_;
89     return;
90   }
91
92   bytes_sent_ += bytes_sent;
93   DVLOG(1) << ENDPOINT << "Stream " << id_ << " sent: " << bytes_sent_;
94 }
95
96 bool QuicFlowController::FlowControlViolation() {
97   if (!IsEnabled()) {
98     return false;
99   }
100
101   if (receive_window_offset_ < TotalReceivedBytes()) {
102     LOG(ERROR)
103         << ENDPOINT << "Flow control violation on stream " << id_
104         << ", receive window: " << receive_window_offset_
105         << ", bytes received: " << TotalReceivedBytes();
106
107     return true;
108   }
109   return false;
110 }
111
112 void QuicFlowController::MaybeSendWindowUpdate(QuicConnection* connection) {
113   if (!IsEnabled()) {
114     return;
115   }
116
117   // Send WindowUpdate to increase receive window if
118   // (receive window offset - consumed bytes) < (max window / 2).
119   // This is behaviour copied from SPDY.
120   size_t consumed_window = receive_window_offset_ - bytes_consumed_;
121   size_t threshold = (max_receive_window_ / 2);
122
123   if (consumed_window < threshold) {
124     // Update our receive window.
125     receive_window_offset_ += (max_receive_window_ - consumed_window);
126
127     DVLOG(1) << ENDPOINT << "Sending WindowUpdate frame for stream " << id_
128              << ", consumed bytes: " << bytes_consumed_
129              << ", consumed window: " << consumed_window
130              << ", and threshold: " << threshold
131              << ", and max recvw: " << max_receive_window_
132              << ". New receive window offset is: " << receive_window_offset_;
133
134     // Inform the peer of our new receive window.
135     connection->SendWindowUpdate(id_, receive_window_offset_);
136   }
137 }
138
139 void QuicFlowController::MaybeSendBlocked(QuicConnection* connection) {
140   if (!IsEnabled()) {
141     return;
142   }
143
144   if (SendWindowSize() == 0 &&
145       last_blocked_send_window_offset_ < send_window_offset_) {
146     DVLOG(1) << ENDPOINT << "Stream " << id_ << " is flow control blocked. "
147              << "Send window: " << SendWindowSize()
148              << ", bytes sent: " << bytes_sent_
149              << ", send limit: " << send_window_offset_;
150     // The entire send_window has been consumed, we are now flow control
151     // blocked.
152     connection->SendBlocked(id_);
153
154     // Keep track of when we last sent a BLOCKED frame so that we only send one
155     // at a given send offset.
156     last_blocked_send_window_offset_ = send_window_offset_;
157   }
158 }
159
160 bool QuicFlowController::UpdateSendWindowOffset(uint64 new_send_window_offset) {
161   if (!IsEnabled()) {
162     return false;
163   }
164
165   // Only update if send window has increased.
166   if (new_send_window_offset <= send_window_offset_) {
167     return false;
168   }
169
170   DVLOG(1) << ENDPOINT << "UpdateSendWindowOffset for stream " << id_
171            << " with new offset " << new_send_window_offset
172            << " , current offset: " << send_window_offset_;
173
174   send_window_offset_ = new_send_window_offset;
175   return true;
176 }
177
178 void QuicFlowController::Disable() {
179   is_enabled_ = false;
180 }
181
182 bool QuicFlowController::IsEnabled() const {
183   bool connection_flow_control_enabled =
184       (id_ == kConnectionLevelId &&
185        FLAGS_enable_quic_connection_flow_control);
186   bool stream_flow_control_enabled =
187       (id_ != kConnectionLevelId &&
188        FLAGS_enable_quic_stream_flow_control_2);
189   return (connection_flow_control_enabled || stream_flow_control_enabled) &&
190          is_enabled_;
191 }
192
193 bool QuicFlowController::IsBlocked() const {
194   return IsEnabled() && SendWindowSize() == 0;
195 }
196
197 uint64 QuicFlowController::SendWindowSize() const {
198   if (bytes_sent_ > send_window_offset_) {
199     return 0;
200   }
201   return send_window_offset_ - bytes_sent_;
202 }
203
204 uint64 QuicFlowController::TotalReceivedBytes() const {
205   return bytes_consumed_ + bytes_buffered_;
206 }
207
208 }  // namespace net