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.
5 #include "net/quic/quic_flow_controller.h"
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"
14 #define ENDPOINT (is_server_ ? "Server: " : " Client: ")
16 QuicFlowController::QuicFlowController(QuicVersion version
,
19 uint64 send_window_offset
,
20 uint64 receive_window_offset
,
21 uint64 max_receive_window
)
24 is_server_(is_server
),
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
;
45 void QuicFlowController::AddBytesConsumed(uint64 bytes_consumed
) {
50 bytes_consumed_
+= bytes_consumed
;
51 DVLOG(1) << ENDPOINT
<< "Stream " << id_
<< " consumed: " << bytes_consumed_
;
54 void QuicFlowController::AddBytesBuffered(uint64 bytes_buffered
) {
59 bytes_buffered_
+= bytes_buffered
;
60 DVLOG(1) << ENDPOINT
<< "Stream " << id_
<< " buffered: " << bytes_buffered_
;
63 void QuicFlowController::RemoveBytesBuffered(uint64 bytes_buffered
) {
68 if (bytes_buffered_
< bytes_buffered
) {
69 LOG(DFATAL
) << "Trying to remove " << bytes_buffered
<< " bytes, when only "
70 << bytes_buffered_
<< " bytes are buffered";
75 bytes_buffered_
-= bytes_buffered
;
76 DVLOG(1) << ENDPOINT
<< "Stream " << id_
<< " buffered: " << bytes_buffered_
;
79 void QuicFlowController::AddBytesSent(uint64 bytes_sent
) {
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_
;
92 bytes_sent_
+= bytes_sent
;
93 DVLOG(1) << ENDPOINT
<< "Stream " << id_
<< " sent: " << bytes_sent_
;
96 bool QuicFlowController::FlowControlViolation() {
101 if (receive_window_offset_
< TotalReceivedBytes()) {
103 << ENDPOINT
<< "Flow control violation on stream " << id_
104 << ", receive window: " << receive_window_offset_
105 << ", bytes received: " << TotalReceivedBytes();
112 void QuicFlowController::MaybeSendWindowUpdate(QuicConnection
* connection
) {
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);
123 if (consumed_window
< threshold
) {
124 // Update our receive window.
125 receive_window_offset_
+= (max_receive_window_
- consumed_window
);
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_
;
134 // Inform the peer of our new receive window.
135 connection
->SendWindowUpdate(id_
, receive_window_offset_
);
139 void QuicFlowController::MaybeSendBlocked(QuicConnection
* connection
) {
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
152 connection
->SendBlocked(id_
);
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_
;
160 bool QuicFlowController::UpdateSendWindowOffset(uint64 new_send_window_offset
) {
165 // Only update if send window has increased.
166 if (new_send_window_offset
<= send_window_offset_
) {
170 DVLOG(1) << ENDPOINT
<< "UpdateSendWindowOffset for stream " << id_
171 << " with new offset " << new_send_window_offset
172 << " , current offset: " << send_window_offset_
;
174 send_window_offset_
= new_send_window_offset
;
178 void QuicFlowController::Disable() {
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
) &&
193 bool QuicFlowController::IsBlocked() const {
194 return IsEnabled() && SendWindowSize() == 0;
197 uint64
QuicFlowController::SendWindowSize() const {
198 if (bytes_sent_
> send_window_offset_
) {
201 return send_window_offset_
- bytes_sent_
;
204 uint64
QuicFlowController::TotalReceivedBytes() const {
205 return bytes_consumed_
+ bytes_buffered_
;