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