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

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

Issue 2193073003: Move shared files in net/quic/ into net/quic/core/ (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: io_thread_unittest.cc Created 4 years, 4 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
« 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
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "net/quic/quic_session.h"
6
7 #include "base/stl_util.h"
8 #include "base/strings/string_number_conversions.h"
9 #include "base/strings/stringprintf.h"
10 #include "net/quic/crypto/proof_verifier.h"
11 #include "net/quic/quic_bug_tracker.h"
12 #include "net/quic/quic_connection.h"
13 #include "net/quic/quic_flags.h"
14 #include "net/quic/quic_flow_controller.h"
15 #include "net/ssl/ssl_info.h"
16
17 using base::IntToString;
18 using base::StringPiece;
19 using std::make_pair;
20 using std::map;
21 using std::max;
22 using std::string;
23 using std::vector;
24 using net::SpdyPriority;
25
26 namespace net {
27
28 #define ENDPOINT \
29 (perspective() == Perspective::IS_SERVER ? "Server: " : " Client: ")
30
31 QuicSession::QuicSession(QuicConnection* connection, const QuicConfig& config)
32 : connection_(connection),
33 config_(config),
34 max_open_outgoing_streams_(kDefaultMaxStreamsPerConnection),
35 max_open_incoming_streams_(config_.GetMaxIncomingDynamicStreamsToSend()),
36 next_outgoing_stream_id_(perspective() == Perspective::IS_SERVER ? 2 : 3),
37 largest_peer_created_stream_id_(
38 perspective() == Perspective::IS_SERVER ? 1 : 0),
39 num_dynamic_incoming_streams_(0),
40 num_draining_incoming_streams_(0),
41 num_locally_closed_incoming_streams_highest_offset_(0),
42 error_(QUIC_NO_ERROR),
43 flow_controller_(connection_.get(),
44 0,
45 perspective(),
46 kMinimumFlowControlSendWindow,
47 config_.GetInitialSessionFlowControlWindowToSend(),
48 perspective() == Perspective::IS_SERVER),
49 currently_writing_stream_id_(0) {}
50
51 void QuicSession::Initialize() {
52 connection_->set_visitor(this);
53 connection_->SetFromConfig(config_);
54
55 DCHECK_EQ(kCryptoStreamId, GetCryptoStream()->id());
56 static_stream_map_[kCryptoStreamId] = GetCryptoStream();
57 }
58
59 QuicSession::~QuicSession() {
60 STLDeleteElements(&closed_streams_);
61 STLDeleteValues(&dynamic_stream_map_);
62
63 DLOG_IF(WARNING, num_locally_closed_incoming_streams_highest_offset() >
64 max_open_incoming_streams_)
65 << "Surprisingly high number of locally closed peer initiated streams"
66 "still waiting for final byte offset: "
67 << num_locally_closed_incoming_streams_highest_offset();
68 DLOG_IF(WARNING, GetNumLocallyClosedOutgoingStreamsHighestOffset() >
69 max_open_outgoing_streams_)
70 << "Surprisingly high number of locally closed self initiated streams"
71 "still waiting for final byte offset: "
72 << GetNumLocallyClosedOutgoingStreamsHighestOffset();
73 }
74
75 void QuicSession::OnStreamFrame(const QuicStreamFrame& frame) {
76 // TODO(rch) deal with the error case of stream id 0.
77 QuicStreamId stream_id = frame.stream_id;
78 ReliableQuicStream* stream = GetOrCreateStream(stream_id);
79 if (!stream) {
80 // The stream no longer exists, but we may still be interested in the
81 // final stream byte offset sent by the peer. A frame with a FIN can give
82 // us this offset.
83 if (frame.fin) {
84 QuicStreamOffset final_byte_offset = frame.offset + frame.data_length;
85 UpdateFlowControlOnFinalReceivedByteOffset(stream_id, final_byte_offset);
86 }
87 return;
88 }
89 stream->OnStreamFrame(frame);
90 }
91
92 void QuicSession::OnRstStream(const QuicRstStreamFrame& frame) {
93 if (ContainsKey(static_stream_map_, frame.stream_id)) {
94 connection()->CloseConnection(
95 QUIC_INVALID_STREAM_ID, "Attempt to reset a static stream",
96 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
97 return;
98 }
99
100 ReliableQuicStream* stream = GetOrCreateDynamicStream(frame.stream_id);
101 if (!stream) {
102 HandleRstOnValidNonexistentStream(frame);
103 return; // Errors are handled by GetOrCreateStream.
104 }
105
106 stream->OnStreamReset(frame);
107 }
108
109 void QuicSession::OnGoAway(const QuicGoAwayFrame& frame) {
110 DCHECK(frame.last_good_stream_id < next_outgoing_stream_id_);
111 }
112
113 void QuicSession::OnConnectionClosed(QuicErrorCode error,
114 const string& /*error_details*/,
115 ConnectionCloseSource source) {
116 DCHECK(!connection_->connected());
117 if (error_ == QUIC_NO_ERROR) {
118 error_ = error;
119 }
120
121 while (!dynamic_stream_map_.empty()) {
122 DynamicStreamMap::iterator it = dynamic_stream_map_.begin();
123 QuicStreamId id = it->first;
124 it->second->OnConnectionClosed(error, source);
125 // The stream should call CloseStream as part of OnConnectionClosed.
126 if (dynamic_stream_map_.find(id) != dynamic_stream_map_.end()) {
127 QUIC_BUG << ENDPOINT << "Stream failed to close under OnConnectionClosed";
128 CloseStream(id);
129 }
130 }
131 }
132
133 void QuicSession::OnSuccessfulVersionNegotiation(
134 const QuicVersion& /*version*/) {}
135
136 void QuicSession::OnPathDegrading() {}
137
138 void QuicSession::OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) {
139 // Stream may be closed by the time we receive a WINDOW_UPDATE, so we can't
140 // assume that it still exists.
141 QuicStreamId stream_id = frame.stream_id;
142 if (stream_id == kConnectionLevelId) {
143 // This is a window update that applies to the connection, rather than an
144 // individual stream.
145 DVLOG(1) << ENDPOINT << "Received connection level flow control window "
146 "update with byte offset: "
147 << frame.byte_offset;
148 flow_controller_.UpdateSendWindowOffset(frame.byte_offset);
149 return;
150 }
151 ReliableQuicStream* stream = GetOrCreateStream(stream_id);
152 if (stream) {
153 stream->OnWindowUpdateFrame(frame);
154 }
155 }
156
157 void QuicSession::OnBlockedFrame(const QuicBlockedFrame& frame) {
158 // TODO(rjshade): Compare our flow control receive windows for specified
159 // streams: if we have a large window then maybe something
160 // had gone wrong with the flow control accounting.
161 DVLOG(1) << ENDPOINT
162 << "Received BLOCKED frame with stream id: " << frame.stream_id;
163 }
164
165 void QuicSession::OnCanWrite() {
166 // We limit the number of writes to the number of pending streams. If more
167 // streams become pending, WillingAndAbleToWrite will be true, which will
168 // cause the connection to request resumption before yielding to other
169 // connections.
170 size_t num_writes = write_blocked_streams_.NumBlockedStreams();
171 if (flow_controller_.IsBlocked()) {
172 // If we are connection level flow control blocked, then only allow the
173 // crypto and headers streams to try writing as all other streams will be
174 // blocked.
175 num_writes = 0;
176 if (write_blocked_streams_.crypto_stream_blocked()) {
177 num_writes += 1;
178 }
179 if (write_blocked_streams_.headers_stream_blocked()) {
180 num_writes += 1;
181 }
182 }
183 if (num_writes == 0) {
184 return;
185 }
186
187 QuicConnection::ScopedPacketBundler ack_bundler(
188 connection_.get(), QuicConnection::SEND_ACK_IF_QUEUED);
189 for (size_t i = 0; i < num_writes; ++i) {
190 if (!(write_blocked_streams_.HasWriteBlockedCryptoOrHeadersStream() ||
191 write_blocked_streams_.HasWriteBlockedDataStreams())) {
192 // Writing one stream removed another!? Something's broken.
193 QUIC_BUG << "WriteBlockedStream is missing";
194 connection_->CloseConnection(QUIC_INTERNAL_ERROR,
195 "WriteBlockedStream is missing",
196 ConnectionCloseBehavior::SILENT_CLOSE);
197 return;
198 }
199 if (!connection_->CanWriteStreamData()) {
200 return;
201 }
202 currently_writing_stream_id_ = write_blocked_streams_.PopFront();
203 ReliableQuicStream* stream =
204 GetOrCreateStream(currently_writing_stream_id_);
205 if (stream != nullptr && !stream->flow_controller()->IsBlocked()) {
206 // If the stream can't write all bytes it'll re-add itself to the blocked
207 // list.
208 stream->OnCanWrite();
209 }
210 currently_writing_stream_id_ = 0;
211 }
212 }
213
214 bool QuicSession::WillingAndAbleToWrite() const {
215 // If the crypto or headers streams are blocked, we want to schedule a write -
216 // they don't get blocked by connection level flow control. Otherwise only
217 // schedule a write if we are not flow control blocked at the connection
218 // level.
219 return write_blocked_streams_.HasWriteBlockedCryptoOrHeadersStream() ||
220 (!flow_controller_.IsBlocked() &&
221 write_blocked_streams_.HasWriteBlockedDataStreams());
222 }
223
224 bool QuicSession::HasPendingHandshake() const {
225 return write_blocked_streams_.crypto_stream_blocked();
226 }
227
228 bool QuicSession::HasOpenDynamicStreams() const {
229 return (dynamic_stream_map_.size() - draining_streams_.size() +
230 locally_closed_streams_highest_offset_.size()) > 0;
231 }
232
233 void QuicSession::ProcessUdpPacket(const IPEndPoint& self_address,
234 const IPEndPoint& peer_address,
235 const QuicReceivedPacket& packet) {
236 connection_->ProcessUdpPacket(self_address, peer_address, packet);
237 }
238
239 QuicConsumedData QuicSession::WritevData(
240 ReliableQuicStream* stream,
241 QuicStreamId id,
242 QuicIOVector iov,
243 QuicStreamOffset offset,
244 bool fin,
245 QuicAckListenerInterface* ack_notifier_delegate) {
246 // This check is an attempt to deal with potential memory corruption
247 // in which |id| ends up set to 1 (the crypto stream id). If this happen
248 // it might end up resulting in unencrypted stream data being sent.
249 // While this is impossible to avoid given sufficient corruption, this
250 // seems like a reasonable mitigation.
251 if (id == kCryptoStreamId && stream != GetCryptoStream()) {
252 QUIC_BUG << "Stream id mismatch";
253 connection_->CloseConnection(
254 QUIC_INTERNAL_ERROR,
255 "Non-crypto stream attempted to write data as crypto stream.",
256 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
257 return QuicConsumedData(0, false);
258 }
259 if (!IsEncryptionEstablished() && id != kCryptoStreamId) {
260 // Do not let streams write without encryption. The calling stream will end
261 // up write blocked until OnCanWrite is next called.
262 return QuicConsumedData(0, false);
263 }
264 QuicConsumedData data =
265 connection_->SendStreamData(id, iov, offset, fin, ack_notifier_delegate);
266 write_blocked_streams_.UpdateBytesForStream(id, data.bytes_consumed);
267 return data;
268 }
269
270 void QuicSession::SendRstStream(QuicStreamId id,
271 QuicRstStreamErrorCode error,
272 QuicStreamOffset bytes_written) {
273 if (ContainsKey(static_stream_map_, id)) {
274 QUIC_BUG << "Cannot send RST for a static stream with ID " << id;
275 return;
276 }
277
278 if (connection()->connected()) {
279 // Only send a RST_STREAM frame if still connected.
280 connection_->SendRstStream(id, error, bytes_written);
281 }
282 CloseStreamInner(id, true);
283 }
284
285 void QuicSession::SendGoAway(QuicErrorCode error_code, const string& reason) {
286 if (goaway_sent()) {
287 return;
288 }
289
290 connection_->SendGoAway(error_code, largest_peer_created_stream_id_, reason);
291 }
292
293 void QuicSession::CloseStream(QuicStreamId stream_id) {
294 CloseStreamInner(stream_id, false);
295 }
296
297 void QuicSession::InsertLocallyClosedStreamsHighestOffset(
298 const QuicStreamId id,
299 QuicStreamOffset offset) {
300 locally_closed_streams_highest_offset_[id] = offset;
301 if (IsIncomingStream(id)) {
302 ++num_locally_closed_incoming_streams_highest_offset_;
303 }
304 }
305
306 void QuicSession::CloseStreamInner(QuicStreamId stream_id, bool locally_reset) {
307 DVLOG(1) << ENDPOINT << "Closing stream " << stream_id;
308
309 DynamicStreamMap::iterator it = dynamic_stream_map_.find(stream_id);
310 if (it == dynamic_stream_map_.end()) {
311 // When CloseStreamInner has been called recursively (via
312 // ReliableQuicStream::OnClose), the stream will already have been deleted
313 // from stream_map_, so return immediately.
314 DVLOG(1) << ENDPOINT << "Stream is already closed: " << stream_id;
315 return;
316 }
317 ReliableQuicStream* stream = it->second;
318
319 // Tell the stream that a RST has been sent.
320 if (locally_reset) {
321 stream->set_rst_sent(true);
322 }
323
324 closed_streams_.push_back(it->second);
325
326 // If we haven't received a FIN or RST for this stream, we need to keep track
327 // of the how many bytes the stream's flow controller believes it has
328 // received, for accurate connection level flow control accounting.
329 if (!stream->HasFinalReceivedByteOffset()) {
330 InsertLocallyClosedStreamsHighestOffset(
331 stream_id, stream->flow_controller()->highest_received_byte_offset());
332 }
333
334 dynamic_stream_map_.erase(it);
335 if (IsIncomingStream(stream_id)) {
336 --num_dynamic_incoming_streams_;
337 }
338
339 if (draining_streams_.find(stream_id) != draining_streams_.end() &&
340 IsIncomingStream(stream_id)) {
341 --num_draining_incoming_streams_;
342 }
343 draining_streams_.erase(stream_id);
344
345 stream->OnClose();
346 // Decrease the number of streams being emulated when a new one is opened.
347 connection_->SetNumOpenStreams(dynamic_stream_map_.size());
348 }
349
350 void QuicSession::UpdateFlowControlOnFinalReceivedByteOffset(
351 QuicStreamId stream_id,
352 QuicStreamOffset final_byte_offset) {
353 map<QuicStreamId, QuicStreamOffset>::iterator it =
354 locally_closed_streams_highest_offset_.find(stream_id);
355 if (it == locally_closed_streams_highest_offset_.end()) {
356 return;
357 }
358
359 DVLOG(1) << ENDPOINT << "Received final byte offset " << final_byte_offset
360 << " for stream " << stream_id;
361 QuicByteCount offset_diff = final_byte_offset - it->second;
362 if (flow_controller_.UpdateHighestReceivedOffset(
363 flow_controller_.highest_received_byte_offset() + offset_diff)) {
364 // If the final offset violates flow control, close the connection now.
365 if (flow_controller_.FlowControlViolation()) {
366 connection_->CloseConnection(
367 QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA,
368 "Connection level flow control violation",
369 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
370 return;
371 }
372 }
373
374 flow_controller_.AddBytesConsumed(offset_diff);
375 locally_closed_streams_highest_offset_.erase(it);
376 if (IsIncomingStream(stream_id)) {
377 --num_locally_closed_incoming_streams_highest_offset_;
378 }
379 }
380
381 bool QuicSession::IsEncryptionEstablished() {
382 return GetCryptoStream()->encryption_established();
383 }
384
385 bool QuicSession::IsCryptoHandshakeConfirmed() {
386 return GetCryptoStream()->handshake_confirmed();
387 }
388
389 void QuicSession::OnConfigNegotiated() {
390 connection_->SetFromConfig(config_);
391
392 const QuicVersion version = connection()->version();
393 uint32_t max_streams = 0;
394 if (version > QUIC_VERSION_34 &&
395 config_.HasReceivedMaxIncomingDynamicStreams()) {
396 max_streams = config_.ReceivedMaxIncomingDynamicStreams();
397 } else {
398 max_streams = config_.MaxStreamsPerConnection();
399 }
400 set_max_open_outgoing_streams(max_streams);
401
402 if (version <= QUIC_VERSION_34) {
403 // A small number of additional incoming streams beyond the limit should be
404 // allowed. This helps avoid early connection termination when FIN/RSTs for
405 // old streams are lost or arrive out of order.
406 // Use a minimum number of additional streams, or a percentage increase,
407 // whichever is larger.
408 uint32_t max_incoming_streams =
409 max(max_streams + kMaxStreamsMinimumIncrement,
410 static_cast<uint32_t>(max_streams * kMaxStreamsMultiplier));
411 set_max_open_incoming_streams(max_incoming_streams);
412 } else {
413 uint32_t max_incoming_streams_to_send =
414 config_.GetMaxIncomingDynamicStreamsToSend();
415 uint32_t max_incoming_streams =
416 max(max_incoming_streams_to_send + kMaxStreamsMinimumIncrement,
417 static_cast<uint32_t>(max_incoming_streams_to_send *
418 kMaxStreamsMultiplier));
419 set_max_open_incoming_streams(max_incoming_streams);
420 }
421
422 if (config_.HasReceivedInitialStreamFlowControlWindowBytes()) {
423 // Streams which were created before the SHLO was received (0-RTT
424 // requests) are now informed of the peer's initial flow control window.
425 OnNewStreamFlowControlWindow(
426 config_.ReceivedInitialStreamFlowControlWindowBytes());
427 }
428 if (config_.HasReceivedInitialSessionFlowControlWindowBytes()) {
429 OnNewSessionFlowControlWindow(
430 config_.ReceivedInitialSessionFlowControlWindowBytes());
431 }
432 }
433
434 void QuicSession::HandleFrameOnNonexistentOutgoingStream(
435 QuicStreamId stream_id) {
436 DCHECK(!IsClosedStream(stream_id));
437 // Received a frame for a locally-created stream that is not currently
438 // active. This is an error.
439 connection()->CloseConnection(
440 QUIC_INVALID_STREAM_ID, "Data for nonexistent stream",
441 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
442 }
443
444 void QuicSession::HandleRstOnValidNonexistentStream(
445 const QuicRstStreamFrame& frame) {
446 // If the stream is neither originally in active streams nor created in
447 // GetOrCreateDynamicStream(), it could be a closed stream in which case its
448 // final received byte offset need to be updated.
449 if (IsClosedStream(frame.stream_id)) {
450 // The RST frame contains the final byte offset for the stream: we can now
451 // update the connection level flow controller if needed.
452 UpdateFlowControlOnFinalReceivedByteOffset(frame.stream_id,
453 frame.byte_offset);
454 }
455 }
456
457 void QuicSession::OnNewStreamFlowControlWindow(QuicStreamOffset new_window) {
458 if (new_window < kMinimumFlowControlSendWindow) {
459 LOG(ERROR) << "Peer sent us an invalid stream flow control send window: "
460 << new_window
461 << ", below default: " << kMinimumFlowControlSendWindow;
462 if (connection_->connected()) {
463 connection_->CloseConnection(
464 QUIC_FLOW_CONTROL_INVALID_WINDOW, "New stream window too low",
465 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
466 }
467 return;
468 }
469
470 // Inform all existing streams about the new window.
471 for (auto const& kv : static_stream_map_) {
472 kv.second->UpdateSendWindowOffset(new_window);
473 }
474 for (auto const& kv : dynamic_stream_map_) {
475 kv.second->UpdateSendWindowOffset(new_window);
476 }
477 }
478
479 void QuicSession::OnNewSessionFlowControlWindow(QuicStreamOffset new_window) {
480 if (new_window < kMinimumFlowControlSendWindow) {
481 LOG(ERROR) << "Peer sent us an invalid session flow control send window: "
482 << new_window
483 << ", below default: " << kMinimumFlowControlSendWindow;
484 if (connection_->connected()) {
485 connection_->CloseConnection(
486 QUIC_FLOW_CONTROL_INVALID_WINDOW, "New connection window too low",
487 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
488 }
489 return;
490 }
491
492 flow_controller_.UpdateSendWindowOffset(new_window);
493 }
494
495 void QuicSession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) {
496 switch (event) {
497 // TODO(satyamshekhar): Move the logic of setting the encrypter/decrypter
498 // to QuicSession since it is the glue.
499 case ENCRYPTION_FIRST_ESTABLISHED:
500 // Given any streams blocked by encryption a chance to write.
501 OnCanWrite();
502 break;
503
504 case ENCRYPTION_REESTABLISHED:
505 // Retransmit originally packets that were sent, since they can't be
506 // decrypted by the peer.
507 connection_->RetransmitUnackedPackets(ALL_INITIAL_RETRANSMISSION);
508 // Given any streams blocked by encryption a chance to write.
509 OnCanWrite();
510 break;
511
512 case HANDSHAKE_CONFIRMED:
513 QUIC_BUG_IF(!config_.negotiated())
514 << ENDPOINT << "Handshake confirmed without parameter negotiation.";
515 // Discard originally encrypted packets, since they can't be decrypted by
516 // the peer.
517 connection_->NeuterUnencryptedPackets();
518 break;
519
520 default:
521 LOG(ERROR) << ENDPOINT << "Got unknown handshake event: " << event;
522 }
523 }
524
525 void QuicSession::OnCryptoHandshakeMessageSent(
526 const CryptoHandshakeMessage& /*message*/) {}
527
528 void QuicSession::OnCryptoHandshakeMessageReceived(
529 const CryptoHandshakeMessage& /*message*/) {}
530
531 QuicConfig* QuicSession::config() {
532 return &config_;
533 }
534
535 void QuicSession::ActivateStream(ReliableQuicStream* stream) {
536 DVLOG(1) << ENDPOINT << "num_streams: " << dynamic_stream_map_.size()
537 << ". activating " << stream->id();
538 DCHECK(!ContainsKey(dynamic_stream_map_, stream->id()));
539 DCHECK(!ContainsKey(static_stream_map_, stream->id()));
540 dynamic_stream_map_[stream->id()] = stream;
541 if (IsIncomingStream(stream->id())) {
542 ++num_dynamic_incoming_streams_;
543 }
544 // Increase the number of streams being emulated when a new one is opened.
545 connection_->SetNumOpenStreams(dynamic_stream_map_.size());
546 }
547
548 QuicStreamId QuicSession::GetNextOutgoingStreamId() {
549 QuicStreamId id = next_outgoing_stream_id_;
550 next_outgoing_stream_id_ += 2;
551 return id;
552 }
553
554 ReliableQuicStream* QuicSession::GetOrCreateStream(
555 const QuicStreamId stream_id) {
556 StaticStreamMap::iterator it = static_stream_map_.find(stream_id);
557 if (it != static_stream_map_.end()) {
558 return it->second;
559 }
560 return GetOrCreateDynamicStream(stream_id);
561 }
562
563 void QuicSession::StreamDraining(QuicStreamId stream_id) {
564 DCHECK(ContainsKey(dynamic_stream_map_, stream_id));
565 if (!ContainsKey(draining_streams_, stream_id)) {
566 draining_streams_.insert(stream_id);
567 if (IsIncomingStream(stream_id)) {
568 ++num_draining_incoming_streams_;
569 }
570 }
571 }
572
573 bool QuicSession::MaybeIncreaseLargestPeerStreamId(
574 const QuicStreamId stream_id) {
575 if (stream_id <= largest_peer_created_stream_id_) {
576 return true;
577 }
578
579 // Check if the new number of available streams would cause the number of
580 // available streams to exceed the limit. Note that the peer can create
581 // only alternately-numbered streams.
582 size_t additional_available_streams =
583 (stream_id - largest_peer_created_stream_id_) / 2 - 1;
584 size_t new_num_available_streams =
585 GetNumAvailableStreams() + additional_available_streams;
586 if (new_num_available_streams > MaxAvailableStreams()) {
587 DVLOG(1) << "Failed to create a new incoming stream with id:" << stream_id
588 << ". There are already " << GetNumAvailableStreams()
589 << " streams available, which would become "
590 << new_num_available_streams << ", which exceeds the limit "
591 << MaxAvailableStreams() << ".";
592 string details = IntToString(new_num_available_streams) + " above " +
593 IntToString(MaxAvailableStreams());
594 connection()->CloseConnection(
595 QUIC_TOO_MANY_AVAILABLE_STREAMS, details.c_str(),
596 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
597 return false;
598 }
599 for (QuicStreamId id = largest_peer_created_stream_id_ + 2; id < stream_id;
600 id += 2) {
601 available_streams_.insert(id);
602 }
603 largest_peer_created_stream_id_ = stream_id;
604
605 return true;
606 }
607
608 bool QuicSession::ShouldYield(QuicStreamId stream_id) {
609 if (stream_id == currently_writing_stream_id_) {
610 return false;
611 }
612 return write_blocked_streams()->ShouldYield(stream_id);
613 }
614
615 ReliableQuicStream* QuicSession::GetOrCreateDynamicStream(
616 const QuicStreamId stream_id) {
617 DCHECK(!ContainsKey(static_stream_map_, stream_id))
618 << "Attempt to call GetOrCreateDynamicStream for a static stream";
619
620 DynamicStreamMap::iterator it = dynamic_stream_map_.find(stream_id);
621 if (it != dynamic_stream_map_.end()) {
622 return it->second;
623 }
624
625 if (IsClosedStream(stream_id)) {
626 return nullptr;
627 }
628
629 if (!IsIncomingStream(stream_id)) {
630 HandleFrameOnNonexistentOutgoingStream(stream_id);
631 return nullptr;
632 }
633
634 available_streams_.erase(stream_id);
635
636 if (!MaybeIncreaseLargestPeerStreamId(stream_id)) {
637 return nullptr;
638 }
639 // Check if the new number of open streams would cause the number of
640 // open streams to exceed the limit.
641 if (GetNumOpenIncomingStreams() >= max_open_incoming_streams()) {
642 // Refuse to open the stream.
643 SendRstStream(stream_id, QUIC_REFUSED_STREAM, 0);
644 return nullptr;
645 }
646
647 return CreateIncomingDynamicStream(stream_id);
648 }
649
650 void QuicSession::set_max_open_incoming_streams(
651 size_t max_open_incoming_streams) {
652 DVLOG(1) << "Setting max_open_incoming_streams_ to "
653 << max_open_incoming_streams;
654 max_open_incoming_streams_ = max_open_incoming_streams;
655 DVLOG(1) << "MaxAvailableStreams() became " << MaxAvailableStreams();
656 }
657
658 void QuicSession::set_max_open_outgoing_streams(
659 size_t max_open_outgoing_streams) {
660 DVLOG(1) << "Setting max_open_outgoing_streams_ to "
661 << max_open_outgoing_streams;
662 max_open_outgoing_streams_ = max_open_outgoing_streams;
663 }
664
665 bool QuicSession::goaway_sent() const {
666 return connection_->goaway_sent();
667 }
668
669 bool QuicSession::goaway_received() const {
670 return connection_->goaway_received();
671 }
672
673 bool QuicSession::IsClosedStream(QuicStreamId id) {
674 DCHECK_NE(0u, id);
675 if (IsOpenStream(id)) {
676 // Stream is active
677 return false;
678 }
679 if (!IsIncomingStream(id)) {
680 // Locally created streams are strictly in-order. If the id is in the
681 // range of created streams and it's not active, it must have been closed.
682 return id < next_outgoing_stream_id_;
683 }
684 // For peer created streams, we also need to consider available streams.
685 return id <= largest_peer_created_stream_id_ &&
686 !ContainsKey(available_streams_, id);
687 }
688
689 bool QuicSession::IsOpenStream(QuicStreamId id) {
690 DCHECK_NE(0u, id);
691 if (ContainsKey(static_stream_map_, id) ||
692 ContainsKey(dynamic_stream_map_, id)) {
693 // Stream is active
694 return true;
695 }
696 return false;
697 }
698
699 size_t QuicSession::GetNumOpenIncomingStreams() const {
700 return num_dynamic_incoming_streams_ - num_draining_incoming_streams_ +
701 num_locally_closed_incoming_streams_highest_offset_;
702 }
703
704 size_t QuicSession::GetNumOpenOutgoingStreams() const {
705 return GetNumDynamicOutgoingStreams() - GetNumDrainingOutgoingStreams() +
706 GetNumLocallyClosedOutgoingStreamsHighestOffset();
707 }
708
709 size_t QuicSession::GetNumActiveStreams() const {
710 return dynamic_stream_map_.size() - draining_streams_.size();
711 }
712
713 size_t QuicSession::GetNumAvailableStreams() const {
714 return available_streams_.size();
715 }
716
717 void QuicSession::MarkConnectionLevelWriteBlocked(QuicStreamId id) {
718 QUIC_BUG_IF(GetOrCreateStream(id) == nullptr) << "Marking unknown stream "
719 << id << " blocked.";
720
721 write_blocked_streams_.AddStream(id);
722 }
723
724 bool QuicSession::HasDataToWrite() const {
725 return write_blocked_streams_.HasWriteBlockedCryptoOrHeadersStream() ||
726 write_blocked_streams_.HasWriteBlockedDataStreams() ||
727 connection_->HasQueuedData();
728 }
729
730 void QuicSession::PostProcessAfterData() {
731 STLDeleteElements(&closed_streams_);
732 closed_streams_.clear();
733 }
734
735 size_t QuicSession::GetNumDynamicOutgoingStreams() const {
736 return dynamic_stream_map_.size() - num_dynamic_incoming_streams_;
737 }
738
739 size_t QuicSession::GetNumDrainingOutgoingStreams() const {
740 return draining_streams_.size() - num_draining_incoming_streams_;
741 }
742
743 size_t QuicSession::GetNumLocallyClosedOutgoingStreamsHighestOffset() const {
744 return locally_closed_streams_highest_offset_.size() -
745 num_locally_closed_incoming_streams_highest_offset_;
746 }
747
748 bool QuicSession::IsConnectionFlowControlBlocked() const {
749 return flow_controller_.IsBlocked();
750 }
751
752 bool QuicSession::IsStreamFlowControlBlocked() {
753 for (auto const& kv : static_stream_map_) {
754 if (kv.second->flow_controller()->IsBlocked()) {
755 return true;
756 }
757 }
758 for (auto const& kv : dynamic_stream_map_) {
759 if (kv.second->flow_controller()->IsBlocked()) {
760 return true;
761 }
762 }
763 return false;
764 }
765
766 size_t QuicSession::MaxAvailableStreams() const {
767 return max_open_incoming_streams_ * kMaxAvailableStreamsMultiplier;
768 }
769
770 bool QuicSession::IsIncomingStream(QuicStreamId id) const {
771 return id % 2 != next_outgoing_stream_id_ % 2;
772 }
773
774 } // 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