quic_session.cc revision 5c02ac1a9c1b504631c0a3d2b6e737b5d738bae1
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/quic/quic_session.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/stl_util.h" 8eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "net/quic/crypto/proof_verifier.h" 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/quic/quic_connection.h" 105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "net/quic/quic_headers_stream.h" 117dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "net/ssl/ssl_info.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::StringPiece; 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::hash_map; 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::hash_set; 162385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdochusing std::make_pair; 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using std::vector; 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace net { 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#define ENDPOINT (is_server() ? "Server: " : " Client: ") 22868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// We want to make sure we delete any closed streams in a safe manner. 242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// To avoid deleting a stream in mid-operation, we have a simple shim between 252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// us and the stream, so we can delete any streams when we return from 262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// processing. 272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// 282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// We could just override the base methods, but this makes it easier to make 292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// sure we don't miss any. 302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class VisitorShim : public QuicConnectionVisitorInterface { 312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public: 322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) explicit VisitorShim(QuicSession* session) : session_(session) {} 332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 345c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu virtual void OnStreamFrames(const vector<QuicStreamFrame>& frames) OVERRIDE { 355c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu session_->OnStreamFrames(frames); 362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) session_->PostProcessAfterData(); 372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual void OnRstStream(const QuicRstStreamFrame& frame) OVERRIDE { 392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) session_->OnRstStream(frame); 402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) session_->PostProcessAfterData(); 412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual void OnGoAway(const QuicGoAwayFrame& frame) OVERRIDE { 442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) session_->OnGoAway(frame); 452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) session_->PostProcessAfterData(); 462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 48a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) virtual void OnWindowUpdateFrames(const vector<QuicWindowUpdateFrame>& frames) 49a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) OVERRIDE { 50a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) session_->OnWindowUpdateFrames(frames); 51a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) session_->PostProcessAfterData(); 52a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 53a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 54a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) virtual void OnBlockedFrames(const vector<QuicBlockedFrame>& frames) 55a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) OVERRIDE { 56a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) session_->OnBlockedFrames(frames); 57a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) session_->PostProcessAfterData(); 58a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 59a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 60a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) virtual void OnCanWrite() OVERRIDE { 61a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) session_->OnCanWrite(); 622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) session_->PostProcessAfterData(); 632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 65d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) virtual void OnSuccessfulVersionNegotiation( 66d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) const QuicVersion& version) OVERRIDE { 67d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) session_->OnSuccessfulVersionNegotiation(version); 68d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) } 69d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) virtual void OnConnectionClosed( 715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) QuicErrorCode error, bool from_peer) OVERRIDE { 721e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) session_->OnConnectionClosed(error, from_peer); 732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // The session will go away, so don't bother with cleanup. 742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) virtual void OnWriteBlocked() OVERRIDE { 775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) session_->OnWriteBlocked(); 785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 80a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) virtual bool HasPendingWrites() const OVERRIDE { 81a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return session_->HasPendingWrites(); 82a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 83a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 84d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) virtual bool HasPendingHandshake() const OVERRIDE { 85d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) return session_->HasPendingHandshake(); 86d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) } 87d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 880529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch virtual bool HasOpenDataStreams() const OVERRIDE { 890529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch return session_->HasOpenDataStreams(); 900529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch } 910529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch 922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private: 932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) QuicSession* session_; 942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}; 952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 9690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)QuicSession::QuicSession(QuicConnection* connection, 975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const QuicConfig& config) 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : connection_(connection), 992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) visitor_shim_(new VisitorShim(this)), 10090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) config_(config), 101ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch max_open_streams_(config_.max_streams_per_connection()), 1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) next_stream_id_(is_server() ? 2 : 3), 1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) largest_peer_created_stream_id_(0), 104868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) error_(QUIC_NO_ERROR), 1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) goaway_received_(false), 106d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) goaway_sent_(false), 107d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) has_pending_handshake_(false) { 108868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 109868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) connection_->set_visitor(visitor_shim_.get()); 1100f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) connection_->SetFromConfig(config_); 111ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch if (connection_->connected()) { 112ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch connection_->SetOverallConnectionTimeout( 113ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch config_.max_time_before_crypto_handshake()); 114ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch } 115a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) headers_stream_.reset(new QuicHeadersStream(this)); 116a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (!is_server()) { 117a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // For version above QUIC v12, the headers stream is stream 3, so the 118a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // next available local stream ID should be 5. 119a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DCHECK_EQ(kHeadersStreamId, next_stream_id_); 120a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) next_stream_id_ += 2; 1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)QuicSession::~QuicSession() { 1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) STLDeleteElements(&closed_streams_); 1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) STLDeleteValues(&stream_map_); 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1295c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid QuicSession::OnStreamFrames(const vector<QuicStreamFrame>& frames) { 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < frames.size(); ++i) { 1315c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // TODO(rch) deal with the error case of stream id 0. 132424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) QuicStreamId stream_id = frames[i].stream_id; 133424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) ReliableQuicStream* stream = GetStream(stream_id); 134424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) if (!stream) { 135424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) continue; 136424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) } 137424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) stream->OnStreamFrame(frames[i]); 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void QuicSession::OnStreamHeaders(QuicStreamId stream_id, 1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) StringPiece headers_data) { 1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) QuicDataStream* stream = GetDataStream(stream_id); 1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!stream) { 1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // It's quite possible to receive headers after a stream has been reset. 1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return; 1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) stream->OnStreamHeaders(headers_data); 1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void QuicSession::OnStreamHeadersPriority(QuicStreamId stream_id, 1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) QuicPriority priority) { 1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) QuicDataStream* stream = GetDataStream(stream_id); 1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!stream) { 1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // It's quite possible to receive headers after a stream has been reset. 1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return; 1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) stream->OnStreamHeadersPriority(priority); 1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void QuicSession::OnStreamHeadersComplete(QuicStreamId stream_id, 1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) bool fin, 1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) size_t frame_len) { 1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) QuicDataStream* stream = GetDataStream(stream_id); 1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!stream) { 1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // It's quite possible to receive headers after a stream has been reset. 1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return; 1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) stream->OnStreamHeadersComplete(fin, frame_len); 1705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void QuicSession::OnRstStream(const QuicRstStreamFrame& frame) { 1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (frame.stream_id == kCryptoStreamId) { 1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) connection()->SendConnectionCloseWithDetails( 1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) QUIC_INVALID_STREAM_ID, 1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "Attempt to reset the crypto stream"); 1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return; 1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 179a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (frame.stream_id == kHeadersStreamId) { 1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) connection()->SendConnectionCloseWithDetails( 1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) QUIC_INVALID_STREAM_ID, 1825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "Attempt to reset the headers stream"); 1835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return; 1845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) QuicDataStream* stream = GetDataStream(frame.stream_id); 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!stream) { 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; // Errors are handled by GetStream. 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 189a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) stream->OnStreamReset(frame); 1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void QuicSession::OnGoAway(const QuicGoAwayFrame& frame) { 1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(frame.last_good_stream_id < next_stream_id_); 1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) goaway_received_ = true; 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1981e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void QuicSession::OnConnectionClosed(QuicErrorCode error, bool from_peer) { 199424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) DCHECK(!connection_->connected()); 200868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (error_ == QUIC_NO_ERROR) { 201868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) error_ = error; 202868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 203868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 204a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) while (!stream_map_.empty()) { 2055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DataStreamMap::iterator it = stream_map_.begin(); 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) QuicStreamId id = it->first; 2071e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) it->second->OnConnectionClosed(error, from_peer); 2081e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // The stream should call CloseStream as part of OnConnectionClosed. 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (stream_map_.find(id) != stream_map_.end()) { 2101e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) LOG(DFATAL) << ENDPOINT 2111e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) << "Stream failed to close under OnConnectionClosed"; 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CloseStream(id); 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 217a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void QuicSession::OnWindowUpdateFrames( 218a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) const vector<QuicWindowUpdateFrame>& frames) { 219a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) for (size_t i = 0; i < frames.size(); ++i) { 220a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Stream may be closed by the time we receive a WINDOW_UPDATE, so we can't 221a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // assume that it still exists. 222a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) QuicStreamId stream_id = frames[i].stream_id; 223a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (stream_id == 0) { 224a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // This is a window update that applies to the connection, rather than an 225a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // individual stream. 226a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // TODO(rjshade): Adjust connection level flow control window. 227a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DVLOG(1) << ENDPOINT 228a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) << "Received connection level flow control window update with " 229a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) "byte offset: " << frames[i].byte_offset; 230a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) continue; 231a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 232a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 233a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) QuicDataStream* stream = GetDataStream(stream_id); 234a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (stream) { 235a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) stream->OnWindowUpdateFrame(frames[i]); 236a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 237a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 238a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 239a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 240a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void QuicSession::OnBlockedFrames(const vector<QuicBlockedFrame>& frames) { 241a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) for (size_t i = 0; i < frames.size(); ++i) { 242a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // TODO(rjshade): Compare our flow control receive windows for specified 243a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // streams: if we have a large window then maybe something 244a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // had gone wrong with the flow control accounting. 245a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DVLOG(1) << ENDPOINT << "Received BLOCKED frame with stream id: " 246a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) << frames[i].stream_id; 247a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 248a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 249a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 250a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void QuicSession::OnCanWrite() { 251a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // We limit the number of writes to the number of pending streams. If more 252a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // streams become pending, HasPendingWrites will be true, which will cause 253a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // the connection to request resumption before yielding to other connections. 254a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) size_t num_writes = write_blocked_streams_.NumBlockedStreams(); 2550529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch if (num_writes == 0) { 2560529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch return; 2570529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch } 2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2590529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch QuicConnection::ScopedPacketBundler ack_bundler( 2600529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch connection_.get(), QuicConnection::NO_ACK); 261a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) for (size_t i = 0; i < num_writes; ++i) { 262f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (!write_blocked_streams_.HasWriteBlockedStreams()) { 263a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Writing one stream removed another?! Something's broken. 264d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) LOG(DFATAL) << "WriteBlockedStream is missing"; 265d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) connection_->CloseConnection(QUIC_INTERNAL_ERROR, false); 266a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return; 267a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 268a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (!connection_->CanWriteStreamData()) { 269a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return; 2703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) } 2715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) QuicStreamId stream_id = write_blocked_streams_.PopFront(); 272d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) if (stream_id == kCryptoStreamId) { 273d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) has_pending_handshake_ = false; // We just popped it. 274d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) } 275d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) ReliableQuicStream* stream = GetStream(stream_id); 2760529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch if (stream != NULL && !stream->flow_controller()->IsBlocked()) { 2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // If the stream can't write all bytes, it'll re-add itself to the blocked 2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // list. 2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) stream->OnCanWrite(); 2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 282a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 284a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool QuicSession::HasPendingWrites() const { 285a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return write_blocked_streams_.HasWriteBlockedStreams(); 2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 288d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)bool QuicSession::HasPendingHandshake() const { 289d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) return has_pending_handshake_; 290d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)} 291d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 2920529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochbool QuicSession::HasOpenDataStreams() const { 2930529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch return GetNumOpenStreams() > 0; 2940529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch} 2950529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch 296f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)QuicConsumedData QuicSession::WritevData( 297f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) QuicStreamId id, 298a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) const IOVector& data, 299f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) QuicStreamOffset offset, 300f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) bool fin, 301f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) QuicAckNotifier::DelegateInterface* ack_notifier_delegate) { 302f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return connection_->SendStreamData(id, data, offset, fin, 303f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ack_notifier_delegate); 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 30623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)size_t QuicSession::WriteHeaders( 30723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) QuicStreamId id, 30823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) const SpdyHeaderBlock& headers, 30923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) bool fin, 31023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) QuicAckNotifier::DelegateInterface* ack_notifier_delegate) { 31123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) return headers_stream_->WriteHeaders(id, headers, fin, ack_notifier_delegate); 3125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 3135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void QuicSession::SendRstStream(QuicStreamId id, 3155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) QuicRstStreamErrorCode error, 3165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) QuicStreamOffset bytes_written) { 317c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch if (connection()->connected()) { 3180529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch // Only send a RST_STREAM frame if still connected. 319c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch connection_->SendRstStream(id, error, bytes_written); 320c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch } 321424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) CloseStreamInner(id, true); 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void QuicSession::SendGoAway(QuicErrorCode error_code, const string& reason) { 325a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (goaway_sent_) { 326a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return; 327a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) goaway_sent_ = true; 3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) connection_->SendGoAway(error_code, largest_peer_created_stream_id_, reason); 3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void QuicSession::CloseStream(QuicStreamId stream_id) { 333424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) CloseStreamInner(stream_id, false); 334424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)} 335424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 336424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)void QuicSession::CloseStreamInner(QuicStreamId stream_id, 337424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) bool locally_reset) { 338f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DVLOG(1) << ENDPOINT << "Closing stream " << stream_id; 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DataStreamMap::iterator it = stream_map_.find(stream_id); 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (it == stream_map_.end()) { 342f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DVLOG(1) << ENDPOINT << "Stream is already closed: " << stream_id; 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) QuicDataStream* stream = it->second; 3465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Tell the stream that a RST has been sent. 3485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (locally_reset) { 3495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) stream->set_rst_sent(true); 3505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 3515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) closed_streams_.push_back(it->second); 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stream_map_.erase(it); 354c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) stream->OnClose(); 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 357c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool QuicSession::IsEncryptionEstablished() { 358c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return GetCryptoStream()->encryption_established(); 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 361c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool QuicSession::IsCryptoHandshakeConfirmed() { 362c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return GetCryptoStream()->handshake_confirmed(); 363c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 364c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 3650f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)void QuicSession::OnConfigNegotiated() { 3660f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) connection_->SetFromConfig(config_); 367e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch // Tell all streams about the newly received peer receive window. 3680529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch if (connection()->version() >= QUIC_VERSION_17 && 3690529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch config_.HasReceivedInitialFlowControlWindowBytes()) { 370e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch // Streams which were created before the SHLO was received (0RTT requests) 371e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch // are now informed of the peer's initial flow control window. 372e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch uint32 new_flow_control_send_window = 3730529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch config_.ReceivedInitialFlowControlWindowBytes(); 374e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch if (new_flow_control_send_window < kDefaultFlowControlSendWindow) { 3750529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch LOG(ERROR) 376e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch << "Peer sent us an invalid flow control send window: " 377e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch << new_flow_control_send_window 378e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch << ", below default: " << kDefaultFlowControlSendWindow; 379e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch connection_->SendConnectionClose(QUIC_FLOW_CONTROL_ERROR); 380e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch return; 381e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch } 382e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch DataStreamMap::iterator it = stream_map_.begin(); 383e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch while (it != stream_map_.end()) { 3840529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch it->second->flow_controller()->UpdateSendWindowOffset( 3850529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch new_flow_control_send_window); 386e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch it++; 387e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch } 388e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch } 3890f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)} 3900f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) 391c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void QuicSession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) { 39290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) switch (event) { 39390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // TODO(satyamshekhar): Move the logic of setting the encrypter/decrypter 39490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // to QuicSession since it is the glue. 39590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) case ENCRYPTION_FIRST_ESTABLISHED: 39690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) break; 39790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 39890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) case ENCRYPTION_REESTABLISHED: 39990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // Retransmit originally packets that were sent, since they can't be 40090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // decrypted by the peer. 401a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) connection_->RetransmitUnackedPackets(INITIAL_ENCRYPTION_ONLY); 40290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) break; 40390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 40490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) case HANDSHAKE_CONFIRMED: 405868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) LOG_IF(DFATAL, !config_.negotiated()) << ENDPOINT 40690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) << "Handshake confirmed without parameter negotiation."; 4075c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Discard originally encrypted packets, since they can't be decrypted by 4085c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // the peer. 4095c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu connection_->NeuterUnencryptedPackets(); 410868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) connection_->SetOverallConnectionTimeout(QuicTime::Delta::Infinite()); 41190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) max_open_streams_ = config_.max_streams_per_connection(); 41290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) break; 41390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 41490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) default: 415868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) LOG(ERROR) << ENDPOINT << "Got unknown handshake event: " << event; 416b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) } 4172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 4182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void QuicSession::OnCryptoHandshakeMessageSent( 4203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) const CryptoHandshakeMessage& message) { 4213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)} 4223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 4233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void QuicSession::OnCryptoHandshakeMessageReceived( 4243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) const CryptoHandshakeMessage& message) { 4253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)} 4263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 42790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)QuicConfig* QuicSession::config() { 42890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return &config_; 42990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 43090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 4315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void QuicSession::ActivateStream(QuicDataStream* stream) { 432f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DVLOG(1) << ENDPOINT << "num_streams: " << stream_map_.size() 433a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) << ". activating " << stream->id(); 434d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) DCHECK_EQ(stream_map_.count(stream->id()), 0u); 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stream_map_[stream->id()] = stream; 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)QuicStreamId QuicSession::GetNextStreamId() { 4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) QuicStreamId id = next_stream_id_; 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_stream_id_ += 2; 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return id; 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ReliableQuicStream* QuicSession::GetStream(const QuicStreamId stream_id) { 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (stream_id == kCryptoStreamId) { 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return GetCryptoStream(); 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 448a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (stream_id == kHeadersStreamId) { 4495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return headers_stream_.get(); 4505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 4515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return GetDataStream(stream_id); 4525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 4535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 4545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)QuicDataStream* QuicSession::GetDataStream(const QuicStreamId stream_id) { 4555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (stream_id == kCryptoStreamId) { 4565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DLOG(FATAL) << "Attempt to call GetDataStream with the crypto stream id"; 4575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return NULL; 4585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 459a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (stream_id == kHeadersStreamId) { 4605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DLOG(FATAL) << "Attempt to call GetDataStream with the headers stream id"; 4615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return NULL; 4625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DataStreamMap::iterator it = stream_map_.find(stream_id); 4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (it != stream_map_.end()) { 4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return it->second; 4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (IsClosedStream(stream_id)) { 4702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return NULL; 4712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (stream_id % 2 == next_stream_id_ % 2) { 4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We've received a frame for a locally-created stream that is not 4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // currently active. This is an error. 4765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (connection()->connected()) { 4775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) connection()->SendConnectionClose(QUIC_PACKET_FOR_NONEXISTENT_STREAM); 4785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return GetIncomingDataStream(stream_id); 4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)QuicDataStream* QuicSession::GetIncomingDataStream(QuicStreamId stream_id) { 4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (IsClosedStream(stream_id)) { 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) implicitly_created_streams_.erase(stream_id); 4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (stream_id > largest_peer_created_stream_id_) { 4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (stream_id - largest_peer_created_stream_id_ > kMaxStreamIdDelta) { 493e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch // We may already have sent a connection close due to multiple reset 494e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch // streams in the same packet. 495e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch if (connection()->connected()) { 496e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch LOG(ERROR) << "Trying to get stream: " << stream_id 497e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch << ", largest peer created stream: " 498e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch << largest_peer_created_stream_id_ 499e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch << ", max delta: " << kMaxStreamIdDelta; 500e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch connection()->SendConnectionClose(QUIC_INVALID_STREAM_ID); 501e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch } 5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 50458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (largest_peer_created_stream_id_ == 0) { 505a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (is_server()) { 5065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) largest_peer_created_stream_id_= 3; 5075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } else { 5085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) largest_peer_created_stream_id_= 1; 5095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 51058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 51158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) for (QuicStreamId id = largest_peer_created_stream_id_ + 2; 51258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) id < stream_id; 51358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) id += 2) { 51458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) implicitly_created_streams_.insert(id); 5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) largest_peer_created_stream_id_ = stream_id; 5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) QuicDataStream* stream = CreateIncomingDataStream(stream_id); 5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (stream == NULL) { 5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ActivateStream(stream); 5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return stream; 5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool QuicSession::IsClosedStream(QuicStreamId id) { 5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_NE(0u, id); 5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (id == kCryptoStreamId) { 5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 531a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (id == kHeadersStreamId) { 532a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return false; 533424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) } 534424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) if (ContainsKey(stream_map_, id)) { 5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Stream is active 5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (id % 2 == next_stream_id_ % 2) { 5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Locally created streams are strictly in-order. If the id is in the 5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // range of created streams and it's not active, it must have been closed. 5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return id < next_stream_id_; 5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // For peer created streams, we also need to consider implicitly created 5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // streams. 5452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return id <= largest_peer_created_stream_id_ && 5462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) implicitly_created_streams_.count(id) == 0; 5472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)size_t QuicSession::GetNumOpenStreams() const { 550a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return stream_map_.size() + implicitly_created_streams_.size(); 5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 553d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void QuicSession::MarkWriteBlocked(QuicStreamId id, QuicPriority priority) { 5545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#ifndef NDEBUG 5555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ReliableQuicStream* stream = GetStream(id); 5565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (stream != NULL) { 5570529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch if (stream->flow_controller()->IsBlocked()) { 5580529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch LOG(DFATAL) << ENDPOINT << "Stream " << id 5590529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch << " is flow control blocked and write blocked!"; 560e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch } 5615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) LOG_IF(DFATAL, priority != stream->EffectivePriority()) 5620529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch << ENDPOINT << "Stream " << id 5635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) << "Priorities do not match. Got: " << priority 5645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) << " Expected: " << stream->EffectivePriority(); 5655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } else { 5665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) LOG(DFATAL) << "Marking unknown stream " << id << " blocked."; 5675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 5685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#endif 5695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 570d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) if (id == kCryptoStreamId) { 571d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) DCHECK(!has_pending_handshake_); 572d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) has_pending_handshake_ = true; 573d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // TODO(jar): Be sure to use the highest priority for the crypto stream, 574d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // perhaps by adding a "special" priority for it that is higher than 575d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // kHighestPriority. 576d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) priority = kHighestPriority; 577d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) } 578a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) write_blocked_streams_.PushBack(id, priority); 5792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 5802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool QuicSession::HasDataToWrite() const { 5825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return write_blocked_streams_.HasWriteBlockedStreams() || 583f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) connection_->HasQueuedData(); 584f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 585f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 58623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)bool QuicSession::GetSSLInfo(SSLInfo* ssl_info) const { 5877dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch NOTIMPLEMENTED(); 5887dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch return false; 5897dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch} 5907dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 5912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void QuicSession::PostProcessAfterData() { 5922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) STLDeleteElements(&closed_streams_); 5932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) closed_streams_.clear(); 5942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 5952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace net 597