reliable_quic_stream.cc revision c2e0dbddbe15c98d52c4786dac06cb8952a8ae6d
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"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::StringPiece;
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace net {
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ReliableQuicStream::ReliableQuicStream(QuicStreamId id,
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       QuicSession* session)
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : sequencer_(this),
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      id_(id),
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      session_(session),
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      visitor_(NULL),
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      stream_bytes_read_(0),
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      stream_bytes_written_(0),
21c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      stream_error_(QUIC_STREAM_NO_ERROR),
22c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      connection_error_(QUIC_NO_ERROR),
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      read_side_closed_(false),
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      write_side_closed_(false),
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      fin_buffered_(false),
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      fin_sent_(false) {
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ReliableQuicStream::~ReliableQuicStream() {
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ReliableQuicStream::WillAcceptStreamFrame(
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const QuicStreamFrame& frame) const {
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (read_side_closed_) {
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (frame.stream_id != id_) {
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Error!";
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return sequencer_.WillAcceptStreamFrame(frame);
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ReliableQuicStream::OnStreamFrame(const QuicStreamFrame& frame) {
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(frame.stream_id, id_);
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (read_side_closed_) {
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DLOG(INFO) << "Ignoring frame " << frame.stream_id;
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // We don't want to be reading: blackhole the data.
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Note: This count include duplicate data received.
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  stream_bytes_read_ += frame.data.length();
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool accepted = sequencer_.OnStreamFrame(frame);
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (frame.fin) {
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    sequencer_.CloseStreamAtOffset(frame.offset + frame.data.size(), true);
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return accepted;
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
63c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void ReliableQuicStream::OnStreamReset(QuicRstStreamErrorCode error) {
64c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  stream_error_ = error;
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  TerminateFromPeer(false);  // Full close.
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ReliableQuicStream::ConnectionClose(QuicErrorCode error, bool from_peer) {
69c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (IsClosed()) {
70c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
71c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
72c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (error != QUIC_NO_ERROR) {
73c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    stream_error_ = QUIC_STREAM_CONNECTION_ERROR;
74c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    connection_error_ = error;
75c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
76c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (from_peer) {
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TerminateFromPeer(false);
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CloseWriteSide();
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CloseReadSide();
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ReliableQuicStream::TerminateFromPeer(bool half_close) {
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!half_close) {
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CloseWriteSide();
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CloseReadSide();
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
92c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void ReliableQuicStream::Close(QuicRstStreamErrorCode error) {
93c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  stream_error_ = error;
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  session()->SendRstStream(id(), error);
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ReliableQuicStream::IsHalfClosed() const {
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return sequencer_.IsHalfClosed();
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
101c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool ReliableQuicStream::IsClosed() const {
102c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return write_side_closed_ && (read_side_closed_ || IsHalfClosed());
103c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ReliableQuicStream::HasBytesToRead() const {
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return sequencer_.HasBytesToRead();
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const IPEndPoint& ReliableQuicStream::GetPeerAddress() const {
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return session_->peer_address();
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)QuicConsumedData ReliableQuicStream::WriteData(StringPiece data, bool fin) {
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return WriteOrBuffer(data, fin);
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)QuicConsumedData ReliableQuicStream::WriteOrBuffer(StringPiece data, bool fin) {
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!fin_buffered_);
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  QuicConsumedData consumed_data(0, false);
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  fin_buffered_ = fin;
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (queued_data_.empty()) {
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    consumed_data = WriteDataInternal(string(data.data(), data.length()), fin);
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK_LE(consumed_data.bytes_consumed, data.length());
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // If there's unconsumed data or an unconsumed fin, queue it.
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (consumed_data.bytes_consumed < data.length() ||
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      (fin && !consumed_data.fin_consumed)) {
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    queued_data_.push_back(
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        string(data.data() + consumed_data.bytes_consumed,
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               data.length() - consumed_data.bytes_consumed));
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return QuicConsumedData(data.size(), true);
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ReliableQuicStream::OnCanWrite() {
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool fin = false;
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  while (!queued_data_.empty()) {
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const string& data = queued_data_.front();
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (queued_data_.size() == 1 && fin_buffered_) {
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      fin = true;
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    QuicConsumedData consumed_data = WriteDataInternal(data, fin);
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (consumed_data.bytes_consumed == data.size() &&
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        fin == consumed_data.fin_consumed) {
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      queued_data_.pop_front();
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    } else {
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      queued_data_.front().erase(0, consumed_data.bytes_consumed);
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)QuicConsumedData ReliableQuicStream::WriteDataInternal(
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    StringPiece data, bool fin) {
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (write_side_closed_) {
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DLOG(ERROR) << "Attempt to write when the write side is closed";
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return QuicConsumedData(0, false);
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  QuicConsumedData consumed_data =
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      session()->WriteData(id(), data, stream_bytes_written_, fin);
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  stream_bytes_written_ += consumed_data.bytes_consumed;
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (consumed_data.bytes_consumed == data.length()) {
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (fin && consumed_data.fin_consumed) {
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      fin_sent_ = true;
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      CloseWriteSide();
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    session_->MarkWriteBlocked(id());
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return consumed_data;
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ReliableQuicStream::CloseReadSide() {
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (read_side_closed_) {
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DLOG(INFO) << "Done reading from stream " << id();
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  read_side_closed_ = true;
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (write_side_closed_) {
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DLOG(INFO) << "Closing stream: " << id();
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    session_->CloseStream(id());
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ReliableQuicStream::CloseWriteSide() {
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (write_side_closed_) {
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DLOG(INFO) << "Done writing to stream " << id();
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  write_side_closed_ = true;
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (read_side_closed_) {
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DLOG(INFO) << "Closing stream: " << id();
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    session_->CloseStream(id());
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ReliableQuicStream::OnClose() {
205c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  CloseReadSide();
206c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  CloseWriteSide();
207c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (visitor_) {
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Visitor* visitor = visitor_;
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Calling Visitor::OnClose() may result the destruction of the visitor,
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // so we need to ensure we don't call it again.
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    visitor_ = NULL;
2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    visitor->OnClose(this);
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace net
218