| 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" |
| (...skipping 15 matching lines...) Expand all Loading... |
| 26 // 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 |
| 27 // 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 |
| 28 // processing. | 28 // processing. |
| 29 // | 29 // |
| 30 // 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 |
| 31 // sure we don't miss any. | 31 // sure we don't miss any. |
| 32 class VisitorShim : public QuicConnectionVisitorInterface { | 32 class VisitorShim : public QuicConnectionVisitorInterface { |
| 33 public: | 33 public: |
| 34 explicit VisitorShim(QuicSession* session) : session_(session) {} | 34 explicit VisitorShim(QuicSession* session) : session_(session) {} |
| 35 | 35 |
| 36 virtual bool OnPacket(const IPEndPoint& self_address, | 36 virtual bool OnStreamFrames(const vector<QuicStreamFrame>& frames) OVERRIDE { |
| 37 const IPEndPoint& peer_address, | 37 bool accepted = session_->OnStreamFrames(frames); |
| 38 const QuicPacketHeader& header, | |
| 39 const vector<QuicStreamFrame>& frame) OVERRIDE { | |
| 40 bool accepted = session_->OnPacket(self_address, peer_address, header, | |
| 41 frame); | |
| 42 session_->PostProcessAfterData(); | 38 session_->PostProcessAfterData(); |
| 43 return accepted; | 39 return accepted; |
| 44 } | 40 } |
| 45 virtual void OnRstStream(const QuicRstStreamFrame& frame) OVERRIDE { | 41 virtual void OnRstStream(const QuicRstStreamFrame& frame) OVERRIDE { |
| 46 session_->OnRstStream(frame); | 42 session_->OnRstStream(frame); |
| 47 session_->PostProcessAfterData(); | 43 session_->PostProcessAfterData(); |
| 48 } | 44 } |
| 49 | 45 |
| 50 virtual void OnGoAway(const QuicGoAwayFrame& frame) OVERRIDE { | 46 virtual void OnGoAway(const QuicGoAwayFrame& frame) OVERRIDE { |
| 51 session_->OnGoAway(frame); | 47 session_->OnGoAway(frame); |
| 52 session_->PostProcessAfterData(); | 48 session_->PostProcessAfterData(); |
| 53 } | 49 } |
| 54 | 50 |
| 55 virtual void OnAck(const SequenceNumberSet& acked_packets) OVERRIDE { | |
| 56 session_->OnAck(acked_packets); | |
| 57 session_->PostProcessAfterData(); | |
| 58 } | |
| 59 | |
| 60 virtual bool OnCanWrite() OVERRIDE { | 51 virtual bool OnCanWrite() OVERRIDE { |
| 61 bool rc = session_->OnCanWrite(); | 52 bool rc = session_->OnCanWrite(); |
| 62 session_->PostProcessAfterData(); | 53 session_->PostProcessAfterData(); |
| 63 return rc; | 54 return rc; |
| 64 } | 55 } |
| 65 | 56 |
| 66 virtual void OnSuccessfulVersionNegotiation( | 57 virtual void OnSuccessfulVersionNegotiation( |
| 67 const QuicVersion& version) OVERRIDE { | 58 const QuicVersion& version) OVERRIDE { |
| 68 session_->OnSuccessfulVersionNegotiation(version); | 59 session_->OnSuccessfulVersionNegotiation(version); |
| 69 } | 60 } |
| 70 | 61 |
| 71 virtual void ConnectionClose(QuicErrorCode error, bool from_peer) OVERRIDE { | 62 virtual void ConnectionClose(QuicErrorCode error, bool from_peer) OVERRIDE { |
| 72 session_->ConnectionClose(error, from_peer); | 63 session_->ConnectionClose(error, from_peer); |
| 73 // The session will go away, so don't bother with cleanup. | 64 // The session will go away, so don't bother with cleanup. |
| 74 } | 65 } |
| 75 | 66 |
| 67 virtual bool HasPendingHandshake() const OVERRIDE { |
| 68 return session_->HasPendingHandshake(); |
| 69 } |
| 70 |
| 76 private: | 71 private: |
| 77 QuicSession* session_; | 72 QuicSession* session_; |
| 78 }; | 73 }; |
| 79 | 74 |
| 80 QuicSession::QuicSession(QuicConnection* connection, | 75 QuicSession::QuicSession(QuicConnection* connection, |
| 81 const QuicConfig& config, | 76 const QuicConfig& config, |
| 82 bool is_server) | 77 bool is_server) |
| 83 : connection_(connection), | 78 : connection_(connection), |
| 84 visitor_shim_(new VisitorShim(this)), | 79 visitor_shim_(new VisitorShim(this)), |
| 85 config_(config), | 80 config_(config), |
| 86 max_open_streams_(config_.max_streams_per_connection()), | 81 max_open_streams_(config_.max_streams_per_connection()), |
| 87 next_stream_id_(is_server ? 2 : 3), | 82 next_stream_id_(is_server ? 2 : 3), |
| 88 is_server_(is_server), | 83 is_server_(is_server), |
| 89 largest_peer_created_stream_id_(0), | 84 largest_peer_created_stream_id_(0), |
| 90 error_(QUIC_NO_ERROR), | 85 error_(QUIC_NO_ERROR), |
| 91 goaway_received_(false), | 86 goaway_received_(false), |
| 92 goaway_sent_(false) { | 87 goaway_sent_(false), |
| 88 has_pending_handshake_(false) { |
| 93 | 89 |
| 94 connection_->set_visitor(visitor_shim_.get()); | 90 connection_->set_visitor(visitor_shim_.get()); |
| 95 connection_->SetIdleNetworkTimeout(config_.idle_connection_state_lifetime()); | 91 connection_->SetIdleNetworkTimeout(config_.idle_connection_state_lifetime()); |
| 96 if (connection_->connected()) { | 92 if (connection_->connected()) { |
| 97 connection_->SetOverallConnectionTimeout( | 93 connection_->SetOverallConnectionTimeout( |
| 98 config_.max_time_before_crypto_handshake()); | 94 config_.max_time_before_crypto_handshake()); |
| 99 } | 95 } |
| 100 // TODO(satyamshekhar): Set congestion control and ICSL also. | 96 // TODO(satyamshekhar): Set congestion control and ICSL also. |
| 101 } | 97 } |
| 102 | 98 |
| 103 QuicSession::~QuicSession() { | 99 QuicSession::~QuicSession() { |
| 104 STLDeleteElements(&closed_streams_); | 100 STLDeleteElements(&closed_streams_); |
| 105 STLDeleteValues(&stream_map_); | 101 STLDeleteValues(&stream_map_); |
| 106 } | 102 } |
| 107 | 103 |
| 108 bool QuicSession::OnPacket(const IPEndPoint& self_address, | 104 bool QuicSession::OnStreamFrames(const vector<QuicStreamFrame>& frames) { |
| 109 const IPEndPoint& peer_address, | |
| 110 const QuicPacketHeader& header, | |
| 111 const vector<QuicStreamFrame>& frames) { | |
| 112 if (header.public_header.guid != connection()->guid()) { | |
| 113 DLOG(INFO) << ENDPOINT << "Got packet header for invalid GUID: " | |
| 114 << header.public_header.guid; | |
| 115 return false; | |
| 116 } | |
| 117 | |
| 118 for (size_t i = 0; i < frames.size(); ++i) { | 105 for (size_t i = 0; i < frames.size(); ++i) { |
| 119 // TODO(rch) deal with the error case of stream id 0 | 106 // TODO(rch) deal with the error case of stream id 0 |
| 120 if (IsClosedStream(frames[i].stream_id)) { | 107 if (IsClosedStream(frames[i].stream_id)) { |
| 121 // If we get additional frames for a stream where we didn't process | 108 // If we get additional frames for a stream where we didn't process |
| 122 // headers, it's highly likely our compression context will end up | 109 // headers, it's highly likely our compression context will end up |
| 123 // permanently out of sync with the peer's, so we give up and close the | 110 // permanently out of sync with the peer's, so we give up and close the |
| 124 // connection. | 111 // connection. |
| 125 if (ContainsKey(prematurely_closed_streams_, frames[i].stream_id)) { | 112 if (ContainsKey(prematurely_closed_streams_, frames[i].stream_id)) { |
| 126 connection()->SendConnectionClose( | 113 connection()->SendConnectionClose( |
| 127 QUIC_STREAM_RST_BEFORE_HEADERS_DECOMPRESSED); | 114 QUIC_STREAM_RST_BEFORE_HEADERS_DECOMPRESSED); |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 215 } | 202 } |
| 216 | 203 |
| 217 bool QuicSession::OnCanWrite() { | 204 bool QuicSession::OnCanWrite() { |
| 218 // We latch this here rather than doing a traditional loop, because streams | 205 // We latch this here rather than doing a traditional loop, because streams |
| 219 // may be modifying the list as we loop. | 206 // may be modifying the list as we loop. |
| 220 int remaining_writes = write_blocked_streams_.NumBlockedStreams(); | 207 int remaining_writes = write_blocked_streams_.NumBlockedStreams(); |
| 221 | 208 |
| 222 while (!connection_->HasQueuedData() && | 209 while (!connection_->HasQueuedData() && |
| 223 remaining_writes > 0) { | 210 remaining_writes > 0) { |
| 224 DCHECK(write_blocked_streams_.HasWriteBlockedStreams()); | 211 DCHECK(write_blocked_streams_.HasWriteBlockedStreams()); |
| 225 ReliableQuicStream* stream = NULL; | |
| 226 int index = write_blocked_streams_.GetHighestPriorityWriteBlockedList(); | 212 int index = write_blocked_streams_.GetHighestPriorityWriteBlockedList(); |
| 227 if (index != -1) { | 213 if (index == -1) { |
| 228 stream = GetStream(write_blocked_streams_.PopFront(index)); | 214 LOG(DFATAL) << "WriteBlockedStream is missing"; |
| 215 connection_->CloseConnection(QUIC_INTERNAL_ERROR, false); |
| 216 return true; // We have no write blocked streams. |
| 229 } | 217 } |
| 218 QuicStreamId stream_id = write_blocked_streams_.PopFront(index); |
| 219 if (stream_id == kCryptoStreamId) { |
| 220 has_pending_handshake_ = false; // We just popped it. |
| 221 } |
| 222 ReliableQuicStream* stream = GetStream(stream_id); |
| 230 if (stream != NULL) { | 223 if (stream != NULL) { |
| 231 // If the stream can't write all bytes, it'll re-add itself to the blocked | 224 // If the stream can't write all bytes, it'll re-add itself to the blocked |
| 232 // list. | 225 // list. |
| 233 stream->OnCanWrite(); | 226 stream->OnCanWrite(); |
| 234 } | 227 } |
| 235 --remaining_writes; | 228 --remaining_writes; |
| 236 } | 229 } |
| 237 | 230 |
| 238 return !write_blocked_streams_.HasWriteBlockedStreams(); | 231 return !write_blocked_streams_.HasWriteBlockedStreams(); |
| 239 } | 232 } |
| 240 | 233 |
| 234 bool QuicSession::HasPendingHandshake() const { |
| 235 return has_pending_handshake_; |
| 236 } |
| 237 |
| 241 QuicConsumedData QuicSession::WritevData(QuicStreamId id, | 238 QuicConsumedData QuicSession::WritevData(QuicStreamId id, |
| 242 const struct iovec* iov, | 239 const struct iovec* iov, |
| 243 int count, | 240 int iov_count, |
| 244 QuicStreamOffset offset, | 241 QuicStreamOffset offset, |
| 245 bool fin) { | 242 bool fin) { |
| 246 return connection_->SendvStreamData(id, iov, count, offset, fin); | 243 return connection_->SendvStreamData(id, iov, iov_count, offset, fin); |
| 247 } | 244 } |
| 248 | 245 |
| 249 void QuicSession::SendRstStream(QuicStreamId id, | 246 void QuicSession::SendRstStream(QuicStreamId id, |
| 250 QuicRstStreamErrorCode error) { | 247 QuicRstStreamErrorCode error) { |
| 251 connection_->SendRstStream(id, error); | 248 connection_->SendRstStream(id, error); |
| 252 CloseStreamInner(id, true); | 249 CloseStreamInner(id, true); |
| 253 } | 250 } |
| 254 | 251 |
| 255 void QuicSession::SendGoAway(QuicErrorCode error_code, const string& reason) { | 252 void QuicSession::SendGoAway(QuicErrorCode error_code, const string& reason) { |
| 256 goaway_sent_ = true; | 253 goaway_sent_ = true; |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 374 const CryptoHandshakeMessage& message) { | 371 const CryptoHandshakeMessage& message) { |
| 375 } | 372 } |
| 376 | 373 |
| 377 QuicConfig* QuicSession::config() { | 374 QuicConfig* QuicSession::config() { |
| 378 return &config_; | 375 return &config_; |
| 379 } | 376 } |
| 380 | 377 |
| 381 void QuicSession::ActivateStream(ReliableQuicStream* stream) { | 378 void QuicSession::ActivateStream(ReliableQuicStream* stream) { |
| 382 DLOG(INFO) << ENDPOINT << "num_streams: " << stream_map_.size() | 379 DLOG(INFO) << ENDPOINT << "num_streams: " << stream_map_.size() |
| 383 << ". activating " << stream->id(); | 380 << ". activating " << stream->id(); |
| 384 DCHECK(stream_map_.count(stream->id()) == 0); | 381 DCHECK_EQ(stream_map_.count(stream->id()), 0u); |
| 385 stream_map_[stream->id()] = stream; | 382 stream_map_[stream->id()] = stream; |
| 386 } | 383 } |
| 387 | 384 |
| 388 QuicStreamId QuicSession::GetNextStreamId() { | 385 QuicStreamId QuicSession::GetNextStreamId() { |
| 389 QuicStreamId id = next_stream_id_; | 386 QuicStreamId id = next_stream_id_; |
| 390 next_stream_id_ += 2; | 387 next_stream_id_ += 2; |
| 391 return id; | 388 return id; |
| 392 } | 389 } |
| 393 | 390 |
| 394 ReliableQuicStream* QuicSession::GetStream(const QuicStreamId stream_id) { | 391 ReliableQuicStream* QuicSession::GetStream(const QuicStreamId stream_id) { |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 474 return id <= largest_peer_created_stream_id_ && | 471 return id <= largest_peer_created_stream_id_ && |
| 475 implicitly_created_streams_.count(id) == 0; | 472 implicitly_created_streams_.count(id) == 0; |
| 476 } | 473 } |
| 477 | 474 |
| 478 size_t QuicSession::GetNumOpenStreams() const { | 475 size_t QuicSession::GetNumOpenStreams() const { |
| 479 return stream_map_.size() + implicitly_created_streams_.size() - | 476 return stream_map_.size() + implicitly_created_streams_.size() - |
| 480 zombie_streams_.size(); | 477 zombie_streams_.size(); |
| 481 } | 478 } |
| 482 | 479 |
| 483 void QuicSession::MarkWriteBlocked(QuicStreamId id, QuicPriority priority) { | 480 void QuicSession::MarkWriteBlocked(QuicStreamId id, QuicPriority priority) { |
| 481 if (id == kCryptoStreamId) { |
| 482 DCHECK(!has_pending_handshake_); |
| 483 has_pending_handshake_ = true; |
| 484 // TODO(jar): Be sure to use the highest priority for the crypto stream, |
| 485 // perhaps by adding a "special" priority for it that is higher than |
| 486 // kHighestPriority. |
| 487 priority = kHighestPriority; |
| 488 } |
| 484 write_blocked_streams_.PushBack(id, priority); | 489 write_blocked_streams_.PushBack(id, priority); |
| 485 } | 490 } |
| 486 | 491 |
| 487 void QuicSession::MarkDecompressionBlocked(QuicHeaderId header_id, | 492 void QuicSession::MarkDecompressionBlocked(QuicHeaderId header_id, |
| 488 QuicStreamId stream_id) { | 493 QuicStreamId stream_id) { |
| 489 decompression_blocked_streams_[header_id] = stream_id; | 494 decompression_blocked_streams_[header_id] = stream_id; |
| 490 } | 495 } |
| 491 | 496 |
| 492 bool QuicSession::GetSSLInfo(SSLInfo* ssl_info) { | 497 bool QuicSession::GetSSLInfo(SSLInfo* ssl_info) { |
| 493 NOTIMPLEMENTED(); | 498 NOTIMPLEMENTED(); |
| 494 return false; | 499 return false; |
| 495 } | 500 } |
| 496 | 501 |
| 497 void QuicSession::PostProcessAfterData() { | 502 void QuicSession::PostProcessAfterData() { |
| 498 STLDeleteElements(&closed_streams_); | 503 STLDeleteElements(&closed_streams_); |
| 499 closed_streams_.clear(); | 504 closed_streams_.clear(); |
| 500 } | 505 } |
| 501 | 506 |
| 502 } // namespace net | 507 } // namespace net |
| OLD | NEW |