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