reliable_quic_stream.cc revision 7d4cd473f85ac64c3747c96c277f9e506a0d2246
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/reliable_quic_stream.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/quic/quic_session.h" 8b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "net/quic/quic_spdy_decompressor.h" 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::StringPiece; 11b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)using std::min; 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace net { 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ReliableQuicStream::ReliableQuicStream(QuicStreamId id, 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) QuicSession* session) 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : sequencer_(this), 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) id_(id), 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) session_(session), 202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) visitor_(NULL), 212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) stream_bytes_read_(0), 222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) stream_bytes_written_(0), 23b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) headers_decompressed_(false), 24b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) headers_id_(0), 25c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) stream_error_(QUIC_STREAM_NO_ERROR), 26c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) connection_error_(QUIC_NO_ERROR), 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) read_side_closed_(false), 282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) write_side_closed_(false), 292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) fin_buffered_(false), 302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) fin_sent_(false) { 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ReliableQuicStream::~ReliableQuicStream() { 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ReliableQuicStream::WillAcceptStreamFrame( 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const QuicStreamFrame& frame) const { 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (read_side_closed_) { 392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (frame.stream_id != id_) { 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Error!"; 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return sequencer_.WillAcceptStreamFrame(frame); 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ReliableQuicStream::OnStreamFrame(const QuicStreamFrame& frame) { 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(frame.stream_id, id_); 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (read_side_closed_) { 512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DLOG(INFO) << "Ignoring frame " << frame.stream_id; 522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // We don't want to be reading: blackhole the data. 532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Note: This count include duplicate data received. 562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) stream_bytes_read_ += frame.data.length(); 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool accepted = sequencer_.OnStreamFrame(frame); 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (frame.fin) { 617d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) sequencer_.CloseStreamAtOffset(frame.offset + frame.data.size()); 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return accepted; 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 67c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void ReliableQuicStream::OnStreamReset(QuicRstStreamErrorCode error) { 68c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) stream_error_ = error; 692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) TerminateFromPeer(false); // Full close. 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ReliableQuicStream::ConnectionClose(QuicErrorCode error, bool from_peer) { 737d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if (read_side_closed_ && write_side_closed_) { 74c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return; 75c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 76c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (error != QUIC_NO_ERROR) { 77c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) stream_error_ = QUIC_STREAM_CONNECTION_ERROR; 78c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) connection_error_ = error; 79c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 80c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (from_peer) { 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TerminateFromPeer(false); 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CloseWriteSide(); 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CloseReadSide(); 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ReliableQuicStream::TerminateFromPeer(bool half_close) { 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!half_close) { 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CloseWriteSide(); 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CloseReadSide(); 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 96c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void ReliableQuicStream::Close(QuicRstStreamErrorCode error) { 97c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) stream_error_ = error; 98868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (error != QUIC_STREAM_NO_ERROR) { 99868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // Sending a RstStream results in calling CloseStream. 100868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) session()->SendRstStream(id(), error); 101868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } else { 102868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) session_->CloseStream(id()); 103868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1065e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)size_t ReliableQuicStream::Readv(const struct iovec* iov, size_t iov_len) { 107b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if (headers_decompressed_ && decompressed_headers_.empty()) { 108b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return sequencer_.Readv(iov, iov_len); 109b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) } 110b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) size_t bytes_consumed = 0; 111868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) size_t iov_index = 0; 112b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) while (iov_index < iov_len && 113b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) decompressed_headers_.length() > bytes_consumed) { 1145e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles) size_t bytes_to_read = min(iov[iov_index].iov_len, 1155e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles) decompressed_headers_.length() - bytes_consumed); 116b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) char* iov_ptr = static_cast<char*>(iov[iov_index].iov_base); 117b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) memcpy(iov_ptr, 118b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) decompressed_headers_.data() + bytes_consumed, bytes_to_read); 119b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) bytes_consumed += bytes_to_read; 120b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) ++iov_index; 121b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) } 122b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) decompressed_headers_.erase(0, bytes_consumed); 123b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return bytes_consumed; 124b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)} 125b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 126868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)int ReliableQuicStream::GetReadableRegions(iovec* iov, size_t iov_len) { 127b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if (headers_decompressed_ && decompressed_headers_.empty()) { 128b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return sequencer_.GetReadableRegions(iov, iov_len); 129b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) } 130b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if (iov_len == 0) { 131b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return 0; 132b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) } 133b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) iov[0].iov_base = static_cast<void*>( 134b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) const_cast<char*>(decompressed_headers_.data())); 135b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) iov[0].iov_len = decompressed_headers_.length(); 136b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return 1; 137b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)} 138b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ReliableQuicStream::IsHalfClosed() const { 140b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if (!headers_decompressed_ || !decompressed_headers_.empty()) { 141b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return false; 142b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) } 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return sequencer_.IsHalfClosed(); 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ReliableQuicStream::HasBytesToRead() const { 147b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return !decompressed_headers_.empty() || sequencer_.HasBytesToRead(); 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const IPEndPoint& ReliableQuicStream::GetPeerAddress() const { 1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return session_->peer_address(); 1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 15490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)QuicSpdyCompressor* ReliableQuicStream::compressor() { 15590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return session_->compressor(); 15690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 15790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)QuicConsumedData ReliableQuicStream::WriteData(StringPiece data, bool fin) { 159868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) DCHECK(data.size() > 0 || fin); 1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return WriteOrBuffer(data, fin); 1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)QuicConsumedData ReliableQuicStream::WriteOrBuffer(StringPiece data, bool fin) { 1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(!fin_buffered_); 1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) QuicConsumedData consumed_data(0, false); 1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) fin_buffered_ = fin; 1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (queued_data_.empty()) { 1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) consumed_data = WriteDataInternal(string(data.data(), data.length()), fin); 1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK_LE(consumed_data.bytes_consumed, data.length()); 1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // If there's unconsumed data or an unconsumed fin, queue it. 1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (consumed_data.bytes_consumed < data.length() || 1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) (fin && !consumed_data.fin_consumed)) { 1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) queued_data_.push_back( 1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) string(data.data() + consumed_data.bytes_consumed, 1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) data.length() - consumed_data.bytes_consumed)); 1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return QuicConsumedData(data.size(), true); 1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ReliableQuicStream::OnCanWrite() { 1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool fin = false; 1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) while (!queued_data_.empty()) { 1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const string& data = queued_data_.front(); 1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (queued_data_.size() == 1 && fin_buffered_) { 1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) fin = true; 1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) QuicConsumedData consumed_data = WriteDataInternal(data, fin); 1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (consumed_data.bytes_consumed == data.size() && 1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) fin == consumed_data.fin_consumed) { 1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) queued_data_.pop_front(); 1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) queued_data_.front().erase(0, consumed_data.bytes_consumed); 1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)QuicConsumedData ReliableQuicStream::WriteDataInternal( 2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) StringPiece data, bool fin) { 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (write_side_closed_) { 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DLOG(ERROR) << "Attempt to write when the write side is closed"; 2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return QuicConsumedData(0, false); 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) QuicConsumedData consumed_data = 2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) session()->WriteData(id(), data, stream_bytes_written_, fin); 2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) stream_bytes_written_ += consumed_data.bytes_consumed; 2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (consumed_data.bytes_consumed == data.length()) { 2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (fin && consumed_data.fin_consumed) { 2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) fin_sent_ = true; 2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CloseWriteSide(); 217868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } else if (fin && !consumed_data.fin_consumed) { 218868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) session_->MarkWriteBlocked(id()); 2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) session_->MarkWriteBlocked(id()); 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return consumed_data; 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ReliableQuicStream::CloseReadSide() { 2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (read_side_closed_) { 2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DLOG(INFO) << "Done reading from stream " << id(); 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) read_side_closed_ = true; 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (write_side_closed_) { 2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DLOG(INFO) << "Closing stream: " << id(); 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) session_->CloseStream(id()); 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 239b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)uint32 ReliableQuicStream::ProcessRawData(const char* data, uint32 data_len) { 240b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if (id() == kCryptoStreamId) { 241b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) // The crypto stream does not use compression. 242b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return ProcessData(data, data_len); 243b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) } 244b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) uint32 total_bytes_consumed = 0; 245b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if (headers_id_ == 0u) { 246b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) // The headers ID has not yet been read. Strip it from the beginning of 247b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) // the data stream. 248b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) DCHECK_GT(4u, headers_id_buffer_.length()); 249b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) size_t missing_size = 4 - headers_id_buffer_.length(); 250b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if (data_len < missing_size) { 251b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) StringPiece(data, data_len).AppendToString(&headers_id_buffer_); 252b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return data_len; 253b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) } 254b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) total_bytes_consumed += missing_size; 255b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) StringPiece(data, missing_size).AppendToString(&headers_id_buffer_); 256b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) DCHECK_EQ(4u, headers_id_buffer_.length()); 257b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) memcpy(&headers_id_, headers_id_buffer_.data(), 4); 258b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) headers_id_buffer_.clear(); 259b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) data += missing_size; 260b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) data_len -= missing_size; 261b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) } 262b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) DCHECK_NE(0u, headers_id_); 263b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 264b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) // Once the headers are finished, we simply pass the data through. 265b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if (headers_decompressed_) { 266b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) // Some buffered header data remains. 267b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if (!decompressed_headers_.empty()) { 268b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) ProcessHeaderData(); 269b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) } 270b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if (decompressed_headers_.empty()) { 271b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) DVLOG(1) << "Delegating procesing to ProcessData"; 272b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) total_bytes_consumed += ProcessData(data, data_len); 273b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) } 274b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return total_bytes_consumed; 275b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) } 276b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 277b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) QuicHeaderId current_header_id = 278b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) session_->decompressor()->current_header_id(); 279b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) // Ensure that this header id looks sane. 280b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if (headers_id_ < current_header_id || 281b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) headers_id_ > kMaxHeaderIdDelta + current_header_id) { 282b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) DVLOG(1) << "Invalid headers for stream: " << id() 283b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) << " header_id: " << headers_id_ 284b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) << " current_header_id: " << current_header_id; 285b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) session_->connection()->SendConnectionClose(QUIC_INVALID_HEADER_ID); 286b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return total_bytes_consumed; 287b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) } 288b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 289b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) // If we are head-of-line blocked on decompression, then back up. 290b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if (current_header_id != headers_id_) { 291b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) session_->MarkDecompressionBlocked(headers_id_, id()); 29290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) DVLOG(1) << "Unable to decompress header data for stream: " << id() 29390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) << " header_id: " << headers_id_; 294b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return total_bytes_consumed; 295b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) } 296b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 297b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) // Decompressed data will be delivered to decompressed_headers_. 298b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) size_t bytes_consumed = session_->decompressor()->DecompressData( 299b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) StringPiece(data, data_len), this); 300b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) total_bytes_consumed += bytes_consumed; 301b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 302b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) // Headers are complete if the decompressor has moved on to the 303b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) // next stream. 304b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) headers_decompressed_ = 305b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) session_->decompressor()->current_header_id() != headers_id_; 306b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 307b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) ProcessHeaderData(); 308b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 309b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) // We have processed all of the decompressed data but we might 310b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) // have some more raw data to process. 311b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if (decompressed_headers_.empty() || total_bytes_consumed < data_len) { 312b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) total_bytes_consumed += ProcessData(data + bytes_consumed, 313b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) data_len - bytes_consumed); 314b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) } 315b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 316b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) // The sequencer will push any additional buffered frames if this data 317b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) // has been completely consumed. 318b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return total_bytes_consumed; 319b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)} 320b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 321b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)uint32 ReliableQuicStream::ProcessHeaderData() { 322b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if (decompressed_headers_.empty()) { 323b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return 0; 324b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) } 325b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 326b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) size_t bytes_processed = ProcessData(decompressed_headers_.data(), 327b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) decompressed_headers_.length()); 328b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if (bytes_processed == decompressed_headers_.length()) { 329b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) decompressed_headers_.clear(); 330b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) } else { 331b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) decompressed_headers_ = decompressed_headers_.erase(0, bytes_processed); 332b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) } 333b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return bytes_processed; 334b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)} 335b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 336b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void ReliableQuicStream::OnDecompressorAvailable() { 337b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) DCHECK_EQ(headers_id_, 338b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) session_->decompressor()->current_header_id()); 339b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) DCHECK(!headers_decompressed_); 340b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) DCHECK_EQ(0u, decompressed_headers_.length()); 341b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 342b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) size_t total_bytes_consumed = 0; 343b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) struct iovec iovecs[5]; 344b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) while (!headers_decompressed_) { 345b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) size_t num_iovecs = 346b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) sequencer_.GetReadableRegions(iovecs, arraysize(iovecs)); 347b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 348b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if (num_iovecs == 0) { 349b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return; 350b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) } 351b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) for (size_t i = 0; i < num_iovecs && !headers_decompressed_; i++) { 352b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) total_bytes_consumed += session_->decompressor()->DecompressData( 353b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) StringPiece(static_cast<char*>(iovecs[i].iov_base), 354b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) iovecs[i].iov_len), this); 355b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 356b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) headers_decompressed_ = 357b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) session_->decompressor()->current_header_id() != headers_id_; 358b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) } 359b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) } 360b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 361b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) // Either the headers are complete, or the all data as been consumed. 362b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) sequencer_.MarkConsumed(total_bytes_consumed); 363b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) ProcessHeaderData(); // Unprocessed headers remain in decompressed_headers_. 3647d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if (IsHalfClosed()) { 3657d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) TerminateFromPeer(true); 3667d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) } else if (headers_decompressed_ && decompressed_headers_.empty()) { 367b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) sequencer_.FlushBufferedFrames(); 368b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) } 369b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)} 370b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 371b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)bool ReliableQuicStream::OnDecompressedData(StringPiece data) { 372b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) data.AppendToString(&decompressed_headers_); 373b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return true; 374b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)} 375b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 37690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void ReliableQuicStream::OnDecompressionError() { 37790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) session_->connection()->SendConnectionClose(QUIC_DECOMPRESSION_FAILURE); 37890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 37990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 38090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ReliableQuicStream::CloseWriteSide() { 3822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (write_side_closed_) { 3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 3842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DLOG(INFO) << "Done writing to stream " << id(); 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) write_side_closed_ = true; 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (read_side_closed_) { 3892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DLOG(INFO) << "Closing stream: " << id(); 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) session_->CloseStream(id()); 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ReliableQuicStream::OnClose() { 395c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) CloseReadSide(); 396c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) CloseWriteSide(); 397c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 3982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (visitor_) { 3992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Visitor* visitor = visitor_; 4002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Calling Visitor::OnClose() may result the destruction of the visitor, 4012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // so we need to ensure we don't call it again. 4022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) visitor_ = NULL; 4032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) visitor->OnClose(this); 4042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 4062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace net 408