OLD | NEW |
| (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 | |
OLD | NEW |