| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/quic/quic_connection.h" | 5 #include "net/quic/quic_connection.h" |
| 6 | 6 |
| 7 #include "base/basictypes.h" | 7 #include "base/basictypes.h" |
| 8 #include "base/bind.h" | 8 #include "base/bind.h" |
| 9 #include "net/base/net_errors.h" | 9 #include "net/base/net_errors.h" |
| 10 #include "net/quic/congestion_control/receive_algorithm_interface.h" | 10 #include "net/quic/congestion_control/receive_algorithm_interface.h" |
| 11 #include "net/quic/congestion_control/send_algorithm_interface.h" | 11 #include "net/quic/congestion_control/send_algorithm_interface.h" |
| 12 #include "net/quic/crypto/null_encrypter.h" | 12 #include "net/quic/crypto/null_encrypter.h" |
| 13 #include "net/quic/crypto/quic_decrypter.h" | 13 #include "net/quic/crypto/quic_decrypter.h" |
| 14 #include "net/quic/crypto/quic_encrypter.h" | 14 #include "net/quic/crypto/quic_encrypter.h" |
| 15 #include "net/quic/crypto/quic_random.h" | 15 #include "net/quic/crypto/quic_random.h" |
| 16 #include "net/quic/quic_protocol.h" |
| 16 #include "net/quic/quic_utils.h" | 17 #include "net/quic/quic_utils.h" |
| 17 #include "net/quic/test_tools/mock_clock.h" | 18 #include "net/quic/test_tools/mock_clock.h" |
| 18 #include "net/quic/test_tools/mock_random.h" | 19 #include "net/quic/test_tools/mock_random.h" |
| 19 #include "net/quic/test_tools/quic_connection_peer.h" | 20 #include "net/quic/test_tools/quic_connection_peer.h" |
| 20 #include "net/quic/test_tools/quic_framer_peer.h" | 21 #include "net/quic/test_tools/quic_framer_peer.h" |
| 21 #include "net/quic/test_tools/quic_packet_creator_peer.h" | 22 #include "net/quic/test_tools/quic_packet_creator_peer.h" |
| 22 #include "net/quic/test_tools/quic_test_utils.h" | 23 #include "net/quic/test_tools/quic_test_utils.h" |
| 23 #include "testing/gmock/include/gmock/gmock.h" | 24 #include "testing/gmock/include/gmock/gmock.h" |
| 24 #include "testing/gtest/include/gtest/gtest.h" | 25 #include "testing/gtest/include/gtest/gtest.h" |
| 25 | 26 |
| (...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 243 return random_generator_; | 244 return random_generator_; |
| 244 } | 245 } |
| 245 | 246 |
| 246 virtual int WritePacketToWire(const QuicEncryptedPacket& packet, | 247 virtual int WritePacketToWire(const QuicEncryptedPacket& packet, |
| 247 int* error) OVERRIDE { | 248 int* error) OVERRIDE { |
| 248 if (packet.length() >= sizeof(final_bytes_of_last_packet_)) { | 249 if (packet.length() >= sizeof(final_bytes_of_last_packet_)) { |
| 249 memcpy(&final_bytes_of_last_packet_, packet.data() + packet.length() - 4, | 250 memcpy(&final_bytes_of_last_packet_, packet.data() + packet.length() - 4, |
| 250 sizeof(final_bytes_of_last_packet_)); | 251 sizeof(final_bytes_of_last_packet_)); |
| 251 } | 252 } |
| 252 | 253 |
| 253 QuicFramer framer(kQuicVersion1, QuicTime::Zero(), is_server_); | 254 QuicFramer framer(QuicVersionMax(), QuicTime::Zero(), is_server_); |
| 254 if (use_tagging_decrypter_) { | 255 if (use_tagging_decrypter_) { |
| 255 framer.SetDecrypter(new TaggingDecrypter); | 256 framer.SetDecrypter(new TaggingDecrypter); |
| 256 } | 257 } |
| 257 FramerVisitorCapturingFrames visitor; | 258 FramerVisitorCapturingFrames visitor; |
| 258 framer.set_visitor(&visitor); | 259 framer.set_visitor(&visitor); |
| 259 EXPECT_TRUE(framer.ProcessPacket(packet)); | 260 EXPECT_TRUE(framer.ProcessPacket(packet)); |
| 260 header_ = *visitor.header(); | 261 header_ = *visitor.header(); |
| 261 frame_count_ = visitor.frame_count(); | 262 frame_count_ = visitor.frame_count(); |
| 262 if (visitor.ack()) { | 263 if (visitor.ack()) { |
| 263 ack_.reset(new QuicAckFrame(*visitor.ack())); | 264 ack_.reset(new QuicAckFrame(*visitor.ack())); |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 373 | 374 |
| 374 DISALLOW_COPY_AND_ASSIGN(TestConnectionHelper); | 375 DISALLOW_COPY_AND_ASSIGN(TestConnectionHelper); |
| 375 }; | 376 }; |
| 376 | 377 |
| 377 class TestConnection : public QuicConnection { | 378 class TestConnection : public QuicConnection { |
| 378 public: | 379 public: |
| 379 TestConnection(QuicGuid guid, | 380 TestConnection(QuicGuid guid, |
| 380 IPEndPoint address, | 381 IPEndPoint address, |
| 381 TestConnectionHelper* helper, | 382 TestConnectionHelper* helper, |
| 382 bool is_server) | 383 bool is_server) |
| 383 : QuicConnection(guid, address, helper, is_server), | 384 : QuicConnection(guid, address, helper, is_server, QuicVersionMax()), |
| 384 helper_(helper) { | 385 helper_(helper) { |
| 385 helper_->set_is_server(!is_server); | 386 helper_->set_is_server(!is_server); |
| 386 } | 387 } |
| 387 | 388 |
| 388 void SendAck() { | 389 void SendAck() { |
| 389 QuicConnectionPeer::SendAck(this); | 390 QuicConnectionPeer::SendAck(this); |
| 390 } | 391 } |
| 391 | 392 |
| 392 void SetReceiveAlgorithm(TestReceiveAlgorithm* receive_algorithm) { | 393 void SetReceiveAlgorithm(TestReceiveAlgorithm* receive_algorithm) { |
| 393 QuicConnectionPeer::SetReceiveAlgorithm(this, receive_algorithm); | 394 QuicConnectionPeer::SetReceiveAlgorithm(this, receive_algorithm); |
| 394 } | 395 } |
| 395 | 396 |
| 396 void SetSendAlgorithm(SendAlgorithmInterface* send_algorithm) { | 397 void SetSendAlgorithm(SendAlgorithmInterface* send_algorithm) { |
| 397 QuicConnectionPeer::SetSendAlgorithm(this, send_algorithm); | 398 QuicConnectionPeer::SetSendAlgorithm(this, send_algorithm); |
| 398 } | 399 } |
| 399 | 400 |
| 400 QuicConsumedData SendStreamData1() { | 401 QuicConsumedData SendStreamData1() { |
| 401 return SendStreamData(1u, "food", 0, !kFin); | 402 return SendStreamData(1u, "food", 0, !kFin); |
| 402 } | 403 } |
| 403 | 404 |
| 404 QuicConsumedData SendStreamData2() { | 405 QuicConsumedData SendStreamData2() { |
| 405 return SendStreamData(2u, "food2", 0, !kFin); | 406 return SendStreamData(2u, "food2", 0, !kFin); |
| 406 } | 407 } |
| 407 | 408 |
| 408 bool is_server() { | 409 bool is_server() { |
| 409 return QuicConnectionPeer::IsServer(this); | 410 return QuicConnectionPeer::IsServer(this); |
| 410 } | 411 } |
| 411 | 412 |
| 413 void set_version(QuicVersion version) { |
| 414 framer_.set_version(version); |
| 415 } |
| 416 |
| 412 void set_is_server(bool is_server) { | 417 void set_is_server(bool is_server) { |
| 413 helper_->set_is_server(!is_server); | 418 helper_->set_is_server(!is_server); |
| 414 QuicPacketCreatorPeer::SetIsServer( | 419 QuicPacketCreatorPeer::SetIsServer( |
| 415 QuicConnectionPeer::GetPacketCreator(this), is_server); | 420 QuicConnectionPeer::GetPacketCreator(this), is_server); |
| 416 QuicConnectionPeer::SetIsServer(this, is_server); | 421 QuicConnectionPeer::SetIsServer(this, is_server); |
| 417 } | 422 } |
| 418 | 423 |
| 419 using QuicConnection::SendOrQueuePacket; | 424 using QuicConnection::SendOrQueuePacket; |
| 420 using QuicConnection::DontWaitForPacketsBefore; | 425 using QuicConnection::DontWaitForPacketsBefore; |
| 426 using QuicConnection::SelectMutualVersion; |
| 421 | 427 |
| 422 private: | 428 private: |
| 423 TestConnectionHelper* helper_; | 429 TestConnectionHelper* helper_; |
| 424 | 430 |
| 425 DISALLOW_COPY_AND_ASSIGN(TestConnection); | 431 DISALLOW_COPY_AND_ASSIGN(TestConnection); |
| 426 }; | 432 }; |
| 427 | 433 |
| 428 class QuicConnectionTest : public ::testing::Test { | 434 class QuicConnectionTest : public ::testing::Test { |
| 429 protected: | 435 protected: |
| 430 QuicConnectionTest() | 436 QuicConnectionTest() |
| 431 : guid_(42), | 437 : guid_(42), |
| 432 framer_(kQuicVersion1, QuicTime::Zero(), false), | 438 framer_(QuicVersionMax(), QuicTime::Zero(), false), |
| 433 creator_(guid_, &framer_, QuicRandom::GetInstance(), false), | 439 creator_(guid_, &framer_, QuicRandom::GetInstance(), false), |
| 434 send_algorithm_(new StrictMock<MockSendAlgorithm>), | 440 send_algorithm_(new StrictMock<MockSendAlgorithm>), |
| 435 helper_(new TestConnectionHelper(&clock_, &random_generator_)), | 441 helper_(new TestConnectionHelper(&clock_, &random_generator_)), |
| 436 connection_(guid_, IPEndPoint(), helper_, false), | 442 connection_(guid_, IPEndPoint(), helper_, false), |
| 437 frame1_(1, false, 0, data1), | 443 frame1_(1, false, 0, data1), |
| 438 frame2_(1, false, 3, data2), | 444 frame2_(1, false, 3, data2), |
| 439 accept_packet_(true) { | 445 accept_packet_(true) { |
| 440 connection_.set_visitor(&visitor_); | 446 connection_.set_visitor(&visitor_); |
| 441 connection_.SetSendAlgorithm(send_algorithm_); | 447 connection_.SetSendAlgorithm(send_algorithm_); |
| 442 // Simplify tests by not sending feedback unless specifically configured. | 448 // Simplify tests by not sending feedback unless specifically configured. |
| 443 SetFeedback(NULL); | 449 SetFeedback(NULL); |
| 444 EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _, _)).WillRepeatedly(Return( | 450 EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _, _)).WillRepeatedly(Return( |
| 445 QuicTime::Delta::Zero())); | 451 QuicTime::Delta::Zero())); |
| 446 EXPECT_CALL(*receive_algorithm_, | 452 EXPECT_CALL(*receive_algorithm_, |
| 447 RecordIncomingPacket(_, _, _, _)).Times(AnyNumber()); | 453 RecordIncomingPacket(_, _, _, _)).Times(AnyNumber()); |
| 448 EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(AnyNumber()); | 454 EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(AnyNumber()); |
| 455 EXPECT_CALL(*send_algorithm_, RetransmissionDelay()).WillRepeatedly( |
| 456 Return(QuicTime::Delta::Zero())); |
| 449 } | 457 } |
| 450 | 458 |
| 451 QuicAckFrame* outgoing_ack() { | 459 QuicAckFrame* outgoing_ack() { |
| 452 return QuicConnectionPeer::GetOutgoingAck(&connection_); | 460 return QuicConnectionPeer::GetOutgoingAck(&connection_); |
| 453 } | 461 } |
| 454 | 462 |
| 455 QuicAckFrame* last_ack() { | 463 QuicAckFrame* last_ack() { |
| 456 return helper_->ack(); | 464 return helper_->ack(); |
| 457 } | 465 } |
| 458 | 466 |
| (...skipping 357 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 816 | 824 |
| 817 frame.received_info.missing_packets.erase(191); | 825 frame.received_info.missing_packets.erase(191); |
| 818 frame.received_info.entropy_hash = | 826 frame.received_info.entropy_hash = |
| 819 QuicConnectionPeer::GetSentEntropyHash(&connection_, 192) ^ | 827 QuicConnectionPeer::GetSentEntropyHash(&connection_, 192) ^ |
| 820 QuicConnectionPeer::GetSentEntropyHash(&connection_, 190); | 828 QuicConnectionPeer::GetSentEntropyHash(&connection_, 190); |
| 821 | 829 |
| 822 ProcessAckPacket(&frame, true); | 830 ProcessAckPacket(&frame, true); |
| 823 EXPECT_FALSE(QuicConnectionPeer::GetReceivedTruncatedAck(&connection_)); | 831 EXPECT_FALSE(QuicConnectionPeer::GetReceivedTruncatedAck(&connection_)); |
| 824 } | 832 } |
| 825 | 833 |
| 834 TEST_F(QuicConnectionTest, DISABLED_AckReceiptCausesAckSend) { |
| 835 ProcessPacket(1); |
| 836 // Delay sending, then queue up an ack. |
| 837 EXPECT_CALL(*send_algorithm_, |
| 838 TimeUntilSend(_, NOT_RETRANSMISSION, _)).WillOnce( |
| 839 testing::Return(QuicTime::Delta::FromMicroseconds(1))); |
| 840 QuicConnectionPeer::SendAck(&connection_); |
| 841 |
| 842 // Process an ack with a least unacked of the received ack. |
| 843 // This causes an ack to be sent when TimeUntilSend returns 0. |
| 844 EXPECT_CALL(*send_algorithm_, |
| 845 TimeUntilSend(_, NOT_RETRANSMISSION, _)).WillRepeatedly( |
| 846 testing::Return(QuicTime::Delta::Zero())); |
| 847 // Skip a packet and then record an ack. |
| 848 creator_.set_sequence_number(2); |
| 849 QuicAckFrame frame(0, QuicTime::Zero(), 3); |
| 850 ProcessAckPacket(&frame, true); |
| 851 } |
| 852 |
| 826 TEST_F(QuicConnectionTest, LeastUnackedLower) { | 853 TEST_F(QuicConnectionTest, LeastUnackedLower) { |
| 827 SendStreamDataToPeer(1, "foo", 0, !kFin, NULL); | 854 SendStreamDataToPeer(1, "foo", 0, !kFin, NULL); |
| 828 SendStreamDataToPeer(1, "bar", 3, !kFin, NULL); | 855 SendStreamDataToPeer(1, "bar", 3, !kFin, NULL); |
| 829 SendStreamDataToPeer(1, "eep", 6, !kFin, NULL); | 856 SendStreamDataToPeer(1, "eep", 6, !kFin, NULL); |
| 830 | 857 |
| 831 // Start out saying the least unacked is 2 | 858 // Start out saying the least unacked is 2 |
| 832 creator_.set_sequence_number(5); | 859 creator_.set_sequence_number(5); |
| 833 QuicAckFrame frame(0, QuicTime::Zero(), 2); | 860 QuicAckFrame frame(0, QuicTime::Zero(), 2); |
| 834 ProcessAckPacket(&frame, true); | 861 ProcessAckPacket(&frame, true); |
| 835 | 862 |
| (...skipping 1250 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2086 | 2113 |
| 2087 entropy_hash ^= packet_entropy_hash; | 2114 entropy_hash ^= packet_entropy_hash; |
| 2088 } | 2115 } |
| 2089 EXPECT_TRUE(QuicConnectionPeer::IsValidEntropy( | 2116 EXPECT_TRUE(QuicConnectionPeer::IsValidEntropy( |
| 2090 &connection_, max_sequence_number, missing_packets, entropy_hash)) | 2117 &connection_, max_sequence_number, missing_packets, entropy_hash)) |
| 2091 << ""; | 2118 << ""; |
| 2092 } | 2119 } |
| 2093 | 2120 |
| 2094 // TODO(satyamsehkhar): Add more test when we start supporting more versions. | 2121 // TODO(satyamsehkhar): Add more test when we start supporting more versions. |
| 2095 TEST_F(QuicConnectionTest, SendVersionNegotiationPacket) { | 2122 TEST_F(QuicConnectionTest, SendVersionNegotiationPacket) { |
| 2096 QuicTag kRandomVersion = 143; | 2123 // TODO(rjshade): Update this to use a real version once we have multiple |
| 2097 QuicFramerPeer::SetVersion(&framer_, kRandomVersion); | 2124 // versions in the codebase. |
| 2125 framer_.set_version_for_tests(QUIC_VERSION_UNSUPPORTED); |
| 2098 | 2126 |
| 2099 QuicPacketHeader header; | 2127 QuicPacketHeader header; |
| 2100 header.public_header.guid = guid_; | 2128 header.public_header.guid = guid_; |
| 2101 header.public_header.reset_flag = false; | 2129 header.public_header.reset_flag = false; |
| 2102 header.public_header.version_flag = true; | 2130 header.public_header.version_flag = true; |
| 2103 header.entropy_flag = false; | 2131 header.entropy_flag = false; |
| 2104 header.fec_flag = false; | 2132 header.fec_flag = false; |
| 2105 header.packet_sequence_number = 12; | 2133 header.packet_sequence_number = 12; |
| 2106 header.fec_group = 0; | 2134 header.fec_group = 0; |
| 2107 | 2135 |
| 2108 QuicFrames frames; | 2136 QuicFrames frames; |
| 2109 QuicFrame frame(&frame1_); | 2137 QuicFrame frame(&frame1_); |
| 2110 frames.push_back(frame); | 2138 frames.push_back(frame); |
| 2111 scoped_ptr<QuicPacket> packet( | 2139 scoped_ptr<QuicPacket> packet( |
| 2112 framer_.ConstructFrameDataPacket(header, frames).packet); | 2140 framer_.ConstructFrameDataPacket(header, frames).packet); |
| 2113 scoped_ptr<QuicEncryptedPacket> encrypted( | 2141 scoped_ptr<QuicEncryptedPacket> encrypted( |
| 2114 framer_.EncryptPacket(ENCRYPTION_NONE, 12, *packet)); | 2142 framer_.EncryptPacket(ENCRYPTION_NONE, 12, *packet)); |
| 2115 | 2143 |
| 2116 QuicFramerPeer::SetVersion(&framer_, kQuicVersion1); | 2144 framer_.set_version(QuicVersionMax()); |
| 2117 connection_.set_is_server(true); | 2145 connection_.set_is_server(true); |
| 2118 connection_.ProcessUdpPacket(IPEndPoint(), IPEndPoint(), *encrypted); | 2146 connection_.ProcessUdpPacket(IPEndPoint(), IPEndPoint(), *encrypted); |
| 2119 EXPECT_TRUE(helper_->version_negotiation_packet() != NULL); | 2147 EXPECT_TRUE(helper_->version_negotiation_packet() != NULL); |
| 2120 EXPECT_EQ(1u, | 2148 |
| 2149 size_t num_versions = arraysize(kSupportedQuicVersions); |
| 2150 EXPECT_EQ(num_versions, |
| 2121 helper_->version_negotiation_packet()->versions.size()); | 2151 helper_->version_negotiation_packet()->versions.size()); |
| 2122 EXPECT_EQ(kQuicVersion1, | 2152 |
| 2123 helper_->version_negotiation_packet()->versions[0]); | 2153 // We expect all versions in kSupportedQuicVersions to be |
| 2154 // included in the packet. |
| 2155 for (size_t i = 0; i < num_versions; ++i) { |
| 2156 EXPECT_EQ(kSupportedQuicVersions[i], |
| 2157 helper_->version_negotiation_packet()->versions[i]); |
| 2158 } |
| 2124 } | 2159 } |
| 2125 | 2160 |
| 2126 TEST_F(QuicConnectionTest, CheckSendStats) { | 2161 TEST_F(QuicConnectionTest, CheckSendStats) { |
| 2127 EXPECT_CALL(*send_algorithm_, AbandoningPacket(_, _)).Times(3); | 2162 EXPECT_CALL(*send_algorithm_, AbandoningPacket(_, _)).Times(3); |
| 2128 EXPECT_CALL(*send_algorithm_, | 2163 EXPECT_CALL(*send_algorithm_, |
| 2129 SentPacket(_, _, _, NOT_RETRANSMISSION)); | 2164 SentPacket(_, _, _, NOT_RETRANSMISSION)); |
| 2130 connection_.SendStreamData(1u, "first", 0, !kFin); | 2165 connection_.SendStreamData(1u, "first", 0, !kFin); |
| 2131 size_t first_packet_size = last_sent_packet_size(); | 2166 size_t first_packet_size = last_sent_packet_size(); |
| 2132 | 2167 |
| 2133 EXPECT_CALL(*send_algorithm_, | 2168 EXPECT_CALL(*send_algorithm_, |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2244 scoped_ptr<QuicEncryptedPacket> encrypted(framer_.EncryptPacket( | 2279 scoped_ptr<QuicEncryptedPacket> encrypted(framer_.EncryptPacket( |
| 2245 ENCRYPTION_NONE, 1, *packet)); | 2280 ENCRYPTION_NONE, 1, *packet)); |
| 2246 | 2281 |
| 2247 EXPECT_CALL(visitor_, OnCanWrite()).Times(1).WillOnce(Return(true)); | 2282 EXPECT_CALL(visitor_, OnCanWrite()).Times(1).WillOnce(Return(true)); |
| 2248 EXPECT_CALL(visitor_, ConnectionClose(QUIC_PEER_GOING_AWAY, true)); | 2283 EXPECT_CALL(visitor_, ConnectionClose(QUIC_PEER_GOING_AWAY, true)); |
| 2249 EXPECT_CALL(visitor_, OnPacket(_, _, _, _)).Times(0); | 2284 EXPECT_CALL(visitor_, OnPacket(_, _, _, _)).Times(0); |
| 2250 | 2285 |
| 2251 connection_.ProcessUdpPacket(IPEndPoint(), IPEndPoint(), *encrypted); | 2286 connection_.ProcessUdpPacket(IPEndPoint(), IPEndPoint(), *encrypted); |
| 2252 } | 2287 } |
| 2253 | 2288 |
| 2289 //// The QUIC_VERSION_X versions are deliberately set, rather than using all |
| 2290 //// values in kSupportedQuicVersions. |
| 2291 //TEST_F(QuicConnectionTest, SelectMutualVersion) { |
| 2292 // // Set the connection to speak QUIC_VERSION_6. |
| 2293 // connection_.set_version(QUIC_VERSION_6); |
| 2294 // EXPECT_EQ(connection_.version(), QUIC_VERSION_6); |
| 2295 // |
| 2296 // // Pass in available versions which includes a higher mutually supported |
| 2297 // // version. The higher mutually supported version should be selected. |
| 2298 // EXPECT_TRUE( |
| 2299 // connection_.SelectMutualVersion({QUIC_VERSION_6, QUIC_VERSION_7})); |
| 2300 // EXPECT_EQ(connection_.version(), QUIC_VERSION_7); |
| 2301 // |
| 2302 // // Expect that the lower version is selected. |
| 2303 // EXPECT_TRUE(connection_.SelectMutualVersion({QUIC_VERSION_6})); |
| 2304 // EXPECT_EQ(connection_.version(), QUIC_VERSION_6); |
| 2305 // |
| 2306 // // Shouldn't be able to find a mutually supported version. |
| 2307 // EXPECT_FALSE(connection_.SelectMutualVersion({QUIC_VERSION_UNSUPPORTED})); |
| 2308 //} |
| 2309 |
| 2254 } // namespace | 2310 } // namespace |
| 2255 } // namespace test | 2311 } // namespace test |
| 2256 } // namespace net | 2312 } // namespace net |
| OLD | NEW |