blob: 34a668d5d47b9ad5c068dd08e7d78dc068d82b8d [file] [log] [blame]
James Robinson646469d2014-10-03 15:33:28 -07001// 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
3// found in the LICENSE file.
4
5#include "net/quic/quic_session.h"
6
7#include "base/stl_util.h"
8#include "net/quic/crypto/proof_verifier.h"
9#include "net/quic/quic_connection.h"
10#include "net/quic/quic_flags.h"
11#include "net/quic/quic_flow_controller.h"
12#include "net/quic/quic_headers_stream.h"
13#include "net/ssl/ssl_info.h"
14
15using base::StringPiece;
16using base::hash_map;
17using base::hash_set;
18using std::make_pair;
19using std::max;
20using std::vector;
21
22namespace net {
23
24#define ENDPOINT (is_server() ? "Server: " : " Client: ")
25
26// 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
28// us and the stream, so we can delete any streams when we return from
29// processing.
30//
31// We could just override the base methods, but this makes it easier to make
32// sure we don't miss any.
33class VisitorShim : public QuicConnectionVisitorInterface {
34 public:
35 explicit VisitorShim(QuicSession* session) : session_(session) {}
36
James Robinsone1b30cf2014-10-21 12:25:40 -070037 void OnStreamFrames(const vector<QuicStreamFrame>& frames) override {
James Robinson646469d2014-10-03 15:33:28 -070038 session_->OnStreamFrames(frames);
39 session_->PostProcessAfterData();
40 }
James Robinsone1b30cf2014-10-21 12:25:40 -070041 void OnRstStream(const QuicRstStreamFrame& frame) override {
James Robinson646469d2014-10-03 15:33:28 -070042 session_->OnRstStream(frame);
43 session_->PostProcessAfterData();
44 }
45
James Robinsone1b30cf2014-10-21 12:25:40 -070046 void OnGoAway(const QuicGoAwayFrame& frame) override {
James Robinson646469d2014-10-03 15:33:28 -070047 session_->OnGoAway(frame);
48 session_->PostProcessAfterData();
49 }
50
James Robinson74f9f1f2014-11-04 11:17:49 -080051 void OnWindowUpdateFrames(const vector<QuicWindowUpdateFrame>& frames)
52 override {
James Robinson646469d2014-10-03 15:33:28 -070053 session_->OnWindowUpdateFrames(frames);
54 session_->PostProcessAfterData();
55 }
56
James Robinsone1b30cf2014-10-21 12:25:40 -070057 void OnBlockedFrames(const vector<QuicBlockedFrame>& frames) override {
James Robinson646469d2014-10-03 15:33:28 -070058 session_->OnBlockedFrames(frames);
59 session_->PostProcessAfterData();
60 }
61
James Robinsone1b30cf2014-10-21 12:25:40 -070062 void OnCanWrite() override {
James Robinson646469d2014-10-03 15:33:28 -070063 session_->OnCanWrite();
64 session_->PostProcessAfterData();
65 }
66
James Robinsone1b30cf2014-10-21 12:25:40 -070067 void OnCongestionWindowChange(QuicTime now) override {
James Robinson646469d2014-10-03 15:33:28 -070068 session_->OnCongestionWindowChange(now);
69 }
70
James Robinsone1b30cf2014-10-21 12:25:40 -070071 void OnSuccessfulVersionNegotiation(const QuicVersion& version) override {
James Robinson646469d2014-10-03 15:33:28 -070072 session_->OnSuccessfulVersionNegotiation(version);
73 }
74
James Robinsone1b30cf2014-10-21 12:25:40 -070075 void OnConnectionClosed(QuicErrorCode error, bool from_peer) override {
James Robinson646469d2014-10-03 15:33:28 -070076 session_->OnConnectionClosed(error, from_peer);
77 // The session will go away, so don't bother with cleanup.
78 }
79
James Robinsone1b30cf2014-10-21 12:25:40 -070080 void OnWriteBlocked() override { session_->OnWriteBlocked(); }
James Robinson646469d2014-10-03 15:33:28 -070081
James Robinsone1b30cf2014-10-21 12:25:40 -070082 bool WillingAndAbleToWrite() const override {
James Robinson646469d2014-10-03 15:33:28 -070083 return session_->WillingAndAbleToWrite();
84 }
85
James Robinsone1b30cf2014-10-21 12:25:40 -070086 bool HasPendingHandshake() const override {
James Robinson646469d2014-10-03 15:33:28 -070087 return session_->HasPendingHandshake();
88 }
89
James Robinsone1b30cf2014-10-21 12:25:40 -070090 bool HasOpenDataStreams() const override {
James Robinson646469d2014-10-03 15:33:28 -070091 return session_->HasOpenDataStreams();
92 }
93
94 private:
95 QuicSession* session_;
96};
97
James Robinson1ae030a2014-11-07 08:32:47 -080098QuicSession::QuicSession(QuicConnection* connection, const QuicConfig& config,
99 bool is_secure)
James Robinson646469d2014-10-03 15:33:28 -0700100 : connection_(connection),
101 visitor_shim_(new VisitorShim(this)),
102 config_(config),
103 max_open_streams_(config_.MaxStreamsPerConnection()),
104 next_stream_id_(is_server() ? 2 : 5),
105 largest_peer_created_stream_id_(0),
106 error_(QUIC_NO_ERROR),
107 goaway_received_(false),
108 goaway_sent_(false),
James Robinson1ae030a2014-11-07 08:32:47 -0800109 has_pending_handshake_(false),
110 is_secure_(is_secure) {
James Robinsone1b30cf2014-10-21 12:25:40 -0700111 if (connection_->version() == QUIC_VERSION_19) {
James Robinson646469d2014-10-03 15:33:28 -0700112 flow_controller_.reset(new QuicFlowController(
113 connection_.get(), 0, is_server(), kDefaultFlowControlSendWindow,
114 config_.GetInitialFlowControlWindowToSend(),
115 config_.GetInitialFlowControlWindowToSend()));
116 } else {
117 flow_controller_.reset(new QuicFlowController(
118 connection_.get(), 0, is_server(), kDefaultFlowControlSendWindow,
119 config_.GetInitialSessionFlowControlWindowToSend(),
120 config_.GetInitialSessionFlowControlWindowToSend()));
121 }
122}
123
124void QuicSession::InitializeSession() {
125 connection_->set_visitor(visitor_shim_.get());
126 connection_->SetFromConfig(config_);
127 if (!FLAGS_quic_unified_timeouts && connection_->connected()) {
128 connection_->SetOverallConnectionTimeout(
129 config_.max_time_before_crypto_handshake());
130 }
131 headers_stream_.reset(new QuicHeadersStream(this));
132}
133
134QuicSession::~QuicSession() {
135 STLDeleteElements(&closed_streams_);
136 STLDeleteValues(&stream_map_);
137
138 DLOG_IF(WARNING,
139 locally_closed_streams_highest_offset_.size() > max_open_streams_)
140 << "Surprisingly high number of locally closed streams still waiting for "
141 "final byte offset: " << locally_closed_streams_highest_offset_.size();
142}
143
144void QuicSession::OnStreamFrames(const vector<QuicStreamFrame>& frames) {
145 for (size_t i = 0; i < frames.size(); ++i) {
146 // TODO(rch) deal with the error case of stream id 0.
147 const QuicStreamFrame& frame = frames[i];
148 QuicStreamId stream_id = frame.stream_id;
149 ReliableQuicStream* stream = GetStream(stream_id);
150 if (!stream) {
151 // The stream no longer exists, but we may still be interested in the
152 // final stream byte offset sent by the peer. A frame with a FIN can give
153 // us this offset.
154 if (frame.fin) {
155 QuicStreamOffset final_byte_offset =
156 frame.offset + frame.data.TotalBufferSize();
157 UpdateFlowControlOnFinalReceivedByteOffset(stream_id,
158 final_byte_offset);
159 }
160
161 continue;
162 }
163 stream->OnStreamFrame(frames[i]);
164 }
165}
166
167void QuicSession::OnStreamHeaders(QuicStreamId stream_id,
168 StringPiece headers_data) {
169 QuicDataStream* stream = GetDataStream(stream_id);
170 if (!stream) {
171 // It's quite possible to receive headers after a stream has been reset.
172 return;
173 }
174 stream->OnStreamHeaders(headers_data);
175}
176
177void QuicSession::OnStreamHeadersPriority(QuicStreamId stream_id,
178 QuicPriority priority) {
179 QuicDataStream* stream = GetDataStream(stream_id);
180 if (!stream) {
181 // It's quite possible to receive headers after a stream has been reset.
182 return;
183 }
184 stream->OnStreamHeadersPriority(priority);
185}
186
187void QuicSession::OnStreamHeadersComplete(QuicStreamId stream_id,
188 bool fin,
189 size_t frame_len) {
190 QuicDataStream* stream = GetDataStream(stream_id);
191 if (!stream) {
192 // It's quite possible to receive headers after a stream has been reset.
193 return;
194 }
195 stream->OnStreamHeadersComplete(fin, frame_len);
196}
197
198void QuicSession::OnRstStream(const QuicRstStreamFrame& frame) {
199 if (frame.stream_id == kCryptoStreamId) {
200 connection()->SendConnectionCloseWithDetails(
201 QUIC_INVALID_STREAM_ID,
202 "Attempt to reset the crypto stream");
203 return;
204 }
205 if (frame.stream_id == kHeadersStreamId) {
206 connection()->SendConnectionCloseWithDetails(
207 QUIC_INVALID_STREAM_ID,
208 "Attempt to reset the headers stream");
209 return;
210 }
211
212 QuicDataStream* stream = GetDataStream(frame.stream_id);
213 if (!stream) {
214 // The RST frame contains the final byte offset for the stream: we can now
215 // update the connection level flow controller if needed.
216 UpdateFlowControlOnFinalReceivedByteOffset(frame.stream_id,
217 frame.byte_offset);
218 return; // Errors are handled by GetStream.
219 }
220
221 stream->OnStreamReset(frame);
222}
223
224void QuicSession::OnGoAway(const QuicGoAwayFrame& frame) {
225 DCHECK(frame.last_good_stream_id < next_stream_id_);
226 goaway_received_ = true;
227}
228
229void QuicSession::OnConnectionClosed(QuicErrorCode error, bool from_peer) {
230 DCHECK(!connection_->connected());
231 if (error_ == QUIC_NO_ERROR) {
232 error_ = error;
233 }
234
235 while (!stream_map_.empty()) {
236 DataStreamMap::iterator it = stream_map_.begin();
237 QuicStreamId id = it->first;
238 it->second->OnConnectionClosed(error, from_peer);
239 // The stream should call CloseStream as part of OnConnectionClosed.
240 if (stream_map_.find(id) != stream_map_.end()) {
241 LOG(DFATAL) << ENDPOINT
242 << "Stream failed to close under OnConnectionClosed";
243 CloseStream(id);
244 }
245 }
246}
247
248void QuicSession::OnWindowUpdateFrames(
249 const vector<QuicWindowUpdateFrame>& frames) {
250 bool connection_window_updated = false;
251 for (size_t i = 0; i < frames.size(); ++i) {
252 // Stream may be closed by the time we receive a WINDOW_UPDATE, so we can't
253 // assume that it still exists.
254 QuicStreamId stream_id = frames[i].stream_id;
255 if (stream_id == kConnectionLevelId) {
256 // This is a window update that applies to the connection, rather than an
257 // individual stream.
258 DVLOG(1) << ENDPOINT
259 << "Received connection level flow control window update with "
260 "byte offset: " << frames[i].byte_offset;
261 if (flow_controller_->UpdateSendWindowOffset(frames[i].byte_offset)) {
262 connection_window_updated = true;
263 }
264 continue;
265 }
266
267 if (connection_->version() < QUIC_VERSION_21 &&
268 (stream_id == kCryptoStreamId || stream_id == kHeadersStreamId)) {
269 DLOG(DFATAL) << "WindowUpdate for stream " << stream_id << " in version "
270 << QuicVersionToString(connection_->version());
271 return;
272 }
273
274 ReliableQuicStream* stream = GetStream(stream_id);
275 if (stream) {
276 stream->OnWindowUpdateFrame(frames[i]);
277 }
278 }
279
280 // Connection level flow control window has increased, so blocked streams can
281 // write again.
282 if (connection_window_updated) {
283 OnCanWrite();
284 }
285}
286
287void QuicSession::OnBlockedFrames(const vector<QuicBlockedFrame>& frames) {
288 for (size_t i = 0; i < frames.size(); ++i) {
289 // TODO(rjshade): Compare our flow control receive windows for specified
290 // streams: if we have a large window then maybe something
291 // had gone wrong with the flow control accounting.
292 DVLOG(1) << ENDPOINT << "Received BLOCKED frame with stream id: "
293 << frames[i].stream_id;
294 }
295}
296
297void QuicSession::OnCanWrite() {
298 // We limit the number of writes to the number of pending streams. If more
299 // streams become pending, WillingAndAbleToWrite will be true, which will
300 // cause the connection to request resumption before yielding to other
301 // connections.
302 size_t num_writes = write_blocked_streams_.NumBlockedStreams();
303 if (flow_controller_->IsBlocked()) {
304 // If we are connection level flow control blocked, then only allow the
305 // crypto and headers streams to try writing as all other streams will be
306 // blocked.
307 num_writes = 0;
308 if (write_blocked_streams_.crypto_stream_blocked()) {
309 num_writes += 1;
310 }
311 if (write_blocked_streams_.headers_stream_blocked()) {
312 num_writes += 1;
313 }
314 }
315 if (num_writes == 0) {
316 return;
317 }
318
319 QuicConnection::ScopedPacketBundler ack_bundler(
320 connection_.get(), QuicConnection::NO_ACK);
321 for (size_t i = 0; i < num_writes; ++i) {
322 if (!(write_blocked_streams_.HasWriteBlockedCryptoOrHeadersStream() ||
323 write_blocked_streams_.HasWriteBlockedDataStreams())) {
324 // Writing one stream removed another!? Something's broken.
325 LOG(DFATAL) << "WriteBlockedStream is missing";
326 connection_->CloseConnection(QUIC_INTERNAL_ERROR, false);
327 return;
328 }
329 if (!connection_->CanWriteStreamData()) {
330 return;
331 }
332 QuicStreamId stream_id = write_blocked_streams_.PopFront();
333 if (stream_id == kCryptoStreamId) {
334 has_pending_handshake_ = false; // We just popped it.
335 }
336 ReliableQuicStream* stream = GetStream(stream_id);
337 if (stream != nullptr && !stream->flow_controller()->IsBlocked()) {
338 // If the stream can't write all bytes, it'll re-add itself to the blocked
339 // list.
340 stream->OnCanWrite();
341 }
342 }
343}
344
345bool QuicSession::WillingAndAbleToWrite() const {
346 // If the crypto or headers streams are blocked, we want to schedule a write -
347 // they don't get blocked by connection level flow control. Otherwise only
348 // schedule a write if we are not flow control blocked at the connection
349 // level.
350 return write_blocked_streams_.HasWriteBlockedCryptoOrHeadersStream() ||
351 (!flow_controller_->IsBlocked() &&
352 write_blocked_streams_.HasWriteBlockedDataStreams());
353}
354
355bool QuicSession::HasPendingHandshake() const {
356 return has_pending_handshake_;
357}
358
359bool QuicSession::HasOpenDataStreams() const {
360 return GetNumOpenStreams() > 0;
361}
362
363QuicConsumedData QuicSession::WritevData(
364 QuicStreamId id,
365 const IOVector& data,
366 QuicStreamOffset offset,
367 bool fin,
368 FecProtection fec_protection,
369 QuicAckNotifier::DelegateInterface* ack_notifier_delegate) {
370 return connection_->SendStreamData(id, data, offset, fin, fec_protection,
371 ack_notifier_delegate);
372}
373
374size_t QuicSession::WriteHeaders(
375 QuicStreamId id,
376 const SpdyHeaderBlock& headers,
377 bool fin,
378 QuicAckNotifier::DelegateInterface* ack_notifier_delegate) {
379 return headers_stream_->WriteHeaders(id, headers, fin, ack_notifier_delegate);
380}
381
382void QuicSession::SendRstStream(QuicStreamId id,
383 QuicRstStreamErrorCode error,
384 QuicStreamOffset bytes_written) {
385 if (connection()->connected()) {
386 // Only send a RST_STREAM frame if still connected.
387 connection_->SendRstStream(id, error, bytes_written);
388 }
389 CloseStreamInner(id, true);
390}
391
392void QuicSession::SendGoAway(QuicErrorCode error_code, const string& reason) {
393 if (goaway_sent_) {
394 return;
395 }
396 goaway_sent_ = true;
397 connection_->SendGoAway(error_code, largest_peer_created_stream_id_, reason);
398}
399
400void QuicSession::CloseStream(QuicStreamId stream_id) {
401 CloseStreamInner(stream_id, false);
402}
403
404void QuicSession::CloseStreamInner(QuicStreamId stream_id,
405 bool locally_reset) {
406 DVLOG(1) << ENDPOINT << "Closing stream " << stream_id;
407
408 DataStreamMap::iterator it = stream_map_.find(stream_id);
409 if (it == stream_map_.end()) {
410 DVLOG(1) << ENDPOINT << "Stream is already closed: " << stream_id;
411 return;
412 }
413 QuicDataStream* stream = it->second;
414
415 // Tell the stream that a RST has been sent.
416 if (locally_reset) {
417 stream->set_rst_sent(true);
418 }
419
420 closed_streams_.push_back(it->second);
421
422 // If we haven't received a FIN or RST for this stream, we need to keep track
423 // of the how many bytes the stream's flow controller believes it has
424 // received, for accurate connection level flow control accounting.
425 if (!stream->HasFinalReceivedByteOffset() &&
426 stream->flow_controller()->IsEnabled()) {
427 locally_closed_streams_highest_offset_[stream_id] =
428 stream->flow_controller()->highest_received_byte_offset();
429 }
430
431 stream_map_.erase(it);
432 stream->OnClose();
James Robinson74f9f1f2014-11-04 11:17:49 -0800433 // Decrease the number of streams being emulated when a new one is opened.
434 connection_->SetNumOpenStreams(stream_map_.size());
James Robinson646469d2014-10-03 15:33:28 -0700435}
436
437void QuicSession::UpdateFlowControlOnFinalReceivedByteOffset(
438 QuicStreamId stream_id, QuicStreamOffset final_byte_offset) {
439 map<QuicStreamId, QuicStreamOffset>::iterator it =
440 locally_closed_streams_highest_offset_.find(stream_id);
441 if (it == locally_closed_streams_highest_offset_.end()) {
442 return;
443 }
444
445 DVLOG(1) << ENDPOINT << "Received final byte offset " << final_byte_offset
446 << " for stream " << stream_id;
447 uint64 offset_diff = final_byte_offset - it->second;
448 if (flow_controller_->UpdateHighestReceivedOffset(
449 flow_controller_->highest_received_byte_offset() + offset_diff)) {
450 // If the final offset violates flow control, close the connection now.
451 if (flow_controller_->FlowControlViolation()) {
452 connection_->SendConnectionClose(
453 QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA);
454 return;
455 }
456 }
457
458 flow_controller_->AddBytesConsumed(offset_diff);
459 locally_closed_streams_highest_offset_.erase(it);
460}
461
462bool QuicSession::IsEncryptionEstablished() {
463 return GetCryptoStream()->encryption_established();
464}
465
466bool QuicSession::IsCryptoHandshakeConfirmed() {
467 return GetCryptoStream()->handshake_confirmed();
468}
469
470void QuicSession::OnConfigNegotiated() {
471 connection_->SetFromConfig(config_);
472 QuicVersion version = connection()->version();
473
474 if (FLAGS_quic_allow_more_open_streams) {
475 uint32 max_streams = config_.MaxStreamsPerConnection();
476 if (is_server()) {
477 // A server should accept a small number of additional streams beyond the
478 // limit sent to the client. This helps avoid early connection termination
479 // when FIN/RSTs for old streams are lost or arrive out of order.
480 // Use a minimum number of additional streams, or a percentage increase,
481 // whichever is larger.
482 max_streams =
483 max(max_streams + kMaxStreamsMinimumIncrement,
484 static_cast<uint32>(max_streams * kMaxStreamsMultiplier));
485 }
486 set_max_open_streams(max_streams);
487 }
488
James Robinsone1b30cf2014-10-21 12:25:40 -0700489 if (version == QUIC_VERSION_19) {
490 // QUIC_VERSION_19 doesn't support independent stream/session flow
James Robinson646469d2014-10-03 15:33:28 -0700491 // control windows.
492 if (config_.HasReceivedInitialFlowControlWindowBytes()) {
493 // Streams which were created before the SHLO was received (0-RTT
494 // requests) are now informed of the peer's initial flow control window.
495 uint32 new_window = config_.ReceivedInitialFlowControlWindowBytes();
496 OnNewStreamFlowControlWindow(new_window);
497 OnNewSessionFlowControlWindow(new_window);
498 }
499
500 return;
501 }
502
503 // QUIC_VERSION_21 and higher can have independent stream and session flow
504 // control windows.
505 if (config_.HasReceivedInitialStreamFlowControlWindowBytes()) {
506 // Streams which were created before the SHLO was received (0-RTT
507 // requests) are now informed of the peer's initial flow control window.
508 OnNewStreamFlowControlWindow(
509 config_.ReceivedInitialStreamFlowControlWindowBytes());
510 }
511 if (config_.HasReceivedInitialSessionFlowControlWindowBytes()) {
512 OnNewSessionFlowControlWindow(
513 config_.ReceivedInitialSessionFlowControlWindowBytes());
514 }
515}
516
517void QuicSession::OnNewStreamFlowControlWindow(uint32 new_window) {
518 if (new_window < kDefaultFlowControlSendWindow) {
519 LOG(ERROR)
520 << "Peer sent us an invalid stream flow control send window: "
521 << new_window << ", below default: " << kDefaultFlowControlSendWindow;
522 if (connection_->connected()) {
523 connection_->SendConnectionClose(QUIC_FLOW_CONTROL_INVALID_WINDOW);
524 }
525 return;
526 }
527
528 // Inform all existing streams about the new window.
529 if (connection_->version() >= QUIC_VERSION_21) {
James Robinsone2ac7e82014-10-15 13:21:59 -0700530 GetCryptoStream()->UpdateSendWindowOffset(new_window);
531 headers_stream_->UpdateSendWindowOffset(new_window);
James Robinson646469d2014-10-03 15:33:28 -0700532 }
533 for (DataStreamMap::iterator it = stream_map_.begin();
534 it != stream_map_.end(); ++it) {
James Robinsone2ac7e82014-10-15 13:21:59 -0700535 it->second->UpdateSendWindowOffset(new_window);
James Robinson646469d2014-10-03 15:33:28 -0700536 }
537}
538
539void QuicSession::OnNewSessionFlowControlWindow(uint32 new_window) {
540 if (new_window < kDefaultFlowControlSendWindow) {
541 LOG(ERROR)
542 << "Peer sent us an invalid session flow control send window: "
543 << new_window << ", below default: " << kDefaultFlowControlSendWindow;
544 if (connection_->connected()) {
545 connection_->SendConnectionClose(QUIC_FLOW_CONTROL_INVALID_WINDOW);
546 }
547 return;
548 }
549
550 flow_controller_->UpdateSendWindowOffset(new_window);
551}
552
553void QuicSession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) {
554 switch (event) {
555 // TODO(satyamshekhar): Move the logic of setting the encrypter/decrypter
556 // to QuicSession since it is the glue.
557 case ENCRYPTION_FIRST_ESTABLISHED:
558 break;
559
560 case ENCRYPTION_REESTABLISHED:
561 // Retransmit originally packets that were sent, since they can't be
562 // decrypted by the peer.
563 connection_->RetransmitUnackedPackets(ALL_INITIAL_RETRANSMISSION);
564 break;
565
566 case HANDSHAKE_CONFIRMED:
567 LOG_IF(DFATAL, !config_.negotiated()) << ENDPOINT
568 << "Handshake confirmed without parameter negotiation.";
569 // Discard originally encrypted packets, since they can't be decrypted by
570 // the peer.
571 connection_->NeuterUnencryptedPackets();
572 if (!FLAGS_quic_unified_timeouts) {
573 connection_->SetOverallConnectionTimeout(QuicTime::Delta::Infinite());
574 }
575 if (!FLAGS_quic_allow_more_open_streams) {
576 max_open_streams_ = config_.MaxStreamsPerConnection();
577 }
578 break;
579
580 default:
581 LOG(ERROR) << ENDPOINT << "Got unknown handshake event: " << event;
582 }
583}
584
585void QuicSession::OnCryptoHandshakeMessageSent(
586 const CryptoHandshakeMessage& message) {
587}
588
589void QuicSession::OnCryptoHandshakeMessageReceived(
590 const CryptoHandshakeMessage& message) {
591}
592
593QuicConfig* QuicSession::config() {
594 return &config_;
595}
596
597void QuicSession::ActivateStream(QuicDataStream* stream) {
598 DVLOG(1) << ENDPOINT << "num_streams: " << stream_map_.size()
599 << ". activating " << stream->id();
600 DCHECK_EQ(stream_map_.count(stream->id()), 0u);
601 stream_map_[stream->id()] = stream;
James Robinson74f9f1f2014-11-04 11:17:49 -0800602 // Increase the number of streams being emulated when a new one is opened.
603 connection_->SetNumOpenStreams(stream_map_.size());
James Robinson646469d2014-10-03 15:33:28 -0700604}
605
606QuicStreamId QuicSession::GetNextStreamId() {
607 QuicStreamId id = next_stream_id_;
608 next_stream_id_ += 2;
609 return id;
610}
611
612ReliableQuicStream* QuicSession::GetStream(const QuicStreamId stream_id) {
613 if (stream_id == kCryptoStreamId) {
614 return GetCryptoStream();
615 }
616 if (stream_id == kHeadersStreamId) {
617 return headers_stream_.get();
618 }
619 return GetDataStream(stream_id);
620}
621
622QuicDataStream* QuicSession::GetDataStream(const QuicStreamId stream_id) {
623 if (stream_id == kCryptoStreamId) {
624 DLOG(FATAL) << "Attempt to call GetDataStream with the crypto stream id";
625 return nullptr;
626 }
627 if (stream_id == kHeadersStreamId) {
628 DLOG(FATAL) << "Attempt to call GetDataStream with the headers stream id";
629 return nullptr;
630 }
631
632 DataStreamMap::iterator it = stream_map_.find(stream_id);
633 if (it != stream_map_.end()) {
634 return it->second;
635 }
636
637 if (IsClosedStream(stream_id)) {
638 return nullptr;
639 }
640
641 if (stream_id % 2 == next_stream_id_ % 2) {
642 // We've received a frame for a locally-created stream that is not
643 // currently active. This is an error.
644 if (connection()->connected()) {
645 connection()->SendConnectionClose(QUIC_PACKET_FOR_NONEXISTENT_STREAM);
646 }
647 return nullptr;
648 }
649
650 return GetIncomingDataStream(stream_id);
651}
652
653QuicDataStream* QuicSession::GetIncomingDataStream(QuicStreamId stream_id) {
654 if (IsClosedStream(stream_id)) {
655 return nullptr;
656 }
657
658 implicitly_created_streams_.erase(stream_id);
659 if (stream_id > largest_peer_created_stream_id_) {
660 if (stream_id - largest_peer_created_stream_id_ > kMaxStreamIdDelta) {
661 // We may already have sent a connection close due to multiple reset
662 // streams in the same packet.
663 if (connection()->connected()) {
664 LOG(ERROR) << "Trying to get stream: " << stream_id
665 << ", largest peer created stream: "
666 << largest_peer_created_stream_id_
667 << ", max delta: " << kMaxStreamIdDelta;
668 connection()->SendConnectionClose(QUIC_INVALID_STREAM_ID);
669 }
670 return nullptr;
671 }
672 if (largest_peer_created_stream_id_ == 0) {
673 if (is_server()) {
674 largest_peer_created_stream_id_= 3;
675 } else {
676 largest_peer_created_stream_id_= 1;
677 }
678 }
679 for (QuicStreamId id = largest_peer_created_stream_id_ + 2;
680 id < stream_id;
681 id += 2) {
682 implicitly_created_streams_.insert(id);
683 }
684 largest_peer_created_stream_id_ = stream_id;
685 }
686 QuicDataStream* stream = CreateIncomingDataStream(stream_id);
687 if (stream == nullptr) {
688 return nullptr;
689 }
690 ActivateStream(stream);
691 return stream;
692}
693
694void QuicSession::set_max_open_streams(size_t max_open_streams) {
695 DVLOG(1) << "Setting max_open_streams_ to " << max_open_streams;
696 max_open_streams_ = max_open_streams;
697}
698
699bool QuicSession::IsClosedStream(QuicStreamId id) {
700 DCHECK_NE(0u, id);
701 if (id == kCryptoStreamId) {
702 return false;
703 }
704 if (id == kHeadersStreamId) {
705 return false;
706 }
707 if (ContainsKey(stream_map_, id)) {
708 // Stream is active
709 return false;
710 }
711 if (id % 2 == next_stream_id_ % 2) {
712 // Locally created streams are strictly in-order. If the id is in the
713 // range of created streams and it's not active, it must have been closed.
714 return id < next_stream_id_;
715 }
716 // For peer created streams, we also need to consider implicitly created
717 // streams.
718 return id <= largest_peer_created_stream_id_ &&
James Robinsone1b30cf2014-10-21 12:25:40 -0700719 !ContainsKey(implicitly_created_streams_, id);
James Robinson646469d2014-10-03 15:33:28 -0700720}
721
722size_t QuicSession::GetNumOpenStreams() const {
723 return stream_map_.size() + implicitly_created_streams_.size();
724}
725
726void QuicSession::MarkWriteBlocked(QuicStreamId id, QuicPriority priority) {
727#ifndef NDEBUG
728 ReliableQuicStream* stream = GetStream(id);
729 if (stream != nullptr) {
730 LOG_IF(DFATAL, priority != stream->EffectivePriority())
731 << ENDPOINT << "Stream " << id
732 << "Priorities do not match. Got: " << priority
733 << " Expected: " << stream->EffectivePriority();
734 } else {
735 LOG(DFATAL) << "Marking unknown stream " << id << " blocked.";
736 }
737#endif
738
739 if (id == kCryptoStreamId) {
740 DCHECK(!has_pending_handshake_);
741 has_pending_handshake_ = true;
742 // TODO(jar): Be sure to use the highest priority for the crypto stream,
743 // perhaps by adding a "special" priority for it that is higher than
744 // kHighestPriority.
745 priority = kHighestPriority;
746 }
747 write_blocked_streams_.PushBack(id, priority);
748}
749
750bool QuicSession::HasDataToWrite() const {
751 return write_blocked_streams_.HasWriteBlockedCryptoOrHeadersStream() ||
752 write_blocked_streams_.HasWriteBlockedDataStreams() ||
753 connection_->HasQueuedData();
754}
755
756bool QuicSession::GetSSLInfo(SSLInfo* ssl_info) const {
757 NOTIMPLEMENTED();
758 return false;
759}
760
761void QuicSession::PostProcessAfterData() {
762 STLDeleteElements(&closed_streams_);
763 closed_streams_.clear();
764
James Robinson7f480212014-10-31 10:28:08 -0700765 if (connection()->connected() &&
James Robinson646469d2014-10-03 15:33:28 -0700766 locally_closed_streams_highest_offset_.size() > max_open_streams_) {
767 // A buggy client may fail to send FIN/RSTs. Don't tolerate this.
768 connection_->SendConnectionClose(QUIC_TOO_MANY_UNFINISHED_STREAMS);
769 }
770}
771
772void QuicSession::OnSuccessfulVersionNegotiation(const QuicVersion& version) {
James Robinson646469d2014-10-03 15:33:28 -0700773 // Disable stream level flow control based on negotiated version. Streams may
774 // have been created with a different version.
775 if (version < QUIC_VERSION_21) {
776 GetCryptoStream()->flow_controller()->Disable();
777 headers_stream_->flow_controller()->Disable();
778 }
779}
780
James Robinsone2ac7e82014-10-15 13:21:59 -0700781bool QuicSession::IsConnectionFlowControlBlocked() const {
782 return flow_controller_->IsBlocked();
783}
784
785bool QuicSession::IsStreamFlowControlBlocked() {
786 if (headers_stream_->flow_controller()->IsBlocked() ||
787 GetCryptoStream()->flow_controller()->IsBlocked()) {
788 return true;
789 }
790 for (DataStreamMap::iterator it = stream_map_.begin();
791 it != stream_map_.end(); ++it) {
792 if (it->second->flow_controller()->IsBlocked()) {
793 return true;
794 }
795 }
796 return false;
797}
798
James Robinson646469d2014-10-03 15:33:28 -0700799} // namespace net