|  | // Copyright 2013 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "net/quic/test_tools/quic_test_packet_maker.h" | 
|  |  | 
|  | #include <list> | 
|  |  | 
|  | #include "net/quic/quic_framer.h" | 
|  | #include "net/quic/quic_http_utils.h" | 
|  | #include "net/quic/quic_utils.h" | 
|  | #include "net/quic/test_tools/quic_test_utils.h" | 
|  |  | 
|  | using std::make_pair; | 
|  |  | 
|  | namespace net { | 
|  | namespace test { | 
|  |  | 
|  | QuicTestPacketMaker::QuicTestPacketMaker(QuicVersion version, | 
|  | QuicConnectionId connection_id, | 
|  | MockClock* clock, | 
|  | const std::string& host) | 
|  | : version_(version), | 
|  | connection_id_(connection_id), | 
|  | clock_(clock), | 
|  | host_(host), | 
|  | spdy_request_framer_(HTTP2), | 
|  | spdy_response_framer_(HTTP2) {} | 
|  |  | 
|  | QuicTestPacketMaker::~QuicTestPacketMaker() {} | 
|  |  | 
|  | void QuicTestPacketMaker::set_hostname(const std::string& host) { | 
|  | host_.assign(host); | 
|  | } | 
|  |  | 
|  | scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakePingPacket( | 
|  | QuicPacketNumber num, | 
|  | bool include_version) { | 
|  | QuicPacketHeader header; | 
|  | header.public_header.connection_id = connection_id_; | 
|  | header.public_header.reset_flag = false; | 
|  | header.public_header.version_flag = include_version; | 
|  | header.public_header.packet_number_length = PACKET_1BYTE_PACKET_NUMBER; | 
|  | header.packet_number = num; | 
|  | header.entropy_flag = false; | 
|  | header.fec_flag = false; | 
|  | header.fec_group = 0; | 
|  |  | 
|  | QuicPingFrame ping; | 
|  | return scoped_ptr<QuicEncryptedPacket>(MakePacket(header, QuicFrame(ping))); | 
|  | } | 
|  |  | 
|  | scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakeRstPacket( | 
|  | QuicPacketNumber num, | 
|  | bool include_version, | 
|  | QuicStreamId stream_id, | 
|  | QuicRstStreamErrorCode error_code) { | 
|  | QuicPacketHeader header; | 
|  | header.public_header.connection_id = connection_id_; | 
|  | header.public_header.reset_flag = false; | 
|  | header.public_header.version_flag = include_version; | 
|  | header.public_header.packet_number_length = PACKET_1BYTE_PACKET_NUMBER; | 
|  | header.packet_number = num; | 
|  | header.entropy_flag = false; | 
|  | header.fec_flag = false; | 
|  | header.fec_group = 0; | 
|  |  | 
|  | QuicRstStreamFrame rst(stream_id, error_code, 0); | 
|  | return scoped_ptr<QuicEncryptedPacket>(MakePacket(header, QuicFrame(&rst))); | 
|  | } | 
|  |  | 
|  | scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakeAckAndRstPacket( | 
|  | QuicPacketNumber num, | 
|  | bool include_version, | 
|  | QuicStreamId stream_id, | 
|  | QuicRstStreamErrorCode error_code, | 
|  | QuicPacketNumber largest_received, | 
|  | QuicPacketNumber least_unacked, | 
|  | bool send_feedback) { | 
|  | QuicPacketHeader header; | 
|  | header.public_header.connection_id = connection_id_; | 
|  | header.public_header.reset_flag = false; | 
|  | header.public_header.version_flag = include_version; | 
|  | header.public_header.packet_number_length = PACKET_1BYTE_PACKET_NUMBER; | 
|  | header.packet_number = num; | 
|  | header.entropy_flag = false; | 
|  | header.fec_flag = false; | 
|  | header.fec_group = 0; | 
|  |  | 
|  | QuicAckFrame ack(MakeAckFrame(largest_received)); | 
|  | ack.ack_delay_time = QuicTime::Delta::Zero(); | 
|  | for (QuicPacketNumber i = least_unacked; i <= largest_received; ++i) { | 
|  | ack.received_packet_times.push_back(make_pair(i, clock_->Now())); | 
|  | } | 
|  | QuicFrames frames; | 
|  | frames.push_back(QuicFrame(&ack)); | 
|  |  | 
|  | QuicStopWaitingFrame stop_waiting; | 
|  | stop_waiting.least_unacked = least_unacked; | 
|  | frames.push_back(QuicFrame(&stop_waiting)); | 
|  |  | 
|  | QuicRstStreamFrame rst(stream_id, error_code, 0); | 
|  | frames.push_back(QuicFrame(&rst)); | 
|  |  | 
|  | QuicFramer framer(SupportedVersions(version_), clock_->Now(), | 
|  | Perspective::IS_CLIENT); | 
|  | scoped_ptr<QuicPacket> packet( | 
|  | BuildUnsizedDataPacket(&framer, header, frames)); | 
|  | char buffer[kMaxPacketSize]; | 
|  | size_t encrypted_size = framer.EncryptPayload( | 
|  | ENCRYPTION_NONE, header.packet_number, *packet, buffer, kMaxPacketSize); | 
|  | EXPECT_NE(0u, encrypted_size); | 
|  | QuicEncryptedPacket encrypted(buffer, encrypted_size, false); | 
|  | return scoped_ptr<QuicEncryptedPacket>(encrypted.Clone()); | 
|  | } | 
|  |  | 
|  | scoped_ptr<QuicEncryptedPacket> | 
|  | QuicTestPacketMaker::MakeAckAndConnectionClosePacket( | 
|  | QuicPacketNumber num, | 
|  | bool include_version, | 
|  | QuicTime::Delta ack_delay_time, | 
|  | QuicPacketNumber largest_received, | 
|  | QuicPacketNumber least_unacked, | 
|  | QuicErrorCode quic_error, | 
|  | std::string& quic_error_details) { | 
|  | QuicPacketHeader header; | 
|  | header.public_header.connection_id = connection_id_; | 
|  | header.public_header.reset_flag = false; | 
|  | header.public_header.version_flag = include_version; | 
|  | header.public_header.packet_number_length = PACKET_1BYTE_PACKET_NUMBER; | 
|  | header.packet_number = num; | 
|  | header.entropy_flag = false; | 
|  | header.fec_flag = false; | 
|  | header.fec_group = 0; | 
|  |  | 
|  | QuicAckFrame ack(MakeAckFrame(largest_received)); | 
|  | ack.ack_delay_time = ack_delay_time; | 
|  | for (QuicPacketNumber i = least_unacked; i <= largest_received; ++i) { | 
|  | ack.received_packet_times.push_back(make_pair(i, clock_->Now())); | 
|  | } | 
|  | QuicFrames frames; | 
|  | frames.push_back(QuicFrame(&ack)); | 
|  | DVLOG(1) << "Adding frame: " << frames[0]; | 
|  |  | 
|  | QuicStopWaitingFrame stop_waiting; | 
|  | stop_waiting.least_unacked = least_unacked; | 
|  | frames.push_back(QuicFrame(&stop_waiting)); | 
|  | DVLOG(1) << "Adding frame: " << frames[1]; | 
|  |  | 
|  | QuicConnectionCloseFrame close; | 
|  | close.error_code = quic_error; | 
|  | close.error_details = quic_error_details; | 
|  |  | 
|  | frames.push_back(QuicFrame(&close)); | 
|  | DVLOG(1) << "Adding frame: " << frames[2]; | 
|  |  | 
|  | QuicFramer framer(SupportedVersions(version_), clock_->Now(), | 
|  | Perspective::IS_CLIENT); | 
|  | scoped_ptr<QuicPacket> packet( | 
|  | BuildUnsizedDataPacket(&framer, header, frames)); | 
|  | char buffer[kMaxPacketSize]; | 
|  | size_t encrypted_size = framer.EncryptPayload( | 
|  | ENCRYPTION_NONE, header.packet_number, *packet, buffer, kMaxPacketSize); | 
|  | EXPECT_NE(0u, encrypted_size); | 
|  | QuicEncryptedPacket encrypted(buffer, encrypted_size, false); | 
|  | return scoped_ptr<QuicEncryptedPacket>(encrypted.Clone()); | 
|  | } | 
|  |  | 
|  | scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakeConnectionClosePacket( | 
|  | QuicPacketNumber num) { | 
|  | QuicPacketHeader header; | 
|  | header.public_header.connection_id = connection_id_; | 
|  | header.public_header.reset_flag = false; | 
|  | header.public_header.version_flag = false; | 
|  | header.public_header.packet_number_length = PACKET_1BYTE_PACKET_NUMBER; | 
|  | header.packet_number = num; | 
|  | header.entropy_flag = false; | 
|  | header.fec_flag = false; | 
|  | header.fec_group = 0; | 
|  |  | 
|  | QuicConnectionCloseFrame close; | 
|  | close.error_code = QUIC_CRYPTO_VERSION_NOT_SUPPORTED; | 
|  | close.error_details = "Time to panic!"; | 
|  | return scoped_ptr<QuicEncryptedPacket>(MakePacket(header, QuicFrame(&close))); | 
|  | } | 
|  |  | 
|  | // Sets both least_unacked fields in stop waiting frame and ack frame | 
|  | // to be |least_unacked|. | 
|  | scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakeAckPacket( | 
|  | QuicPacketNumber packet_number, | 
|  | QuicPacketNumber largest_received, | 
|  | QuicPacketNumber least_unacked, | 
|  | bool send_feedback) { | 
|  | return MakeAckPacket(packet_number, largest_received, least_unacked, | 
|  | least_unacked, send_feedback); | 
|  | } | 
|  |  | 
|  | scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakeAckPacket( | 
|  | QuicPacketNumber packet_number, | 
|  | QuicPacketNumber largest_received, | 
|  | QuicPacketNumber ack_least_unacked, | 
|  | QuicPacketNumber stop_least_unacked, | 
|  | bool send_feedback) { | 
|  | QuicPacketHeader header; | 
|  | header.public_header.connection_id = connection_id_; | 
|  | header.public_header.reset_flag = false; | 
|  | header.public_header.version_flag = false; | 
|  | header.public_header.packet_number_length = PACKET_1BYTE_PACKET_NUMBER; | 
|  | header.packet_number = packet_number; | 
|  | header.entropy_flag = false; | 
|  | header.fec_flag = false; | 
|  | header.fec_group = 0; | 
|  |  | 
|  | QuicAckFrame ack(MakeAckFrame(largest_received)); | 
|  | ack.ack_delay_time = QuicTime::Delta::Zero(); | 
|  | for (QuicPacketNumber i = ack_least_unacked; i <= largest_received; ++i) { | 
|  | ack.received_packet_times.push_back(make_pair(i, clock_->Now())); | 
|  | } | 
|  |  | 
|  | QuicFramer framer(SupportedVersions(version_), clock_->Now(), | 
|  | Perspective::IS_CLIENT); | 
|  | QuicFrames frames; | 
|  | frames.push_back(QuicFrame(&ack)); | 
|  |  | 
|  | QuicStopWaitingFrame stop_waiting; | 
|  | stop_waiting.least_unacked = stop_least_unacked; | 
|  | frames.push_back(QuicFrame(&stop_waiting)); | 
|  |  | 
|  | scoped_ptr<QuicPacket> packet( | 
|  | BuildUnsizedDataPacket(&framer, header, frames)); | 
|  | char buffer[kMaxPacketSize]; | 
|  | size_t encrypted_size = framer.EncryptPayload( | 
|  | ENCRYPTION_NONE, header.packet_number, *packet, buffer, kMaxPacketSize); | 
|  | EXPECT_NE(0u, encrypted_size); | 
|  | QuicEncryptedPacket encrypted(buffer, encrypted_size, false); | 
|  | return scoped_ptr<QuicEncryptedPacket>(encrypted.Clone()); | 
|  | } | 
|  |  | 
|  | // Returns a newly created packet to send kData on stream 1. | 
|  | scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakeDataPacket( | 
|  | QuicPacketNumber packet_number, | 
|  | QuicStreamId stream_id, | 
|  | bool should_include_version, | 
|  | bool fin, | 
|  | QuicStreamOffset offset, | 
|  | base::StringPiece data) { | 
|  | InitializeHeader(packet_number, should_include_version); | 
|  | QuicStreamFrame frame(stream_id, fin, offset, data); | 
|  | return MakePacket(header_, QuicFrame(&frame)); | 
|  | } | 
|  |  | 
|  | scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakeAckAndDataPacket( | 
|  | QuicPacketNumber packet_number, | 
|  | bool include_version, | 
|  | QuicStreamId stream_id, | 
|  | QuicPacketNumber largest_received, | 
|  | QuicPacketNumber least_unacked, | 
|  | bool fin, | 
|  | QuicStreamOffset offset, | 
|  | base::StringPiece data) { | 
|  | InitializeHeader(packet_number, include_version); | 
|  |  | 
|  | QuicAckFrame ack(MakeAckFrame(largest_received)); | 
|  | ack.ack_delay_time = QuicTime::Delta::Zero(); | 
|  | for (QuicPacketNumber i = least_unacked; i <= largest_received; ++i) { | 
|  | ack.received_packet_times.push_back(make_pair(i, clock_->Now())); | 
|  | } | 
|  | QuicFrames frames; | 
|  | frames.push_back(QuicFrame(&ack)); | 
|  |  | 
|  | QuicStopWaitingFrame stop_waiting; | 
|  | stop_waiting.least_unacked = least_unacked; | 
|  | frames.push_back(QuicFrame(&stop_waiting)); | 
|  |  | 
|  | QuicStreamFrame stream_frame(stream_id, fin, offset, data); | 
|  | frames.push_back(QuicFrame(&stream_frame)); | 
|  |  | 
|  | return MakeMultipleFramesPacket(header_, frames); | 
|  | } | 
|  |  | 
|  | scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakeRequestHeadersPacket( | 
|  | QuicPacketNumber packet_number, | 
|  | QuicStreamId stream_id, | 
|  | bool should_include_version, | 
|  | bool fin, | 
|  | SpdyPriority priority, | 
|  | const SpdyHeaderBlock& headers, | 
|  | size_t* spdy_headers_frame_length) { | 
|  | return MakeRequestHeadersPacket(packet_number, stream_id, | 
|  | should_include_version, fin, priority, | 
|  | headers, spdy_headers_frame_length, nullptr); | 
|  | } | 
|  |  | 
|  | // If |offset| is provided, will use the value when creating the packet. | 
|  | // Will also update the value after packet creation. | 
|  | scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakeRequestHeadersPacket( | 
|  | QuicPacketNumber packet_number, | 
|  | QuicStreamId stream_id, | 
|  | bool should_include_version, | 
|  | bool fin, | 
|  | SpdyPriority priority, | 
|  | const SpdyHeaderBlock& headers, | 
|  | size_t* spdy_headers_frame_length, | 
|  | QuicStreamOffset* offset) { | 
|  | InitializeHeader(packet_number, should_include_version); | 
|  | scoped_ptr<SpdySerializedFrame> spdy_frame; | 
|  | if (spdy_request_framer_.protocol_version() == SPDY3) { | 
|  | SpdySynStreamIR syn_stream(stream_id); | 
|  | syn_stream.set_header_block(headers); | 
|  | syn_stream.set_fin(fin); | 
|  | syn_stream.set_priority(priority); | 
|  | spdy_frame.reset(spdy_request_framer_.SerializeSynStream(syn_stream)); | 
|  | } else { | 
|  | SpdyHeadersIR headers_frame(stream_id); | 
|  | headers_frame.set_header_block(headers); | 
|  | headers_frame.set_fin(fin); | 
|  | headers_frame.set_priority(priority); | 
|  | headers_frame.set_has_priority(true); | 
|  | spdy_frame.reset(spdy_request_framer_.SerializeFrame(headers_frame)); | 
|  | } | 
|  | if (spdy_headers_frame_length) { | 
|  | *spdy_headers_frame_length = spdy_frame->size(); | 
|  | } | 
|  | if (offset != nullptr) { | 
|  | QuicStreamFrame frame( | 
|  | kHeadersStreamId, false, *offset, | 
|  | base::StringPiece(spdy_frame->data(), spdy_frame->size())); | 
|  | *offset += spdy_frame->size(); | 
|  | return MakePacket(header_, QuicFrame(&frame)); | 
|  | } else { | 
|  | QuicStreamFrame frame( | 
|  | kHeadersStreamId, false, 0, | 
|  | base::StringPiece(spdy_frame->data(), spdy_frame->size())); | 
|  |  | 
|  | return MakePacket(header_, QuicFrame(&frame)); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Convenience method for calling MakeRequestHeadersPacket with nullptr for | 
|  | // |spdy_headers_frame_length|. | 
|  | scoped_ptr<QuicEncryptedPacket> | 
|  | QuicTestPacketMaker::MakeRequestHeadersPacketWithOffsetTracking( | 
|  | QuicPacketNumber packet_number, | 
|  | QuicStreamId stream_id, | 
|  | bool should_include_version, | 
|  | bool fin, | 
|  | SpdyPriority priority, | 
|  | const SpdyHeaderBlock& headers, | 
|  | QuicStreamOffset* offset) { | 
|  | return MakeRequestHeadersPacket(packet_number, stream_id, | 
|  | should_include_version, fin, priority, | 
|  | headers, nullptr, offset); | 
|  | } | 
|  |  | 
|  | // If |offset| is provided, will use the value when creating the packet. | 
|  | // Will also update the value after packet creation. | 
|  | scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakeResponseHeadersPacket( | 
|  | QuicPacketNumber packet_number, | 
|  | QuicStreamId stream_id, | 
|  | bool should_include_version, | 
|  | bool fin, | 
|  | const SpdyHeaderBlock& headers, | 
|  | size_t* spdy_headers_frame_length, | 
|  | QuicStreamOffset* offset) { | 
|  | InitializeHeader(packet_number, should_include_version); | 
|  | scoped_ptr<SpdySerializedFrame> spdy_frame; | 
|  | if (spdy_response_framer_.protocol_version() == SPDY3) { | 
|  | SpdySynReplyIR syn_reply(stream_id); | 
|  | syn_reply.set_header_block(headers); | 
|  | syn_reply.set_fin(fin); | 
|  | spdy_frame.reset(spdy_response_framer_.SerializeSynReply(syn_reply)); | 
|  | } else { | 
|  | SpdyHeadersIR headers_frame(stream_id); | 
|  | headers_frame.set_header_block(headers); | 
|  | headers_frame.set_fin(fin); | 
|  | spdy_frame.reset(spdy_response_framer_.SerializeFrame(headers_frame)); | 
|  | } | 
|  | if (spdy_headers_frame_length) { | 
|  | *spdy_headers_frame_length = spdy_frame->size(); | 
|  | } | 
|  | if (offset != nullptr) { | 
|  | QuicStreamFrame frame( | 
|  | kHeadersStreamId, false, *offset, | 
|  | base::StringPiece(spdy_frame->data(), spdy_frame->size())); | 
|  | *offset += spdy_frame->size(); | 
|  | return MakePacket(header_, QuicFrame(&frame)); | 
|  | } else { | 
|  | QuicStreamFrame frame( | 
|  | kHeadersStreamId, false, 0, | 
|  | base::StringPiece(spdy_frame->data(), spdy_frame->size())); | 
|  | return MakePacket(header_, QuicFrame(&frame)); | 
|  | } | 
|  | } | 
|  |  | 
|  | scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakeResponseHeadersPacket( | 
|  | QuicPacketNumber packet_number, | 
|  | QuicStreamId stream_id, | 
|  | bool should_include_version, | 
|  | bool fin, | 
|  | const SpdyHeaderBlock& headers, | 
|  | size_t* spdy_headers_frame_length) { | 
|  | return MakeResponseHeadersPacket(packet_number, stream_id, | 
|  | should_include_version, fin, headers, | 
|  | spdy_headers_frame_length, nullptr); | 
|  | } | 
|  |  | 
|  | // Convenience method for calling MakeResponseHeadersPacket with nullptr for | 
|  | // |spdy_headers_frame_length|. | 
|  | scoped_ptr<QuicEncryptedPacket> | 
|  | QuicTestPacketMaker::MakeResponseHeadersPacketWithOffsetTracking( | 
|  | QuicPacketNumber packet_number, | 
|  | QuicStreamId stream_id, | 
|  | bool should_include_version, | 
|  | bool fin, | 
|  | const SpdyHeaderBlock& headers, | 
|  | QuicStreamOffset* offset) { | 
|  | return MakeResponseHeadersPacket(packet_number, stream_id, | 
|  | should_include_version, fin, headers, | 
|  | nullptr, offset); | 
|  | } | 
|  |  | 
|  | SpdyHeaderBlock QuicTestPacketMaker::GetRequestHeaders( | 
|  | const std::string& method, | 
|  | const std::string& scheme, | 
|  | const std::string& path) { | 
|  | SpdyHeaderBlock headers; | 
|  | headers[":method"] = method; | 
|  | headers[":authority"] = host_; | 
|  | headers[":scheme"] = scheme; | 
|  | headers[":path"] = path; | 
|  | return headers; | 
|  | } | 
|  |  | 
|  | SpdyHeaderBlock QuicTestPacketMaker::GetResponseHeaders( | 
|  | const std::string& status) { | 
|  | SpdyHeaderBlock headers; | 
|  | headers[":status"] = status; | 
|  | headers["content-type"] = "text/plain"; | 
|  | return headers; | 
|  | } | 
|  |  | 
|  | SpdyHeaderBlock QuicTestPacketMaker::GetResponseHeaders( | 
|  | const std::string& status, | 
|  | const std::string& alt_svc) { | 
|  | SpdyHeaderBlock headers; | 
|  | headers[":status"] = status; | 
|  | headers["Alt-Svc"] = alt_svc; | 
|  | headers["content-type"] = "text/plain"; | 
|  | return headers; | 
|  | } | 
|  |  | 
|  | scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakePacket( | 
|  | const QuicPacketHeader& header, | 
|  | const QuicFrame& frame) { | 
|  | QuicFrames frames; | 
|  | frames.push_back(frame); | 
|  | return MakeMultipleFramesPacket(header, frames); | 
|  | } | 
|  |  | 
|  | scoped_ptr<QuicEncryptedPacket> QuicTestPacketMaker::MakeMultipleFramesPacket( | 
|  | const QuicPacketHeader& header, | 
|  | const QuicFrames& frames) { | 
|  | QuicFramer framer(SupportedVersions(version_), QuicTime::Zero(), | 
|  | Perspective::IS_CLIENT); | 
|  | scoped_ptr<QuicPacket> packet( | 
|  | BuildUnsizedDataPacket(&framer, header, frames)); | 
|  | char buffer[kMaxPacketSize]; | 
|  | size_t encrypted_size = framer.EncryptPayload( | 
|  | ENCRYPTION_NONE, header.packet_number, *packet, buffer, kMaxPacketSize); | 
|  | EXPECT_NE(0u, encrypted_size); | 
|  | QuicEncryptedPacket encrypted(buffer, encrypted_size, false); | 
|  | return scoped_ptr<QuicEncryptedPacket>(encrypted.Clone()); | 
|  | } | 
|  |  | 
|  | void QuicTestPacketMaker::InitializeHeader(QuicPacketNumber packet_number, | 
|  | bool should_include_version) { | 
|  | header_.public_header.connection_id = connection_id_; | 
|  | header_.public_header.reset_flag = false; | 
|  | header_.public_header.version_flag = should_include_version; | 
|  | header_.public_header.packet_number_length = PACKET_1BYTE_PACKET_NUMBER; | 
|  | header_.packet_number = packet_number; | 
|  | header_.fec_group = 0; | 
|  | header_.entropy_flag = false; | 
|  | header_.fec_flag = false; | 
|  | } | 
|  |  | 
|  | }  // namespace test | 
|  | }  // namespace net |