Update To 11.40.268.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(QuicConnection* connection,
17                                        QuicStreamId id,
18                                        bool is_server,
19                                        uint64 send_window_offset,
20                                        uint64 receive_window_offset,
21                                        uint64 max_receive_window)
22     : connection_(connection),
23       id_(id),
24       is_enabled_(true),
25       is_server_(is_server),
26       bytes_consumed_(0),
27       highest_received_byte_offset_(0),
28       bytes_sent_(0),
29       send_window_offset_(send_window_offset),
30       receive_window_offset_(receive_window_offset),
31       max_receive_window_(max_receive_window),
32       last_blocked_send_window_offset_(0) {
33   DVLOG(1) << ENDPOINT << "Created flow controller for stream " << id_
34            << ", setting initial receive window offset to: "
35            << receive_window_offset_
36            << ", max receive window to: "
37            << max_receive_window_
38            << ", setting send window offset to: " << send_window_offset_;
39 }
40
41 void QuicFlowController::AddBytesConsumed(uint64 bytes_consumed) {
42   if (!IsEnabled()) {
43     return;
44   }
45
46   bytes_consumed_ += bytes_consumed;
47   DVLOG(1) << ENDPOINT << "Stream " << id_ << " consumed: " << bytes_consumed_;
48
49   MaybeSendWindowUpdate();
50 }
51
52 bool QuicFlowController::UpdateHighestReceivedOffset(uint64 new_offset) {
53   if (!IsEnabled()) {
54     return false;
55   }
56
57   // Only update if offset has increased.
58   if (new_offset <= highest_received_byte_offset_) {
59     return false;
60   }
61
62   DVLOG(1) << ENDPOINT << "Stream " << id_
63            << " highest byte offset increased from: "
64            << highest_received_byte_offset_ << " to " << new_offset;
65   highest_received_byte_offset_ = new_offset;
66   return true;
67 }
68
69 void QuicFlowController::AddBytesSent(uint64 bytes_sent) {
70   if (!IsEnabled()) {
71     return;
72   }
73
74   if (bytes_sent_ + bytes_sent > send_window_offset_) {
75     LOG(DFATAL) << ENDPOINT << "Stream " << id_ << " Trying to send an extra "
76                 << bytes_sent << " bytes, when bytes_sent = " << bytes_sent_
77                 << ", and send_window_offset_ = " << send_window_offset_;
78     bytes_sent_ = send_window_offset_;
79
80     // This is an error on our side, close the connection as soon as possible.
81     connection_->SendConnectionClose(QUIC_FLOW_CONTROL_SENT_TOO_MUCH_DATA);
82     return;
83   }
84
85   bytes_sent_ += bytes_sent;
86   DVLOG(1) << ENDPOINT << "Stream " << id_ << " sent: " << bytes_sent_;
87 }
88
89 bool QuicFlowController::FlowControlViolation() {
90   if (!IsEnabled()) {
91     return false;
92   }
93
94   if (highest_received_byte_offset_ > receive_window_offset_) {
95     LOG(ERROR) << ENDPOINT << "Flow control violation on stream "
96                << id_ << ", receive window offset: "
97                << receive_window_offset_
98                << ", highest received byte offset: "
99                << highest_received_byte_offset_;
100     return true;
101   }
102   return false;
103 }
104
105 void QuicFlowController::MaybeSendWindowUpdate() {
106   if (!IsEnabled()) {
107     return;
108   }
109
110   // Send WindowUpdate to increase receive window if
111   // (receive window offset - consumed bytes) < (max window / 2).
112   // This is behaviour copied from SPDY.
113   DCHECK_LT(bytes_consumed_, receive_window_offset_);
114   size_t consumed_window = receive_window_offset_ - bytes_consumed_;
115   size_t threshold = (max_receive_window_ / 2);
116
117   if (consumed_window < threshold) {
118     // Update our receive window.
119     receive_window_offset_ += (max_receive_window_ - consumed_window);
120
121     DVLOG(1) << ENDPOINT << "Sending WindowUpdate frame for stream " << id_
122              << ", consumed bytes: " << bytes_consumed_
123              << ", consumed window: " << consumed_window
124              << ", and threshold: " << threshold
125              << ", and max recvw: " << max_receive_window_
126              << ". New receive window offset is: " << receive_window_offset_;
127
128     // Inform the peer of our new receive window.
129     connection_->SendWindowUpdate(id_, receive_window_offset_);
130   }
131 }
132
133 void QuicFlowController::MaybeSendBlocked() {
134   if (!IsEnabled()) {
135     return;
136   }
137
138   if (SendWindowSize() == 0 &&
139       last_blocked_send_window_offset_ < send_window_offset_) {
140     DVLOG(1) << ENDPOINT << "Stream " << id_ << " is flow control blocked. "
141              << "Send window: " << SendWindowSize()
142              << ", bytes sent: " << bytes_sent_
143              << ", send limit: " << send_window_offset_;
144     // The entire send_window has been consumed, we are now flow control
145     // blocked.
146     connection_->SendBlocked(id_);
147
148     // Keep track of when we last sent a BLOCKED frame so that we only send one
149     // at a given send offset.
150     last_blocked_send_window_offset_ = send_window_offset_;
151   }
152 }
153
154 bool QuicFlowController::UpdateSendWindowOffset(uint64 new_send_window_offset) {
155   if (!IsEnabled()) {
156     return false;
157   }
158
159   // Only update if send window has increased.
160   if (new_send_window_offset <= send_window_offset_) {
161     return false;
162   }
163
164   DVLOG(1) << ENDPOINT << "UpdateSendWindowOffset for stream " << id_
165            << " with new offset " << new_send_window_offset
166            << " current offset: " << send_window_offset_
167            << " bytes_sent: " << bytes_sent_;
168
169   const bool blocked = IsBlocked();
170   send_window_offset_ = new_send_window_offset;
171   return blocked;
172 }
173
174 void QuicFlowController::Disable() {
175   is_enabled_ = false;
176 }
177
178 bool QuicFlowController::IsEnabled() const {
179   return is_enabled_;
180 }
181
182 bool QuicFlowController::IsBlocked() const {
183   return IsEnabled() && SendWindowSize() == 0;
184 }
185
186 uint64 QuicFlowController::SendWindowSize() const {
187   if (bytes_sent_ > send_window_offset_) {
188     return 0;
189   }
190   return send_window_offset_ - bytes_sent_;
191 }
192
193 }  // namespace net