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_headers_stream.h" | 10 #include "net/quic/quic_headers_stream.h" |
11 #include "net/ssl/ssl_info.h" | 11 #include "net/ssl/ssl_info.h" |
12 | 12 |
13 using base::StringPiece; | 13 using base::StringPiece; |
14 using base::hash_map; | 14 using base::hash_map; |
15 using base::hash_set; | 15 using base::hash_set; |
16 using std::make_pair; | 16 using std::make_pair; |
17 using std::vector; | 17 using std::vector; |
18 | 18 |
19 namespace net { | 19 namespace net { |
20 | 20 |
21 const size_t kMaxPrematurelyClosedStreamsTracked = 20; | |
22 const size_t kMaxZombieStreams = 20; | |
23 | |
24 #define ENDPOINT (is_server() ? "Server: " : " Client: ") | 21 #define ENDPOINT (is_server() ? "Server: " : " Client: ") |
25 | 22 |
26 // We want to make sure we delete any closed streams in a safe manner. | 23 // We want to make sure we delete any closed streams in a safe manner. |
27 // To avoid deleting a stream in mid-operation, we have a simple shim between | 24 // To avoid deleting a stream in mid-operation, we have a simple shim between |
28 // us and the stream, so we can delete any streams when we return from | 25 // us and the stream, so we can delete any streams when we return from |
29 // processing. | 26 // processing. |
30 // | 27 // |
31 // We could just override the base methods, but this makes it easier to make | 28 // We could just override the base methods, but this makes it easier to make |
32 // sure we don't miss any. | 29 // sure we don't miss any. |
33 class VisitorShim : public QuicConnectionVisitorInterface { | 30 class VisitorShim : public QuicConnectionVisitorInterface { |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
105 goaway_received_(false), | 102 goaway_received_(false), |
106 goaway_sent_(false), | 103 goaway_sent_(false), |
107 has_pending_handshake_(false) { | 104 has_pending_handshake_(false) { |
108 | 105 |
109 connection_->set_visitor(visitor_shim_.get()); | 106 connection_->set_visitor(visitor_shim_.get()); |
110 connection_->SetFromConfig(config_); | 107 connection_->SetFromConfig(config_); |
111 if (connection_->connected()) { | 108 if (connection_->connected()) { |
112 connection_->SetOverallConnectionTimeout( | 109 connection_->SetOverallConnectionTimeout( |
113 config_.max_time_before_crypto_handshake()); | 110 config_.max_time_before_crypto_handshake()); |
114 } | 111 } |
115 if (connection_->version() > QUIC_VERSION_12) { | 112 headers_stream_.reset(new QuicHeadersStream(this)); |
116 headers_stream_.reset(new QuicHeadersStream(this)); | 113 if (!is_server()) { |
117 if (!is_server()) { | 114 // For version above QUIC v12, the headers stream is stream 3, so the |
118 // For version above QUIC v12, the headers stream is stream 3, so the | 115 // next available local stream ID should be 5. |
119 // next available local stream ID should be 5. | 116 DCHECK_EQ(kHeadersStreamId, next_stream_id_); |
120 DCHECK_EQ(kHeadersStreamId, next_stream_id_); | 117 next_stream_id_ += 2; |
121 next_stream_id_ += 2; | |
122 } | |
123 } | 118 } |
124 } | 119 } |
125 | 120 |
126 QuicSession::~QuicSession() { | 121 QuicSession::~QuicSession() { |
127 STLDeleteElements(&closed_streams_); | 122 STLDeleteElements(&closed_streams_); |
128 STLDeleteValues(&stream_map_); | 123 STLDeleteValues(&stream_map_); |
129 } | 124 } |
130 | 125 |
131 bool QuicSession::OnStreamFrames(const vector<QuicStreamFrame>& frames) { | 126 bool QuicSession::OnStreamFrames(const vector<QuicStreamFrame>& frames) { |
132 for (size_t i = 0; i < frames.size(); ++i) { | 127 for (size_t i = 0; i < frames.size(); ++i) { |
133 // TODO(rch) deal with the error case of stream id 0 | 128 // TODO(rch) deal with the error case of stream id 0 |
134 if (IsClosedStream(frames[i].stream_id)) { | 129 if (IsClosedStream(frames[i].stream_id)) { |
135 // If we get additional frames for a stream where we didn't process | |
136 // headers, it's highly likely our compression context will end up | |
137 // permanently out of sync with the peer's, so we give up and close the | |
138 // connection. | |
139 if (ContainsKey(prematurely_closed_streams_, frames[i].stream_id)) { | |
140 connection()->SendConnectionClose( | |
141 QUIC_STREAM_RST_BEFORE_HEADERS_DECOMPRESSED); | |
142 return false; | |
143 } | |
144 continue; | 130 continue; |
145 } | 131 } |
146 | 132 |
147 ReliableQuicStream* stream = GetStream(frames[i].stream_id); | 133 ReliableQuicStream* stream = GetStream(frames[i].stream_id); |
148 if (stream == NULL) return false; | 134 if (stream == NULL) return false; |
149 if (!stream->WillAcceptStreamFrame(frames[i])) return false; | 135 if (!stream->WillAcceptStreamFrame(frames[i])) return false; |
150 | 136 |
151 // TODO(alyssar) check against existing connection address: if changed, make | 137 // TODO(alyssar) check against existing connection address: if changed, make |
152 // sure we update the connection. | 138 // sure we update the connection. |
153 } | 139 } |
154 | 140 |
155 for (size_t i = 0; i < frames.size(); ++i) { | 141 for (size_t i = 0; i < frames.size(); ++i) { |
156 QuicStreamId stream_id = frames[i].stream_id; | 142 QuicStreamId stream_id = frames[i].stream_id; |
157 ReliableQuicStream* stream = GetStream(stream_id); | 143 ReliableQuicStream* stream = GetStream(stream_id); |
158 if (!stream) { | 144 if (!stream) { |
159 continue; | 145 continue; |
160 } | 146 } |
161 stream->OnStreamFrame(frames[i]); | 147 stream->OnStreamFrame(frames[i]); |
162 | |
163 // If the stream is a data stream had been prematurely closed, and the | |
164 // headers are now decompressed, then we are finally finished | |
165 // with this stream. | |
166 if (ContainsKey(zombie_streams_, stream_id) && | |
167 static_cast<QuicDataStream*>(stream)->headers_decompressed()) { | |
168 CloseZombieStream(stream_id); | |
169 } | |
170 } | 148 } |
171 | 149 |
172 while (!decompression_blocked_streams_.empty()) { | |
173 QuicHeaderId header_id = decompression_blocked_streams_.begin()->first; | |
174 if (header_id != decompressor_.current_header_id()) { | |
175 break; | |
176 } | |
177 QuicStreamId stream_id = decompression_blocked_streams_.begin()->second; | |
178 decompression_blocked_streams_.erase(header_id); | |
179 QuicDataStream* stream = GetDataStream(stream_id); | |
180 if (!stream) { | |
181 connection()->SendConnectionClose( | |
182 QUIC_STREAM_RST_BEFORE_HEADERS_DECOMPRESSED); | |
183 return false; | |
184 } | |
185 stream->OnDecompressorAvailable(); | |
186 } | |
187 return true; | 150 return true; |
188 } | 151 } |
189 | 152 |
190 void QuicSession::OnStreamHeaders(QuicStreamId stream_id, | 153 void QuicSession::OnStreamHeaders(QuicStreamId stream_id, |
191 StringPiece headers_data) { | 154 StringPiece headers_data) { |
192 QuicDataStream* stream = GetDataStream(stream_id); | 155 QuicDataStream* stream = GetDataStream(stream_id); |
193 if (!stream) { | 156 if (!stream) { |
194 // It's quite possible to receive headers after a stream has been reset. | 157 // It's quite possible to receive headers after a stream has been reset. |
195 return; | 158 return; |
196 } | 159 } |
(...skipping 21 matching lines...) Expand all Loading... |
218 stream->OnStreamHeadersComplete(fin, frame_len); | 181 stream->OnStreamHeadersComplete(fin, frame_len); |
219 } | 182 } |
220 | 183 |
221 void QuicSession::OnRstStream(const QuicRstStreamFrame& frame) { | 184 void QuicSession::OnRstStream(const QuicRstStreamFrame& frame) { |
222 if (frame.stream_id == kCryptoStreamId) { | 185 if (frame.stream_id == kCryptoStreamId) { |
223 connection()->SendConnectionCloseWithDetails( | 186 connection()->SendConnectionCloseWithDetails( |
224 QUIC_INVALID_STREAM_ID, | 187 QUIC_INVALID_STREAM_ID, |
225 "Attempt to reset the crypto stream"); | 188 "Attempt to reset the crypto stream"); |
226 return; | 189 return; |
227 } | 190 } |
228 if (frame.stream_id == kHeadersStreamId && | 191 if (frame.stream_id == kHeadersStreamId) { |
229 connection()->version() > QUIC_VERSION_12) { | |
230 connection()->SendConnectionCloseWithDetails( | 192 connection()->SendConnectionCloseWithDetails( |
231 QUIC_INVALID_STREAM_ID, | 193 QUIC_INVALID_STREAM_ID, |
232 "Attempt to reset the headers stream"); | 194 "Attempt to reset the headers stream"); |
233 return; | 195 return; |
234 } | 196 } |
235 QuicDataStream* stream = GetDataStream(frame.stream_id); | 197 QuicDataStream* stream = GetDataStream(frame.stream_id); |
236 if (!stream) { | 198 if (!stream) { |
237 return; // Errors are handled by GetStream. | 199 return; // Errors are handled by GetStream. |
238 } | 200 } |
239 // TODO(rjshade): Adjust flow control windows based on frame.byte_offset. | 201 |
240 if (ContainsKey(zombie_streams_, stream->id())) { | |
241 // If this was a zombie stream then we close it out now. | |
242 CloseZombieStream(stream->id()); | |
243 // However, since the headers still have not been decompressed, we want to | |
244 // mark it a prematurely closed so that if we ever receive frames | |
245 // for this stream we can close the connection. | |
246 DCHECK(!stream->headers_decompressed()); | |
247 AddPrematurelyClosedStream(frame.stream_id); | |
248 return; | |
249 } | |
250 if (connection()->version() <= QUIC_VERSION_12) { | |
251 if (stream->stream_bytes_read() > 0 && !stream->headers_decompressed()) { | |
252 connection()->SendConnectionClose( | |
253 QUIC_STREAM_RST_BEFORE_HEADERS_DECOMPRESSED); | |
254 } | |
255 } | |
256 stream->OnStreamReset(frame); | 202 stream->OnStreamReset(frame); |
257 } | 203 } |
258 | 204 |
259 void QuicSession::OnGoAway(const QuicGoAwayFrame& frame) { | 205 void QuicSession::OnGoAway(const QuicGoAwayFrame& frame) { |
260 DCHECK(frame.last_good_stream_id < next_stream_id_); | 206 DCHECK(frame.last_good_stream_id < next_stream_id_); |
261 goaway_received_ = true; | 207 goaway_received_ = true; |
262 } | 208 } |
263 | 209 |
264 void QuicSession::OnConnectionClosed(QuicErrorCode error, bool from_peer) { | 210 void QuicSession::OnConnectionClosed(QuicErrorCode error, bool from_peer) { |
265 DCHECK(!connection_->connected()); | 211 DCHECK(!connection_->connected()); |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
356 QuicStreamOffset offset, | 302 QuicStreamOffset offset, |
357 bool fin, | 303 bool fin, |
358 QuicAckNotifier::DelegateInterface* ack_notifier_delegate) { | 304 QuicAckNotifier::DelegateInterface* ack_notifier_delegate) { |
359 return connection_->SendStreamData(id, data, offset, fin, | 305 return connection_->SendStreamData(id, data, offset, fin, |
360 ack_notifier_delegate); | 306 ack_notifier_delegate); |
361 } | 307 } |
362 | 308 |
363 size_t QuicSession::WriteHeaders(QuicStreamId id, | 309 size_t QuicSession::WriteHeaders(QuicStreamId id, |
364 const SpdyHeaderBlock& headers, | 310 const SpdyHeaderBlock& headers, |
365 bool fin) { | 311 bool fin) { |
366 DCHECK_LT(QUIC_VERSION_12, connection()->version()); | |
367 if (connection()->version() <= QUIC_VERSION_12) { | |
368 return 0; | |
369 } | |
370 return headers_stream_->WriteHeaders(id, headers, fin); | 312 return headers_stream_->WriteHeaders(id, headers, fin); |
371 } | 313 } |
372 | 314 |
373 void QuicSession::SendRstStream(QuicStreamId id, | 315 void QuicSession::SendRstStream(QuicStreamId id, |
374 QuicRstStreamErrorCode error, | 316 QuicRstStreamErrorCode error, |
375 QuicStreamOffset bytes_written) { | 317 QuicStreamOffset bytes_written) { |
376 connection_->SendRstStream(id, error, bytes_written); | 318 connection_->SendRstStream(id, error, bytes_written); |
377 CloseStreamInner(id, true); | 319 CloseStreamInner(id, true); |
378 } | 320 } |
379 | 321 |
(...skipping 15 matching lines...) Expand all Loading... |
395 DVLOG(1) << ENDPOINT << "Stream is already closed: " << stream_id; | 337 DVLOG(1) << ENDPOINT << "Stream is already closed: " << stream_id; |
396 return; | 338 return; |
397 } | 339 } |
398 QuicDataStream* stream = it->second; | 340 QuicDataStream* stream = it->second; |
399 | 341 |
400 // Tell the stream that a RST has been sent. | 342 // Tell the stream that a RST has been sent. |
401 if (locally_reset) { | 343 if (locally_reset) { |
402 stream->set_rst_sent(true); | 344 stream->set_rst_sent(true); |
403 } | 345 } |
404 | 346 |
405 if (connection_->version() <= QUIC_VERSION_12 && | |
406 connection_->connected() && !stream->headers_decompressed()) { | |
407 // If the stream is being closed locally (for example a client cancelling | |
408 // a request before receiving the response) then we need to make sure that | |
409 // we keep the stream alive long enough to process any response or | |
410 // RST_STREAM frames. | |
411 if (locally_reset && !is_server()) { | |
412 AddZombieStream(stream_id); | |
413 return; | |
414 } | |
415 | |
416 // This stream has been closed before the headers were decompressed. | |
417 // This might cause problems with head of line blocking of headers. | |
418 // If the peer sent headers which were lost but we now close the stream | |
419 // we will never be able to decompress headers for other streams. | |
420 // To deal with this, we keep track of streams which have been closed | |
421 // prematurely. If we ever receive data frames for this steam, then we | |
422 // know there actually has been a problem and we close the connection. | |
423 AddPrematurelyClosedStream(stream->id()); | |
424 } | |
425 closed_streams_.push_back(it->second); | 347 closed_streams_.push_back(it->second); |
426 if (ContainsKey(zombie_streams_, stream->id())) { | |
427 zombie_streams_.erase(stream->id()); | |
428 } | |
429 stream_map_.erase(it); | 348 stream_map_.erase(it); |
430 stream->OnClose(); | 349 stream->OnClose(); |
431 } | 350 } |
432 | 351 |
433 void QuicSession::AddZombieStream(QuicStreamId stream_id) { | |
434 if (zombie_streams_.size() == kMaxZombieStreams) { | |
435 QuicStreamId oldest_zombie_stream_id = zombie_streams_.begin()->first; | |
436 CloseZombieStream(oldest_zombie_stream_id); | |
437 // However, since the headers still have not been decompressed, we want to | |
438 // mark it a prematurely closed so that if we ever receive frames | |
439 // for this stream we can close the connection. | |
440 AddPrematurelyClosedStream(oldest_zombie_stream_id); | |
441 } | |
442 zombie_streams_.insert(make_pair(stream_id, true)); | |
443 } | |
444 | |
445 void QuicSession::CloseZombieStream(QuicStreamId stream_id) { | |
446 DCHECK(ContainsKey(zombie_streams_, stream_id)); | |
447 zombie_streams_.erase(stream_id); | |
448 QuicDataStream* stream = GetDataStream(stream_id); | |
449 if (!stream) { | |
450 return; | |
451 } | |
452 stream_map_.erase(stream_id); | |
453 stream->OnClose(); | |
454 closed_streams_.push_back(stream); | |
455 } | |
456 | |
457 void QuicSession::AddPrematurelyClosedStream(QuicStreamId stream_id) { | |
458 if (connection()->version() > QUIC_VERSION_12) { | |
459 return; | |
460 } | |
461 if (prematurely_closed_streams_.size() == | |
462 kMaxPrematurelyClosedStreamsTracked) { | |
463 prematurely_closed_streams_.erase(prematurely_closed_streams_.begin()); | |
464 } | |
465 prematurely_closed_streams_.insert(make_pair(stream_id, true)); | |
466 } | |
467 | |
468 bool QuicSession::IsEncryptionEstablished() { | 352 bool QuicSession::IsEncryptionEstablished() { |
469 return GetCryptoStream()->encryption_established(); | 353 return GetCryptoStream()->encryption_established(); |
470 } | 354 } |
471 | 355 |
472 bool QuicSession::IsCryptoHandshakeConfirmed() { | 356 bool QuicSession::IsCryptoHandshakeConfirmed() { |
473 return GetCryptoStream()->handshake_confirmed(); | 357 return GetCryptoStream()->handshake_confirmed(); |
474 } | 358 } |
475 | 359 |
476 void QuicSession::OnConfigNegotiated() { | 360 void QuicSession::OnConfigNegotiated() { |
477 connection_->SetFromConfig(config_); | 361 connection_->SetFromConfig(config_); |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
524 QuicStreamId QuicSession::GetNextStreamId() { | 408 QuicStreamId QuicSession::GetNextStreamId() { |
525 QuicStreamId id = next_stream_id_; | 409 QuicStreamId id = next_stream_id_; |
526 next_stream_id_ += 2; | 410 next_stream_id_ += 2; |
527 return id; | 411 return id; |
528 } | 412 } |
529 | 413 |
530 ReliableQuicStream* QuicSession::GetStream(const QuicStreamId stream_id) { | 414 ReliableQuicStream* QuicSession::GetStream(const QuicStreamId stream_id) { |
531 if (stream_id == kCryptoStreamId) { | 415 if (stream_id == kCryptoStreamId) { |
532 return GetCryptoStream(); | 416 return GetCryptoStream(); |
533 } | 417 } |
534 if (stream_id == kHeadersStreamId && | 418 if (stream_id == kHeadersStreamId) { |
535 connection_->version() > QUIC_VERSION_12) { | |
536 return headers_stream_.get(); | 419 return headers_stream_.get(); |
537 } | 420 } |
538 return GetDataStream(stream_id); | 421 return GetDataStream(stream_id); |
539 } | 422 } |
540 | 423 |
541 QuicDataStream* QuicSession::GetDataStream(const QuicStreamId stream_id) { | 424 QuicDataStream* QuicSession::GetDataStream(const QuicStreamId stream_id) { |
542 if (stream_id == kCryptoStreamId) { | 425 if (stream_id == kCryptoStreamId) { |
543 DLOG(FATAL) << "Attempt to call GetDataStream with the crypto stream id"; | 426 DLOG(FATAL) << "Attempt to call GetDataStream with the crypto stream id"; |
544 return NULL; | 427 return NULL; |
545 } | 428 } |
546 if (stream_id == kHeadersStreamId && | 429 if (stream_id == kHeadersStreamId) { |
547 connection_->version() > QUIC_VERSION_12) { | |
548 DLOG(FATAL) << "Attempt to call GetDataStream with the headers stream id"; | 430 DLOG(FATAL) << "Attempt to call GetDataStream with the headers stream id"; |
549 return NULL; | 431 return NULL; |
550 } | 432 } |
551 | 433 |
552 DataStreamMap::iterator it = stream_map_.find(stream_id); | 434 DataStreamMap::iterator it = stream_map_.find(stream_id); |
553 if (it != stream_map_.end()) { | 435 if (it != stream_map_.end()) { |
554 return it->second; | 436 return it->second; |
555 } | 437 } |
556 | 438 |
557 if (IsClosedStream(stream_id)) { | 439 if (IsClosedStream(stream_id)) { |
(...skipping 24 matching lines...) Expand all Loading... |
582 } | 464 } |
583 | 465 |
584 implicitly_created_streams_.erase(stream_id); | 466 implicitly_created_streams_.erase(stream_id); |
585 if (stream_id > largest_peer_created_stream_id_) { | 467 if (stream_id > largest_peer_created_stream_id_) { |
586 // TODO(rch) add unit test for this | 468 // TODO(rch) add unit test for this |
587 if (stream_id - largest_peer_created_stream_id_ > kMaxStreamIdDelta) { | 469 if (stream_id - largest_peer_created_stream_id_ > kMaxStreamIdDelta) { |
588 connection()->SendConnectionClose(QUIC_INVALID_STREAM_ID); | 470 connection()->SendConnectionClose(QUIC_INVALID_STREAM_ID); |
589 return NULL; | 471 return NULL; |
590 } | 472 } |
591 if (largest_peer_created_stream_id_ == 0) { | 473 if (largest_peer_created_stream_id_ == 0) { |
592 if (is_server() && connection()->version() > QUIC_VERSION_12) { | 474 if (is_server()) { |
593 largest_peer_created_stream_id_= 3; | 475 largest_peer_created_stream_id_= 3; |
594 } else { | 476 } else { |
595 largest_peer_created_stream_id_= 1; | 477 largest_peer_created_stream_id_= 1; |
596 } | 478 } |
597 } | 479 } |
598 for (QuicStreamId id = largest_peer_created_stream_id_ + 2; | 480 for (QuicStreamId id = largest_peer_created_stream_id_ + 2; |
599 id < stream_id; | 481 id < stream_id; |
600 id += 2) { | 482 id += 2) { |
601 implicitly_created_streams_.insert(id); | 483 implicitly_created_streams_.insert(id); |
602 } | 484 } |
603 largest_peer_created_stream_id_ = stream_id; | 485 largest_peer_created_stream_id_ = stream_id; |
604 } | 486 } |
605 QuicDataStream* stream = CreateIncomingDataStream(stream_id); | 487 QuicDataStream* stream = CreateIncomingDataStream(stream_id); |
606 if (stream == NULL) { | 488 if (stream == NULL) { |
607 return NULL; | 489 return NULL; |
608 } | 490 } |
609 ActivateStream(stream); | 491 ActivateStream(stream); |
610 return stream; | 492 return stream; |
611 } | 493 } |
612 | 494 |
613 bool QuicSession::IsClosedStream(QuicStreamId id) { | 495 bool QuicSession::IsClosedStream(QuicStreamId id) { |
614 DCHECK_NE(0u, id); | 496 DCHECK_NE(0u, id); |
615 if (id == kCryptoStreamId) { | 497 if (id == kCryptoStreamId) { |
616 return false; | 498 return false; |
617 } | 499 } |
618 if (connection()->version() > QUIC_VERSION_12) { | 500 if (id == kHeadersStreamId) { |
619 if (id == kHeadersStreamId) { | 501 return false; |
620 return false; | |
621 } | |
622 } | |
623 if (ContainsKey(zombie_streams_, id)) { | |
624 return true; | |
625 } | 502 } |
626 if (ContainsKey(stream_map_, id)) { | 503 if (ContainsKey(stream_map_, id)) { |
627 // Stream is active | 504 // Stream is active |
628 return false; | 505 return false; |
629 } | 506 } |
630 if (id % 2 == next_stream_id_ % 2) { | 507 if (id % 2 == next_stream_id_ % 2) { |
631 // Locally created streams are strictly in-order. If the id is in the | 508 // Locally created streams are strictly in-order. If the id is in the |
632 // range of created streams and it's not active, it must have been closed. | 509 // range of created streams and it's not active, it must have been closed. |
633 return id < next_stream_id_; | 510 return id < next_stream_id_; |
634 } | 511 } |
635 // For peer created streams, we also need to consider implicitly created | 512 // For peer created streams, we also need to consider implicitly created |
636 // streams. | 513 // streams. |
637 return id <= largest_peer_created_stream_id_ && | 514 return id <= largest_peer_created_stream_id_ && |
638 implicitly_created_streams_.count(id) == 0; | 515 implicitly_created_streams_.count(id) == 0; |
639 } | 516 } |
640 | 517 |
641 size_t QuicSession::GetNumOpenStreams() const { | 518 size_t QuicSession::GetNumOpenStreams() const { |
642 return stream_map_.size() + implicitly_created_streams_.size() - | 519 return stream_map_.size() + implicitly_created_streams_.size(); |
643 zombie_streams_.size(); | |
644 } | 520 } |
645 | 521 |
646 void QuicSession::MarkWriteBlocked(QuicStreamId id, QuicPriority priority) { | 522 void QuicSession::MarkWriteBlocked(QuicStreamId id, QuicPriority priority) { |
647 #ifndef NDEBUG | 523 #ifndef NDEBUG |
648 ReliableQuicStream* stream = GetStream(id); | 524 ReliableQuicStream* stream = GetStream(id); |
649 if (stream != NULL) { | 525 if (stream != NULL) { |
650 LOG_IF(DFATAL, priority != stream->EffectivePriority()) | 526 LOG_IF(DFATAL, priority != stream->EffectivePriority()) |
651 << "Priorities do not match. Got: " << priority | 527 << "Priorities do not match. Got: " << priority |
652 << " Expected: " << stream->EffectivePriority(); | 528 << " Expected: " << stream->EffectivePriority(); |
653 } else { | 529 } else { |
654 LOG(DFATAL) << "Marking unknown stream " << id << " blocked."; | 530 LOG(DFATAL) << "Marking unknown stream " << id << " blocked."; |
655 } | 531 } |
656 #endif | 532 #endif |
657 | 533 |
658 if (id == kCryptoStreamId) { | 534 if (id == kCryptoStreamId) { |
659 DCHECK(!has_pending_handshake_); | 535 DCHECK(!has_pending_handshake_); |
660 has_pending_handshake_ = true; | 536 has_pending_handshake_ = true; |
661 // TODO(jar): Be sure to use the highest priority for the crypto stream, | 537 // TODO(jar): Be sure to use the highest priority for the crypto stream, |
662 // perhaps by adding a "special" priority for it that is higher than | 538 // perhaps by adding a "special" priority for it that is higher than |
663 // kHighestPriority. | 539 // kHighestPriority. |
664 priority = kHighestPriority; | 540 priority = kHighestPriority; |
665 } | 541 } |
666 write_blocked_streams_.PushBack(id, priority, connection()->version()); | 542 write_blocked_streams_.PushBack(id, priority); |
667 } | 543 } |
668 | 544 |
669 bool QuicSession::HasDataToWrite() const { | 545 bool QuicSession::HasDataToWrite() const { |
670 return write_blocked_streams_.HasWriteBlockedStreams() || | 546 return write_blocked_streams_.HasWriteBlockedStreams() || |
671 connection_->HasQueuedData(); | 547 connection_->HasQueuedData(); |
672 } | 548 } |
673 | 549 |
674 void QuicSession::MarkDecompressionBlocked(QuicHeaderId header_id, | |
675 QuicStreamId stream_id) { | |
676 DCHECK_GE(QUIC_VERSION_12, connection()->version()); | |
677 decompression_blocked_streams_[header_id] = stream_id; | |
678 } | |
679 | |
680 bool QuicSession::GetSSLInfo(SSLInfo* ssl_info) { | 550 bool QuicSession::GetSSLInfo(SSLInfo* ssl_info) { |
681 NOTIMPLEMENTED(); | 551 NOTIMPLEMENTED(); |
682 return false; | 552 return false; |
683 } | 553 } |
684 | 554 |
685 void QuicSession::PostProcessAfterData() { | 555 void QuicSession::PostProcessAfterData() { |
686 STLDeleteElements(&closed_streams_); | 556 STLDeleteElements(&closed_streams_); |
687 closed_streams_.clear(); | 557 closed_streams_.clear(); |
688 } | 558 } |
689 | 559 |
690 } // namespace net | 560 } // namespace net |
OLD | NEW |