| 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/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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |