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