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(QuicConnection
* connection
,
19 QuicStreamOffset send_window_offset
,
20 QuicStreamOffset receive_window_offset
,
21 QuicByteCount max_receive_window
)
22 : connection_(connection
),
25 is_server_(is_server
),
27 highest_received_byte_offset_(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_
;
41 void QuicFlowController::AddBytesConsumed(QuicByteCount bytes_consumed
) {
46 bytes_consumed_
+= bytes_consumed
;
47 DVLOG(1) << ENDPOINT
<< "Stream " << id_
<< " consumed: " << bytes_consumed_
;
49 MaybeSendWindowUpdate();
52 bool QuicFlowController::UpdateHighestReceivedOffset(
53 QuicStreamOffset new_offset
) {
58 // Only update if offset has increased.
59 if (new_offset
<= highest_received_byte_offset_
) {
63 DVLOG(1) << ENDPOINT
<< "Stream " << id_
64 << " highest byte offset increased from: "
65 << highest_received_byte_offset_
<< " to " << new_offset
;
66 highest_received_byte_offset_
= new_offset
;
70 void QuicFlowController::AddBytesSent(QuicByteCount bytes_sent
) {
75 if (bytes_sent_
+ bytes_sent
> send_window_offset_
) {
76 LOG(DFATAL
) << ENDPOINT
<< "Stream " << id_
<< " Trying to send an extra "
77 << bytes_sent
<< " bytes, when bytes_sent = " << bytes_sent_
78 << ", and send_window_offset_ = " << send_window_offset_
;
79 bytes_sent_
= send_window_offset_
;
81 // This is an error on our side, close the connection as soon as possible.
82 connection_
->SendConnectionClose(QUIC_FLOW_CONTROL_SENT_TOO_MUCH_DATA
);
86 bytes_sent_
+= bytes_sent
;
87 DVLOG(1) << ENDPOINT
<< "Stream " << id_
<< " sent: " << bytes_sent_
;
90 bool QuicFlowController::FlowControlViolation() {
95 if (highest_received_byte_offset_
> receive_window_offset_
) {
96 LOG(ERROR
) << ENDPOINT
<< "Flow control violation on stream "
97 << id_
<< ", receive window offset: "
98 << receive_window_offset_
99 << ", highest received byte offset: "
100 << highest_received_byte_offset_
;
106 void QuicFlowController::MaybeSendWindowUpdate() {
111 // Send WindowUpdate to increase receive window if
112 // (receive window offset - consumed bytes) < (max window / 2).
113 // This is behaviour copied from SPDY.
114 DCHECK_LT(bytes_consumed_
, receive_window_offset_
);
115 QuicStreamOffset consumed_window
= receive_window_offset_
- bytes_consumed_
;
116 QuicByteCount threshold
= (max_receive_window_
/ 2);
118 if (consumed_window
< threshold
) {
119 // Update our receive window.
120 receive_window_offset_
+= (max_receive_window_
- consumed_window
);
122 DVLOG(1) << ENDPOINT
<< "Sending WindowUpdate frame for stream " << id_
123 << ", consumed bytes: " << bytes_consumed_
124 << ", consumed window: " << consumed_window
125 << ", and threshold: " << threshold
126 << ", and max recvw: " << max_receive_window_
127 << ". New receive window offset is: " << receive_window_offset_
;
129 // Inform the peer of our new receive window.
130 connection_
->SendWindowUpdate(id_
, receive_window_offset_
);
134 void QuicFlowController::MaybeSendBlocked() {
139 if (SendWindowSize() == 0 &&
140 last_blocked_send_window_offset_
< send_window_offset_
) {
141 DVLOG(1) << ENDPOINT
<< "Stream " << id_
<< " is flow control blocked. "
142 << "Send window: " << SendWindowSize()
143 << ", bytes sent: " << bytes_sent_
144 << ", send limit: " << send_window_offset_
;
145 // The entire send_window has been consumed, we are now flow control
147 connection_
->SendBlocked(id_
);
149 // Keep track of when we last sent a BLOCKED frame so that we only send one
150 // at a given send offset.
151 last_blocked_send_window_offset_
= send_window_offset_
;
155 bool QuicFlowController::UpdateSendWindowOffset(
156 QuicStreamOffset new_send_window_offset
) {
161 // Only update if send window has increased.
162 if (new_send_window_offset
<= send_window_offset_
) {
166 DVLOG(1) << ENDPOINT
<< "UpdateSendWindowOffset for stream " << id_
167 << " with new offset " << new_send_window_offset
168 << " current offset: " << send_window_offset_
169 << " bytes_sent: " << bytes_sent_
;
171 const bool blocked
= IsBlocked();
172 send_window_offset_
= new_send_window_offset
;
176 void QuicFlowController::Disable() {
180 bool QuicFlowController::IsEnabled() const {
184 bool QuicFlowController::IsBlocked() const {
185 return IsEnabled() && SendWindowSize() == 0;
188 uint64
QuicFlowController::SendWindowSize() const {
189 if (bytes_sent_
> send_window_offset_
) {
192 return send_window_offset_
- bytes_sent_
;