Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(246)

Side by Side Diff: net/quic/quic_session.cc

Issue 23587004: If the stream is being closed locally (for example in the case of a (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix tests Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « net/quic/quic_session.h ('k') | net/quic/quic_session_test.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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/ssl/ssl_info.h" 10 #include "net/ssl/ssl_info.h"
11 11
12 using base::StringPiece; 12 using base::StringPiece;
13 using base::hash_map; 13 using base::hash_map;
14 using base::hash_set; 14 using base::hash_set;
15 using std::make_pair; 15 using std::make_pair;
16 using std::vector; 16 using std::vector;
17 17
18 namespace net { 18 namespace net {
19 19
20 const size_t kMaxPrematurelyClosedStreamsTracked = 20; 20 const size_t kMaxPrematurelyClosedStreamsTracked = 20;
21 const size_t kMaxZombieStreams = 20;
21 22
22 #define ENDPOINT (is_server_ ? "Server: " : " Client: ") 23 #define ENDPOINT (is_server_ ? "Server: " : " Client: ")
23 24
24 // We want to make sure we delete any closed streams in a safe manner. 25 // We want to make sure we delete any closed streams in a safe manner.
25 // To avoid deleting a stream in mid-operation, we have a simple shim between 26 // To avoid deleting a stream in mid-operation, we have a simple shim between
26 // us and the stream, so we can delete any streams when we return from 27 // us and the stream, so we can delete any streams when we return from
27 // processing. 28 // processing.
28 // 29 //
29 // We could just override the base methods, but this makes it easier to make 30 // We could just override the base methods, but this makes it easier to make
30 // sure we don't miss any. 31 // sure we don't miss any.
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
126 127
127 ReliableQuicStream* stream = GetStream(frames[i].stream_id); 128 ReliableQuicStream* stream = GetStream(frames[i].stream_id);
128 if (stream == NULL) return false; 129 if (stream == NULL) return false;
129 if (!stream->WillAcceptStreamFrame(frames[i])) return false; 130 if (!stream->WillAcceptStreamFrame(frames[i])) return false;
130 131
131 // TODO(alyssar) check against existing connection address: if changed, make 132 // TODO(alyssar) check against existing connection address: if changed, make
132 // sure we update the connection. 133 // sure we update the connection.
133 } 134 }
134 135
135 for (size_t i = 0; i < frames.size(); ++i) { 136 for (size_t i = 0; i < frames.size(); ++i) {
136 ReliableQuicStream* stream = GetStream(frames[i].stream_id); 137 QuicStreamId stream_id = frames[i].stream_id;
137 if (stream) { 138 ReliableQuicStream* stream = GetStream(stream_id);
138 stream->OnStreamFrame(frames[i]); 139 if (!stream) {
140 continue;
141 }
142 stream->OnStreamFrame(frames[i]);
143
144 // If the stream had been prematurely closed, and the
145 // headers are now decompressed, then we are finally finished
146 // with this stream.
147 if (ContainsKey(zombie_streams_, stream_id) &&
148 stream->headers_decompressed()) {
149 CloseZombieStream(stream_id);
139 } 150 }
140 } 151 }
141 152
142 while (!decompression_blocked_streams_.empty()) { 153 while (!decompression_blocked_streams_.empty()) {
143 QuicHeaderId header_id = decompression_blocked_streams_.begin()->first; 154 QuicHeaderId header_id = decompression_blocked_streams_.begin()->first;
144 if (header_id != decompressor_.current_header_id()) { 155 if (header_id != decompressor_.current_header_id()) {
145 break; 156 break;
146 } 157 }
147 QuicStreamId stream_id = decompression_blocked_streams_.begin()->second; 158 QuicStreamId stream_id = decompression_blocked_streams_.begin()->second;
148 decompression_blocked_streams_.erase(header_id); 159 decompression_blocked_streams_.erase(header_id);
149 ReliableQuicStream* stream = GetStream(stream_id); 160 ReliableQuicStream* stream = GetStream(stream_id);
150 if (!stream) { 161 if (!stream) {
151 connection()->SendConnectionClose( 162 connection()->SendConnectionClose(
152 QUIC_STREAM_RST_BEFORE_HEADERS_DECOMPRESSED); 163 QUIC_STREAM_RST_BEFORE_HEADERS_DECOMPRESSED);
153 return false; 164 return false;
154 } 165 }
155 stream->OnDecompressorAvailable(); 166 stream->OnDecompressorAvailable();
156 } 167 }
157 return true; 168 return true;
158 } 169 }
159 170
160 void QuicSession::OnRstStream(const QuicRstStreamFrame& frame) { 171 void QuicSession::OnRstStream(const QuicRstStreamFrame& frame) {
161 ReliableQuicStream* stream = GetStream(frame.stream_id); 172 ReliableQuicStream* stream = GetStream(frame.stream_id);
162 if (!stream) { 173 if (!stream) {
163 return; // Errors are handled by GetStream. 174 return; // Errors are handled by GetStream.
164 } 175 }
176 if (ContainsKey(zombie_streams_, stream->id())) {
177 // If this was a zombie stream then we close it out now.
178 CloseZombieStream(stream->id());
179 // However, since the headers still have not been decompressed, we want to
180 // mark it a prematurely closed so that if we ever receive frames
181 // for this stream we can close the connection.
182 DCHECK(!stream->headers_decompressed());
183 AddPrematurelyClosedStream(frame.stream_id);
184 return;
185 }
165 stream->OnStreamReset(frame.error_code); 186 stream->OnStreamReset(frame.error_code);
166 } 187 }
167 188
168 void QuicSession::OnGoAway(const QuicGoAwayFrame& frame) { 189 void QuicSession::OnGoAway(const QuicGoAwayFrame& frame) {
169 DCHECK(frame.last_good_stream_id < next_stream_id_); 190 DCHECK(frame.last_good_stream_id < next_stream_id_);
170 goaway_received_ = true; 191 goaway_received_ = true;
171 } 192 }
172 193
173 void QuicSession::ConnectionClose(QuicErrorCode error, bool from_peer) { 194 void QuicSession::ConnectionClose(QuicErrorCode error, bool from_peer) {
195 DCHECK(!connection_->connected());
174 if (error_ == QUIC_NO_ERROR) { 196 if (error_ == QUIC_NO_ERROR) {
175 error_ = error; 197 error_ = error;
176 } 198 }
177 199
178 while (stream_map_.size() != 0) { 200 while (stream_map_.size() != 0) {
179 ReliableStreamMap::iterator it = stream_map_.begin(); 201 ReliableStreamMap::iterator it = stream_map_.begin();
180 QuicStreamId id = it->first; 202 QuicStreamId id = it->first;
181 it->second->ConnectionClose(error, from_peer); 203 it->second->ConnectionClose(error, from_peer);
182 // The stream should call CloseStream as part of ConnectionClose. 204 // The stream should call CloseStream as part of ConnectionClose.
183 if (stream_map_.find(id) != stream_map_.end()) { 205 if (stream_map_.find(id) != stream_map_.end()) {
(...skipping 30 matching lines...) Expand all
214 QuicConsumedData QuicSession::WriteData(QuicStreamId id, 236 QuicConsumedData QuicSession::WriteData(QuicStreamId id,
215 StringPiece data, 237 StringPiece data,
216 QuicStreamOffset offset, 238 QuicStreamOffset offset,
217 bool fin) { 239 bool fin) {
218 return connection_->SendStreamData(id, data, offset, fin); 240 return connection_->SendStreamData(id, data, offset, fin);
219 } 241 }
220 242
221 void QuicSession::SendRstStream(QuicStreamId id, 243 void QuicSession::SendRstStream(QuicStreamId id,
222 QuicRstStreamErrorCode error) { 244 QuicRstStreamErrorCode error) {
223 connection_->SendRstStream(id, error); 245 connection_->SendRstStream(id, error);
224 CloseStream(id); 246 CloseStreamInner(id, true);
225 } 247 }
226 248
227 void QuicSession::SendGoAway(QuicErrorCode error_code, const string& reason) { 249 void QuicSession::SendGoAway(QuicErrorCode error_code, const string& reason) {
228 goaway_sent_ = true; 250 goaway_sent_ = true;
229 connection_->SendGoAway(error_code, largest_peer_created_stream_id_, reason); 251 connection_->SendGoAway(error_code, largest_peer_created_stream_id_, reason);
230 } 252 }
231 253
232 void QuicSession::CloseStream(QuicStreamId stream_id) { 254 void QuicSession::CloseStream(QuicStreamId stream_id) {
255 CloseStreamInner(stream_id, false);
256 }
257
258 void QuicSession::CloseStreamInner(QuicStreamId stream_id,
259 bool locally_reset) {
233 DLOG(INFO) << ENDPOINT << "Closing stream " << stream_id; 260 DLOG(INFO) << ENDPOINT << "Closing stream " << stream_id;
234 261
235 ReliableStreamMap::iterator it = stream_map_.find(stream_id); 262 ReliableStreamMap::iterator it = stream_map_.find(stream_id);
236 if (it == stream_map_.end()) { 263 if (it == stream_map_.end()) {
237 DLOG(INFO) << ENDPOINT << "Stream is already closed: " << stream_id; 264 DLOG(INFO) << ENDPOINT << "Stream is already closed: " << stream_id;
238 return; 265 return;
239 } 266 }
240 ReliableQuicStream* stream = it->second; 267 ReliableQuicStream* stream = it->second;
241 if (!stream->headers_decompressed()) { 268 if (connection_->connected() && !stream->headers_decompressed()) {
242 if (prematurely_closed_streams_.size() == 269 // If the stream is being closed locally (for example a client cancelling
243 kMaxPrematurelyClosedStreamsTracked) { 270 // a request before receiving the response) then we need to make sure that
244 prematurely_closed_streams_.erase(prematurely_closed_streams_.begin()); 271 // we keep the stream alive long enough to process any response or
272 // RST_STREAM frames.
273 if (locally_reset && !is_server_) {
274 AddZombieStream(stream_id);
275 return;
245 } 276 }
246 prematurely_closed_streams_.insert(make_pair(stream->id(), true)); 277
278 // This stream has been closed before the headers were decompressed.
279 // This might cause problems with head of line blocking of headers.
280 // If the peer sent headers which were lost but we now close the stream
281 // we will never be able to decompress headers for other streams.
282 // To deal with this, we keep track of streams which have been closed
283 // prematurely. If we ever receive data frames for this steam, then we
284 // know there actually has been a problem and we close the connection.
285 AddPrematurelyClosedStream(stream->id());
247 } 286 }
248 closed_streams_.push_back(it->second); 287 closed_streams_.push_back(it->second);
249 stream_map_.erase(it); 288 stream_map_.erase(it);
250 stream->OnClose(); 289 stream->OnClose();
251 } 290 }
252 291
292 void QuicSession::AddZombieStream(QuicStreamId stream_id) {
293 if (zombie_streams_.size() == kMaxZombieStreams) {
294 QuicStreamId oldest_zombie_stream_id = zombie_streams_.begin()->first;
295 CloseZombieStream(oldest_zombie_stream_id);
296 // However, since the headers still have not been decompressed, we want to
297 // mark it a prematurely closed so that if we ever receive frames
298 // for this stream we can close the connection.
299 AddPrematurelyClosedStream(oldest_zombie_stream_id);
300 }
301 zombie_streams_.insert(make_pair(stream_id, true));
302 }
303
304 void QuicSession::CloseZombieStream(QuicStreamId stream_id) {
305 DCHECK(ContainsKey(zombie_streams_, stream_id));
306 zombie_streams_.erase(stream_id);
307 ReliableQuicStream* stream = GetStream(stream_id);
308 if (!stream) {
309 return;
310 }
311 stream_map_.erase(stream_id);
312 stream->OnClose();
313 closed_streams_.push_back(stream);
314 }
315
316 void QuicSession::AddPrematurelyClosedStream(QuicStreamId stream_id) {
317 if (prematurely_closed_streams_.size() ==
318 kMaxPrematurelyClosedStreamsTracked) {
319 prematurely_closed_streams_.erase(prematurely_closed_streams_.begin());
320 }
321 prematurely_closed_streams_.insert(make_pair(stream_id, true));
322 }
323
253 bool QuicSession::IsEncryptionEstablished() { 324 bool QuicSession::IsEncryptionEstablished() {
254 return GetCryptoStream()->encryption_established(); 325 return GetCryptoStream()->encryption_established();
255 } 326 }
256 327
257 bool QuicSession::IsCryptoHandshakeConfirmed() { 328 bool QuicSession::IsCryptoHandshakeConfirmed() {
258 return GetCryptoStream()->handshake_confirmed(); 329 return GetCryptoStream()->handshake_confirmed();
259 } 330 }
260 331
261 void QuicSession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) { 332 void QuicSession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) {
262 switch (event) { 333 switch (event) {
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after
369 } 440 }
370 ActivateStream(stream); 441 ActivateStream(stream);
371 return stream; 442 return stream;
372 } 443 }
373 444
374 bool QuicSession::IsClosedStream(QuicStreamId id) { 445 bool QuicSession::IsClosedStream(QuicStreamId id) {
375 DCHECK_NE(0u, id); 446 DCHECK_NE(0u, id);
376 if (id == kCryptoStreamId) { 447 if (id == kCryptoStreamId) {
377 return false; 448 return false;
378 } 449 }
379 if (stream_map_.count(id) != 0) { 450 if (ContainsKey(zombie_streams_, id)) {
451 return true;
452 }
453 if (ContainsKey(stream_map_, id)) {
380 // Stream is active 454 // Stream is active
381 return false; 455 return false;
382 } 456 }
383 if (id % 2 == next_stream_id_ % 2) { 457 if (id % 2 == next_stream_id_ % 2) {
384 // Locally created streams are strictly in-order. If the id is in the 458 // Locally created streams are strictly in-order. If the id is in the
385 // range of created streams and it's not active, it must have been closed. 459 // range of created streams and it's not active, it must have been closed.
386 return id < next_stream_id_; 460 return id < next_stream_id_;
387 } 461 }
388 // For peer created streams, we also need to consider implicitly created 462 // For peer created streams, we also need to consider implicitly created
389 // streams. 463 // streams.
390 return id <= largest_peer_created_stream_id_ && 464 return id <= largest_peer_created_stream_id_ &&
391 implicitly_created_streams_.count(id) == 0; 465 implicitly_created_streams_.count(id) == 0;
392 } 466 }
393 467
394 size_t QuicSession::GetNumOpenStreams() const { 468 size_t QuicSession::GetNumOpenStreams() const {
395 return stream_map_.size() + implicitly_created_streams_.size(); 469 return stream_map_.size() + implicitly_created_streams_.size() -
470 zombie_streams_.size();
396 } 471 }
397 472
398 void QuicSession::MarkWriteBlocked(QuicStreamId id) { 473 void QuicSession::MarkWriteBlocked(QuicStreamId id) {
399 write_blocked_streams_.PushBack(id, 0); 474 write_blocked_streams_.PushBack(id, 0);
400 } 475 }
401 476
402 void QuicSession::MarkDecompressionBlocked(QuicHeaderId header_id, 477 void QuicSession::MarkDecompressionBlocked(QuicHeaderId header_id,
403 QuicStreamId stream_id) { 478 QuicStreamId stream_id) {
404 decompression_blocked_streams_[header_id] = stream_id; 479 decompression_blocked_streams_[header_id] = stream_id;
405 } 480 }
406 481
407 bool QuicSession::GetSSLInfo(SSLInfo* ssl_info) { 482 bool QuicSession::GetSSLInfo(SSLInfo* ssl_info) {
408 NOTIMPLEMENTED(); 483 NOTIMPLEMENTED();
409 return false; 484 return false;
410 } 485 }
411 486
412 void QuicSession::PostProcessAfterData() { 487 void QuicSession::PostProcessAfterData() {
413 STLDeleteElements(&closed_streams_); 488 STLDeleteElements(&closed_streams_);
414 closed_streams_.clear(); 489 closed_streams_.clear();
415 } 490 }
416 491
417 } // namespace net 492 } // namespace net
OLDNEW
« no previous file with comments | « net/quic/quic_session.h ('k') | net/quic/quic_session_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698