session_->PostProcessAfterData();
}
+ virtual void OnCongestionWindowChange(QuicTime now) OVERRIDE {
+ session_->OnCongestionWindowChange(now);
+ }
+
virtual void OnSuccessfulVersionNegotiation(
const QuicVersion& version) OVERRIDE {
session_->OnSuccessfulVersionNegotiation(version);
visitor_shim_(new VisitorShim(this)),
config_(config),
max_open_streams_(config_.max_streams_per_connection()),
- next_stream_id_(is_server() ? 2 : 3),
+ next_stream_id_(is_server() ? 2 : 5),
largest_peer_created_stream_id_(0),
error_(QUIC_NO_ERROR),
goaway_received_(false),
config_.GetInitialSessionFlowControlWindowToSend(),
config_.GetInitialSessionFlowControlWindowToSend()));
}
+}
+void QuicSession::InitializeSession() {
connection_->set_visitor(visitor_shim_.get());
connection_->SetFromConfig(config_);
if (connection_->connected()) {
config_.max_time_before_crypto_handshake());
}
headers_stream_.reset(new QuicHeadersStream(this));
- if (!is_server()) {
- // For version above QUIC v12, the headers stream is stream 3, so the
- // next available local stream ID should be 5.
- DCHECK_EQ(kHeadersStreamId, next_stream_id_);
- next_stream_id_ += 2;
- }
}
QuicSession::~QuicSession() {
// Stream may be closed by the time we receive a WINDOW_UPDATE, so we can't
// assume that it still exists.
QuicStreamId stream_id = frames[i].stream_id;
- if (stream_id == 0) {
+ if (stream_id == kConnectionLevelId) {
// This is a window update that applies to the connection, rather than an
// individual stream.
DVLOG(1) << ENDPOINT
<< "Received connection level flow control window update with "
"byte offset: " << frames[i].byte_offset;
- if (FLAGS_enable_quic_connection_flow_control_2 &&
- flow_controller_->UpdateSendWindowOffset(frames[i].byte_offset)) {
+ if (flow_controller_->UpdateSendWindowOffset(frames[i].byte_offset)) {
connection_window_updated = true;
}
continue;
}
- QuicDataStream* stream = GetDataStream(stream_id);
+ if (connection_->version() < QUIC_VERSION_21 &&
+ (stream_id == kCryptoStreamId || stream_id == kHeadersStreamId)) {
+ DLOG(DFATAL) << "WindowUpdate for stream " << stream_id << " in version "
+ << QuicVersionToString(connection_->version());
+ return;
+ }
+
+ ReliableQuicStream* stream = GetStream(stream_id);
if (stream) {
stream->OnWindowUpdateFrame(frames[i]);
}
// of the how many bytes the stream's flow controller believes it has
// received, for accurate connection level flow control accounting.
if (!stream->HasFinalReceivedByteOffset() &&
- stream->flow_controller()->IsEnabled() &&
- FLAGS_enable_quic_connection_flow_control_2) {
+ stream->flow_controller()->IsEnabled()) {
locally_closed_streams_highest_offset_[stream_id] =
stream->flow_controller()->highest_received_byte_offset();
}
void QuicSession::UpdateFlowControlOnFinalReceivedByteOffset(
QuicStreamId stream_id, QuicStreamOffset final_byte_offset) {
- if (!FLAGS_enable_quic_connection_flow_control_2) {
- return;
- }
-
map<QuicStreamId, QuicStreamOffset>::iterator it =
locally_closed_streams_highest_offset_.find(stream_id);
if (it == locally_closed_streams_highest_offset_.end()) {
void QuicSession::OnConfigNegotiated() {
connection_->SetFromConfig(config_);
QuicVersion version = connection()->version();
- if (version < QUIC_VERSION_17) {
+
+ // A server should accept a small number of additional streams beyond the
+ // limit sent to the client. This helps avoid early connection termination
+ // when FIN/RSTs for old streams are lost or arrive out of order.
+ if (FLAGS_quic_allow_more_open_streams) {
+ set_max_open_streams((is_server() ? kMaxStreamsMultiplier : 1.0) *
+ config_.max_streams_per_connection());
+ }
+
+ if (version <= QUIC_VERSION_16) {
return;
}
return;
}
- // QUIC_VERSION_20 and higher can have independent stream and session flow
+ // QUIC_VERSION_21 and higher can have independent stream and session flow
// control windows.
if (config_.HasReceivedInitialStreamFlowControlWindowBytes()) {
// Streams which were created before the SHLO was received (0-RTT
return;
}
+ // Inform all existing streams about the new window.
+ if (connection_->version() >= QUIC_VERSION_21) {
+ GetCryptoStream()->UpdateSendWindowOffset(new_window);
+ headers_stream_->UpdateSendWindowOffset(new_window);
+ }
for (DataStreamMap::iterator it = stream_map_.begin();
it != stream_map_.end(); ++it) {
- it->second->flow_controller()->UpdateSendWindowOffset(new_window);
+ it->second->UpdateSendWindowOffset(new_window);
}
}
case ENCRYPTION_REESTABLISHED:
// Retransmit originally packets that were sent, since they can't be
// decrypted by the peer.
- connection_->RetransmitUnackedPackets(INITIAL_ENCRYPTION_ONLY);
+ connection_->RetransmitUnackedPackets(ALL_INITIAL_RETRANSMISSION);
break;
case HANDSHAKE_CONFIRMED:
// the peer.
connection_->NeuterUnencryptedPackets();
connection_->SetOverallConnectionTimeout(QuicTime::Delta::Infinite());
- max_open_streams_ = config_.max_streams_per_connection();
+ if (!FLAGS_quic_allow_more_open_streams) {
+ max_open_streams_ = config_.max_streams_per_connection();
+ }
break;
default:
return stream;
}
+void QuicSession::set_max_open_streams(size_t max_open_streams) {
+ DVLOG(1) << "Setting max_open_streams_ to " << max_open_streams;
+ max_open_streams_ = max_open_streams;
+}
+
bool QuicSession::IsClosedStream(QuicStreamId id) {
DCHECK_NE(0u, id);
if (id == kCryptoStreamId) {
void QuicSession::PostProcessAfterData() {
STLDeleteElements(&closed_streams_);
closed_streams_.clear();
+
+ if (FLAGS_close_quic_connection_unfinished_streams_2 &&
+ connection()->connected() &&
+ locally_closed_streams_highest_offset_.size() > max_open_streams_) {
+ // A buggy client may fail to send FIN/RSTs. Don't tolerate this.
+ connection_->SendConnectionClose(QUIC_TOO_MANY_UNFINISHED_STREAMS);
+ }
}
void QuicSession::OnSuccessfulVersionNegotiation(const QuicVersion& version) {
flow_controller_->Disable();
}
- // Inform all streams about the negotiated version. They may have been created
- // with a different version.
+ // Disable stream level flow control based on negotiated version. Streams may
+ // have been created with a different version.
+ if (version < QUIC_VERSION_21) {
+ GetCryptoStream()->flow_controller()->Disable();
+ headers_stream_->flow_controller()->Disable();
+ }
for (DataStreamMap::iterator it = stream_map_.begin();
it != stream_map_.end(); ++it) {
- if (version < QUIC_VERSION_17) {
+ if (version <= QUIC_VERSION_16) {
it->second->flow_controller()->Disable();
}
}