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