Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/quic/quic_session.h" | 5 #include "net/quic/quic_session.h" |
| 6 | 6 |
| 7 #include "base/stl_util.h" | 7 #include "base/stl_util.h" |
| 8 #include "net/quic/crypto/proof_verifier.h" | 8 #include "net/quic/crypto/proof_verifier.h" |
| 9 #include "net/quic/quic_connection.h" | 9 #include "net/quic/quic_connection.h" |
| 10 #include "net/quic/quic_flags.h" | 10 #include "net/quic/quic_flags.h" |
| 11 #include "net/quic/quic_flow_controller.h" | |
| 11 #include "net/quic/quic_headers_stream.h" | 12 #include "net/quic/quic_headers_stream.h" |
| 12 #include "net/ssl/ssl_info.h" | 13 #include "net/ssl/ssl_info.h" |
| 13 | 14 |
| 14 using base::StringPiece; | 15 using base::StringPiece; |
| 15 using base::hash_map; | 16 using base::hash_map; |
| 16 using base::hash_set; | 17 using base::hash_set; |
| 17 using std::make_pair; | 18 using std::make_pair; |
| 18 using std::vector; | 19 using std::vector; |
| 19 | 20 |
| 20 namespace net { | 21 namespace net { |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 71 virtual void OnConnectionClosed( | 72 virtual void OnConnectionClosed( |
| 72 QuicErrorCode error, bool from_peer) OVERRIDE { | 73 QuicErrorCode error, bool from_peer) OVERRIDE { |
| 73 session_->OnConnectionClosed(error, from_peer); | 74 session_->OnConnectionClosed(error, from_peer); |
| 74 // The session will go away, so don't bother with cleanup. | 75 // The session will go away, so don't bother with cleanup. |
| 75 } | 76 } |
| 76 | 77 |
| 77 virtual void OnWriteBlocked() OVERRIDE { | 78 virtual void OnWriteBlocked() OVERRIDE { |
| 78 session_->OnWriteBlocked(); | 79 session_->OnWriteBlocked(); |
| 79 } | 80 } |
| 80 | 81 |
| 81 virtual bool HasPendingWrites() const OVERRIDE { | 82 virtual bool WillingAndAbleToWrite() const OVERRIDE { |
| 82 return session_->HasPendingWrites(); | 83 return session_->WillingAndAbleToWrite(); |
| 83 } | 84 } |
| 84 | 85 |
| 85 virtual bool HasPendingHandshake() const OVERRIDE { | 86 virtual bool HasPendingHandshake() const OVERRIDE { |
| 86 return session_->HasPendingHandshake(); | 87 return session_->HasPendingHandshake(); |
| 87 } | 88 } |
| 88 | 89 |
| 89 virtual bool HasOpenDataStreams() const OVERRIDE { | 90 virtual bool HasOpenDataStreams() const OVERRIDE { |
| 90 return session_->HasOpenDataStreams(); | 91 return session_->HasOpenDataStreams(); |
| 91 } | 92 } |
| 92 | 93 |
| 93 private: | 94 private: |
| 94 QuicSession* session_; | 95 QuicSession* session_; |
| 95 }; | 96 }; |
| 96 | 97 |
| 97 QuicSession::QuicSession(QuicConnection* connection, | 98 QuicSession::QuicSession(QuicConnection* connection, |
| 99 uint32 max_flow_control_receive_window_bytes, | |
| 98 const QuicConfig& config) | 100 const QuicConfig& config) |
| 99 : connection_(connection), | 101 : connection_(connection), |
| 100 visitor_shim_(new VisitorShim(this)), | 102 visitor_shim_(new VisitorShim(this)), |
| 101 config_(config), | 103 config_(config), |
| 102 max_open_streams_(config_.max_streams_per_connection()), | 104 max_open_streams_(config_.max_streams_per_connection()), |
| 103 next_stream_id_(is_server() ? 2 : 3), | 105 next_stream_id_(is_server() ? 2 : 3), |
| 104 largest_peer_created_stream_id_(0), | 106 largest_peer_created_stream_id_(0), |
| 105 error_(QUIC_NO_ERROR), | 107 error_(QUIC_NO_ERROR), |
| 106 goaway_received_(false), | 108 goaway_received_(false), |
| 107 goaway_sent_(false), | 109 goaway_sent_(false), |
| 108 has_pending_handshake_(false) { | 110 has_pending_handshake_(false), |
| 111 max_flow_control_receive_window_bytes_( | |
| 112 max_flow_control_receive_window_bytes) { | |
| 113 if (max_flow_control_receive_window_bytes_ < kDefaultFlowControlSendWindow) { | |
| 114 LOG(ERROR) << "Initial receive window (" | |
| 115 << max_flow_control_receive_window_bytes_ | |
| 116 << ") cannot be set lower than default (" | |
| 117 << kDefaultFlowControlSendWindow << ")."; | |
| 118 max_flow_control_receive_window_bytes_ = kDefaultFlowControlSendWindow; | |
| 119 } | |
| 120 flow_controller_.reset(new QuicFlowController( | |
| 121 connection_->supported_versions().front(), 0, is_server(), | |
| 122 kDefaultFlowControlSendWindow, max_flow_control_receive_window_bytes_, | |
| 123 max_flow_control_receive_window_bytes_)); | |
| 109 | 124 |
| 110 connection_->set_visitor(visitor_shim_.get()); | 125 connection_->set_visitor(visitor_shim_.get()); |
| 111 connection_->SetFromConfig(config_); | 126 connection_->SetFromConfig(config_); |
| 112 if (connection_->connected()) { | 127 if (connection_->connected()) { |
| 113 connection_->SetOverallConnectionTimeout( | 128 connection_->SetOverallConnectionTimeout( |
| 114 config_.max_time_before_crypto_handshake()); | 129 config_.max_time_before_crypto_handshake()); |
| 115 } | 130 } |
| 116 headers_stream_.reset(new QuicHeadersStream(this)); | 131 headers_stream_.reset(new QuicHeadersStream(this)); |
| 117 if (!is_server()) { | 132 if (!is_server()) { |
| 118 // For version above QUIC v12, the headers stream is stream 3, so the | 133 // For version above QUIC v12, the headers stream is stream 3, so the |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 222 // Stream may be closed by the time we receive a WINDOW_UPDATE, so we can't | 237 // Stream may be closed by the time we receive a WINDOW_UPDATE, so we can't |
| 223 // assume that it still exists. | 238 // assume that it still exists. |
| 224 QuicStreamId stream_id = frames[i].stream_id; | 239 QuicStreamId stream_id = frames[i].stream_id; |
| 225 if (stream_id == 0) { | 240 if (stream_id == 0) { |
| 226 // This is a window update that applies to the connection, rather than an | 241 // This is a window update that applies to the connection, rather than an |
| 227 // individual stream. | 242 // individual stream. |
| 228 DVLOG(1) << ENDPOINT | 243 DVLOG(1) << ENDPOINT |
| 229 << "Received connection level flow control window update with " | 244 << "Received connection level flow control window update with " |
| 230 "byte offset: " << frames[i].byte_offset; | 245 "byte offset: " << frames[i].byte_offset; |
| 231 if (FLAGS_enable_quic_connection_flow_control && | 246 if (FLAGS_enable_quic_connection_flow_control && |
| 232 connection()->flow_controller()->UpdateSendWindowOffset( | 247 flow_controller_->UpdateSendWindowOffset(frames[i].byte_offset)) { |
| 233 frames[i].byte_offset)) { | |
| 234 connection_window_updated = true; | 248 connection_window_updated = true; |
| 235 } | 249 } |
| 236 continue; | 250 continue; |
| 237 } | 251 } |
| 238 | 252 |
| 239 QuicDataStream* stream = GetDataStream(stream_id); | 253 QuicDataStream* stream = GetDataStream(stream_id); |
| 240 if (stream) { | 254 if (stream) { |
| 241 stream->OnWindowUpdateFrame(frames[i]); | 255 stream->OnWindowUpdateFrame(frames[i]); |
| 242 } | 256 } |
| 243 } | 257 } |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 254 // TODO(rjshade): Compare our flow control receive windows for specified | 268 // TODO(rjshade): Compare our flow control receive windows for specified |
| 255 // streams: if we have a large window then maybe something | 269 // streams: if we have a large window then maybe something |
| 256 // had gone wrong with the flow control accounting. | 270 // had gone wrong with the flow control accounting. |
| 257 DVLOG(1) << ENDPOINT << "Received BLOCKED frame with stream id: " | 271 DVLOG(1) << ENDPOINT << "Received BLOCKED frame with stream id: " |
| 258 << frames[i].stream_id; | 272 << frames[i].stream_id; |
| 259 } | 273 } |
| 260 } | 274 } |
| 261 | 275 |
| 262 void QuicSession::OnCanWrite() { | 276 void QuicSession::OnCanWrite() { |
| 263 // We limit the number of writes to the number of pending streams. If more | 277 // We limit the number of writes to the number of pending streams. If more |
| 264 // streams become pending, HasPendingWrites will be true, which will cause | 278 // streams become pending, WillingAndAbleToWrite will be true, which will |
| 265 // the connection to request resumption before yielding to other connections. | 279 // cause the connection to request resumption before yielding to other |
| 280 // connections. | |
| 266 size_t num_writes = write_blocked_streams_.NumBlockedStreams(); | 281 size_t num_writes = write_blocked_streams_.NumBlockedStreams(); |
| 282 if (flow_controller_->IsBlocked()) { | |
| 283 // If we are connection level flow control blocked, then only allow the | |
| 284 // crypto and headers streams to try writing as all other streams will be | |
| 285 // blocked. | |
| 286 num_writes = 0; | |
| 287 if (write_blocked_streams_.crypto_stream_blocked()) { | |
| 288 num_writes += 1; | |
| 289 } | |
| 290 if (write_blocked_streams_.headers_stream_blocked()) { | |
| 291 num_writes += 1; | |
| 292 } | |
| 293 } | |
| 267 if (num_writes == 0) { | 294 if (num_writes == 0) { |
| 268 return; | 295 return; |
| 269 } | 296 } |
| 270 | 297 |
| 271 QuicConnection::ScopedPacketBundler ack_bundler( | 298 QuicConnection::ScopedPacketBundler ack_bundler( |
| 272 connection_.get(), QuicConnection::NO_ACK); | 299 connection_.get(), QuicConnection::NO_ACK); |
| 273 for (size_t i = 0; i < num_writes; ++i) { | 300 for (size_t i = 0; i < num_writes; ++i) { |
| 274 if (!write_blocked_streams_.HasWriteBlockedStreams()) { | 301 if (!(write_blocked_streams_.HasWriteBlockedCryptoOrHeadersStream() || |
| 302 write_blocked_streams_.HasWriteBlockedDataStreams())) { | |
|
wtc
2014/05/19 18:58:40
Nit: I would simplify this expression with De Morg
ramant (doing other things)
2014/05/20 03:22:32
rjshade: wdyt?
| |
| 275 // Writing one stream removed another!? Something's broken. | 303 // Writing one stream removed another!? Something's broken. |
| 276 LOG(DFATAL) << "WriteBlockedStream is missing"; | 304 LOG(DFATAL) << "WriteBlockedStream is missing"; |
| 277 connection_->CloseConnection(QUIC_INTERNAL_ERROR, false); | 305 connection_->CloseConnection(QUIC_INTERNAL_ERROR, false); |
| 278 return; | 306 return; |
| 279 } | 307 } |
| 280 if (!connection_->CanWriteStreamData()) { | 308 if (!connection_->CanWriteStreamData()) { |
| 281 return; | 309 return; |
| 282 } | 310 } |
| 283 QuicStreamId stream_id = write_blocked_streams_.PopFront(); | 311 QuicStreamId stream_id = write_blocked_streams_.PopFront(); |
| 284 if (stream_id == kCryptoStreamId) { | 312 if (stream_id == kCryptoStreamId) { |
| 285 has_pending_handshake_ = false; // We just popped it. | 313 has_pending_handshake_ = false; // We just popped it. |
| 286 } | 314 } |
| 287 ReliableQuicStream* stream = GetStream(stream_id); | 315 ReliableQuicStream* stream = GetStream(stream_id); |
| 288 if (stream != NULL && !stream->flow_controller()->IsBlocked()) { | 316 if (stream != NULL && !stream->flow_controller()->IsBlocked()) { |
| 289 // If the stream can't write all bytes, it'll re-add itself to the blocked | 317 // If the stream can't write all bytes, it'll re-add itself to the blocked |
| 290 // list. | 318 // list. |
| 291 stream->OnCanWrite(); | 319 stream->OnCanWrite(); |
| 292 } | 320 } |
| 293 } | 321 } |
| 294 } | 322 } |
| 295 | 323 |
| 296 bool QuicSession::HasPendingWrites() const { | 324 bool QuicSession::WillingAndAbleToWrite() const { |
| 297 return write_blocked_streams_.HasWriteBlockedStreams(); | 325 // If the crypto or headers streams are blocked, we want to schedule a write - |
| 326 // they don't get blocked by connection level flow control. Otherwise only | |
| 327 // schedule a write if we are not flow control blocked at the connection | |
| 328 // level. | |
| 329 return write_blocked_streams_.HasWriteBlockedCryptoOrHeadersStream() || | |
| 330 (!flow_controller_->IsBlocked() && | |
| 331 write_blocked_streams_.HasWriteBlockedDataStreams()); | |
| 298 } | 332 } |
| 299 | 333 |
| 300 bool QuicSession::HasPendingHandshake() const { | 334 bool QuicSession::HasPendingHandshake() const { |
| 301 return has_pending_handshake_; | 335 return has_pending_handshake_; |
| 302 } | 336 } |
| 303 | 337 |
| 304 bool QuicSession::HasOpenDataStreams() const { | 338 bool QuicSession::HasOpenDataStreams() const { |
| 305 return GetNumOpenStreams() > 0; | 339 return GetNumOpenStreams() > 0; |
| 306 } | 340 } |
| 307 | 341 |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 392 return; | 426 return; |
| 393 } | 427 } |
| 394 DataStreamMap::iterator it = stream_map_.begin(); | 428 DataStreamMap::iterator it = stream_map_.begin(); |
| 395 while (it != stream_map_.end()) { | 429 while (it != stream_map_.end()) { |
| 396 it->second->flow_controller()->UpdateSendWindowOffset( | 430 it->second->flow_controller()->UpdateSendWindowOffset( |
| 397 new_flow_control_send_window); | 431 new_flow_control_send_window); |
| 398 it++; | 432 it++; |
| 399 } | 433 } |
| 400 | 434 |
| 401 // Update connection level window. | 435 // Update connection level window. |
| 402 connection()->flow_controller()->UpdateSendWindowOffset( | 436 flow_controller_->UpdateSendWindowOffset(new_flow_control_send_window); |
| 403 new_flow_control_send_window); | |
| 404 } | 437 } |
| 405 } | 438 } |
| 406 | 439 |
| 407 void QuicSession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) { | 440 void QuicSession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) { |
| 408 switch (event) { | 441 switch (event) { |
| 409 // TODO(satyamshekhar): Move the logic of setting the encrypter/decrypter | 442 // TODO(satyamshekhar): Move the logic of setting the encrypter/decrypter |
| 410 // to QuicSession since it is the glue. | 443 // to QuicSession since it is the glue. |
| 411 case ENCRYPTION_FIRST_ESTABLISHED: | 444 case ENCRYPTION_FIRST_ESTABLISHED: |
| 412 break; | 445 break; |
| 413 | 446 |
| (...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 584 has_pending_handshake_ = true; | 617 has_pending_handshake_ = true; |
| 585 // TODO(jar): Be sure to use the highest priority for the crypto stream, | 618 // TODO(jar): Be sure to use the highest priority for the crypto stream, |
| 586 // perhaps by adding a "special" priority for it that is higher than | 619 // perhaps by adding a "special" priority for it that is higher than |
| 587 // kHighestPriority. | 620 // kHighestPriority. |
| 588 priority = kHighestPriority; | 621 priority = kHighestPriority; |
| 589 } | 622 } |
| 590 write_blocked_streams_.PushBack(id, priority); | 623 write_blocked_streams_.PushBack(id, priority); |
| 591 } | 624 } |
| 592 | 625 |
| 593 bool QuicSession::HasDataToWrite() const { | 626 bool QuicSession::HasDataToWrite() const { |
| 594 return write_blocked_streams_.HasWriteBlockedStreams() || | 627 return write_blocked_streams_.HasWriteBlockedCryptoOrHeadersStream() || |
| 595 connection_->HasQueuedData(); | 628 write_blocked_streams_.HasWriteBlockedDataStreams() || |
| 629 connection_->HasQueuedData(); | |
| 596 } | 630 } |
| 597 | 631 |
| 598 bool QuicSession::GetSSLInfo(SSLInfo* ssl_info) const { | 632 bool QuicSession::GetSSLInfo(SSLInfo* ssl_info) const { |
| 599 NOTIMPLEMENTED(); | 633 NOTIMPLEMENTED(); |
| 600 return false; | 634 return false; |
| 601 } | 635 } |
| 602 | 636 |
| 603 void QuicSession::PostProcessAfterData() { | 637 void QuicSession::PostProcessAfterData() { |
| 604 STLDeleteElements(&closed_streams_); | 638 STLDeleteElements(&closed_streams_); |
| 605 closed_streams_.clear(); | 639 closed_streams_.clear(); |
| 606 } | 640 } |
| 607 | 641 |
| 642 void QuicSession::OnSuccessfulVersionNegotiation(const QuicVersion& version) { | |
| 643 if (version < QUIC_VERSION_19) { | |
| 644 flow_controller_->Disable(); | |
| 645 } | |
| 646 } | |
| 647 | |
| 608 } // namespace net | 648 } // namespace net |
| OLD | NEW |