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 |