OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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/base/network_quality_estimator.h" | 5 #include "net/base/network_quality_estimator.h" |
6 | 6 |
7 #include <stdint.h> | 7 #include <stdint.h> |
8 | 8 |
9 #include <limits> | 9 #include <limits> |
10 #include <map> | 10 #include <map> |
(...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
217 // Network quality should be unavailable when no observations are available. | 217 // Network quality should be unavailable when no observations are available. |
218 base::TimeDelta rtt; | 218 base::TimeDelta rtt; |
219 EXPECT_FALSE(estimator.GetRTTEstimate(&rtt)); | 219 EXPECT_FALSE(estimator.GetRTTEstimate(&rtt)); |
220 int32_t kbps; | 220 int32_t kbps; |
221 EXPECT_FALSE(estimator.GetDownlinkThroughputKbpsEstimate(&kbps)); | 221 EXPECT_FALSE(estimator.GetDownlinkThroughputKbpsEstimate(&kbps)); |
222 | 222 |
223 // Insert samples from {1,2,3,..., 100}. First insert odd samples, then even | 223 // Insert samples from {1,2,3,..., 100}. First insert odd samples, then even |
224 // samples. This helps in verifying that the order of samples does not matter. | 224 // samples. This helps in verifying that the order of samples does not matter. |
225 for (int i = 1; i <= 99; i += 2) { | 225 for (int i = 1; i <= 99; i += 2) { |
226 estimator.downstream_throughput_kbps_observations_.AddObservation( | 226 estimator.downstream_throughput_kbps_observations_.AddObservation( |
227 NetworkQualityEstimator::Observation(i, now)); | 227 NetworkQualityEstimator::Observation( |
| 228 i, now, NetworkQualityEstimator::OBSERVATION_SOURCE_URL_REQUEST)); |
228 estimator.rtt_msec_observations_.AddObservation( | 229 estimator.rtt_msec_observations_.AddObservation( |
229 NetworkQualityEstimator::Observation(i, now)); | 230 NetworkQualityEstimator::Observation( |
| 231 i, now, NetworkQualityEstimator::OBSERVATION_SOURCE_URL_REQUEST)); |
230 EXPECT_TRUE(estimator.GetRTTEstimate(&rtt)); | 232 EXPECT_TRUE(estimator.GetRTTEstimate(&rtt)); |
231 EXPECT_TRUE(estimator.GetDownlinkThroughputKbpsEstimate(&kbps)); | 233 EXPECT_TRUE(estimator.GetDownlinkThroughputKbpsEstimate(&kbps)); |
232 } | 234 } |
233 | 235 |
234 for (int i = 2; i <= 100; i += 2) { | 236 for (int i = 2; i <= 100; i += 2) { |
235 estimator.downstream_throughput_kbps_observations_.AddObservation( | 237 estimator.downstream_throughput_kbps_observations_.AddObservation( |
236 NetworkQualityEstimator::Observation(i, now)); | 238 NetworkQualityEstimator::Observation( |
| 239 i, now, NetworkQualityEstimator::OBSERVATION_SOURCE_URL_REQUEST)); |
237 estimator.rtt_msec_observations_.AddObservation( | 240 estimator.rtt_msec_observations_.AddObservation( |
238 NetworkQualityEstimator::Observation(i, now)); | 241 NetworkQualityEstimator::Observation( |
| 242 i, now, NetworkQualityEstimator::OBSERVATION_SOURCE_URL_REQUEST)); |
239 EXPECT_TRUE(estimator.GetRTTEstimate(&rtt)); | 243 EXPECT_TRUE(estimator.GetRTTEstimate(&rtt)); |
240 EXPECT_TRUE(estimator.GetDownlinkThroughputKbpsEstimate(&kbps)); | 244 EXPECT_TRUE(estimator.GetDownlinkThroughputKbpsEstimate(&kbps)); |
241 } | 245 } |
242 | 246 |
243 for (int i = 0; i <= 100; ++i) { | 247 for (int i = 0; i <= 100; ++i) { |
244 // Checks if the difference between the two integers is less than 1. This is | 248 // Checks if the difference between the two integers is less than 1. This is |
245 // required because computed percentiles may be slightly different from | 249 // required because computed percentiles may be slightly different from |
246 // what is expected due to floating point computation errors and integer | 250 // what is expected due to floating point computation errors and integer |
247 // rounding off errors. | 251 // rounding off errors. |
248 EXPECT_NEAR(estimator.GetDownlinkThroughputKbpsEstimateInternal( | 252 EXPECT_NEAR(estimator.GetDownlinkThroughputKbpsEstimateInternal( |
(...skipping 20 matching lines...) Expand all Loading... |
269 // order. RTT percentiles must be in increasing order. | 273 // order. RTT percentiles must be in increasing order. |
270 TEST(NetworkQualityEstimatorTest, PercentileDifferentTimestamps) { | 274 TEST(NetworkQualityEstimatorTest, PercentileDifferentTimestamps) { |
271 std::map<std::string, std::string> variation_params; | 275 std::map<std::string, std::string> variation_params; |
272 TestNetworkQualityEstimator estimator(variation_params); | 276 TestNetworkQualityEstimator estimator(variation_params); |
273 base::TimeTicks now = base::TimeTicks::Now(); | 277 base::TimeTicks now = base::TimeTicks::Now(); |
274 base::TimeTicks very_old = base::TimeTicks::UnixEpoch(); | 278 base::TimeTicks very_old = base::TimeTicks::UnixEpoch(); |
275 | 279 |
276 // First 50 samples have very old timestamp. | 280 // First 50 samples have very old timestamp. |
277 for (int i = 1; i <= 50; ++i) { | 281 for (int i = 1; i <= 50; ++i) { |
278 estimator.downstream_throughput_kbps_observations_.AddObservation( | 282 estimator.downstream_throughput_kbps_observations_.AddObservation( |
279 NetworkQualityEstimator::Observation(i, very_old)); | 283 NetworkQualityEstimator::Observation( |
| 284 i, very_old, |
| 285 NetworkQualityEstimator::OBSERVATION_SOURCE_URL_REQUEST)); |
280 estimator.rtt_msec_observations_.AddObservation( | 286 estimator.rtt_msec_observations_.AddObservation( |
281 NetworkQualityEstimator::Observation(i, very_old)); | 287 NetworkQualityEstimator::Observation( |
| 288 i, very_old, |
| 289 NetworkQualityEstimator::OBSERVATION_SOURCE_URL_REQUEST)); |
282 } | 290 } |
283 | 291 |
284 // Next 50 (i.e., from 51 to 100) have recent timestamp. | 292 // Next 50 (i.e., from 51 to 100) have recent timestamp. |
285 for (int i = 51; i <= 100; ++i) { | 293 for (int i = 51; i <= 100; ++i) { |
286 estimator.downstream_throughput_kbps_observations_.AddObservation( | 294 estimator.downstream_throughput_kbps_observations_.AddObservation( |
287 NetworkQualityEstimator::Observation(i, now)); | 295 NetworkQualityEstimator::Observation( |
| 296 i, now, NetworkQualityEstimator::OBSERVATION_SOURCE_URL_REQUEST)); |
288 estimator.rtt_msec_observations_.AddObservation( | 297 estimator.rtt_msec_observations_.AddObservation( |
289 NetworkQualityEstimator::Observation(i, now)); | 298 NetworkQualityEstimator::Observation( |
| 299 i, now, NetworkQualityEstimator::OBSERVATION_SOURCE_URL_REQUEST)); |
290 } | 300 } |
291 | 301 |
292 // Older samples have very little weight. So, all percentiles are >= 51 | 302 // Older samples have very little weight. So, all percentiles are >= 51 |
293 // (lowest value among recent observations). | 303 // (lowest value among recent observations). |
294 for (int i = 1; i < 100; ++i) { | 304 for (int i = 1; i < 100; ++i) { |
295 // Checks if the difference between the two integers is less than 1. This is | 305 // Checks if the difference between the two integers is less than 1. This is |
296 // required because computed percentiles may be slightly different from | 306 // required because computed percentiles may be slightly different from |
297 // what is expected due to floating point computation errors and integer | 307 // what is expected due to floating point computation errors and integer |
298 // rounding off errors. | 308 // rounding off errors. |
299 EXPECT_NEAR(estimator.GetDownlinkThroughputKbpsEstimateInternal( | 309 EXPECT_NEAR(estimator.GetDownlinkThroughputKbpsEstimateInternal( |
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
488 // Test if the network estimates are cached when network change notification | 498 // Test if the network estimates are cached when network change notification |
489 // is invoked. | 499 // is invoked. |
490 TEST(NetworkQualityEstimatorTest, TestCaching) { | 500 TEST(NetworkQualityEstimatorTest, TestCaching) { |
491 std::map<std::string, std::string> variation_params; | 501 std::map<std::string, std::string> variation_params; |
492 TestNetworkQualityEstimator estimator(variation_params); | 502 TestNetworkQualityEstimator estimator(variation_params); |
493 size_t expected_cache_size = 0; | 503 size_t expected_cache_size = 0; |
494 EXPECT_EQ(expected_cache_size, estimator.cached_network_qualities_.size()); | 504 EXPECT_EQ(expected_cache_size, estimator.cached_network_qualities_.size()); |
495 | 505 |
496 // Cache entry will not be added for (NONE, ""). | 506 // Cache entry will not be added for (NONE, ""). |
497 estimator.downstream_throughput_kbps_observations_.AddObservation( | 507 estimator.downstream_throughput_kbps_observations_.AddObservation( |
498 NetworkQualityEstimator::Observation(1, base::TimeTicks::Now())); | 508 NetworkQualityEstimator::Observation( |
| 509 1, base::TimeTicks::Now(), |
| 510 NetworkQualityEstimator::OBSERVATION_SOURCE_URL_REQUEST)); |
499 estimator.rtt_msec_observations_.AddObservation( | 511 estimator.rtt_msec_observations_.AddObservation( |
500 NetworkQualityEstimator::Observation(1000, base::TimeTicks::Now())); | 512 NetworkQualityEstimator::Observation( |
| 513 1000, base::TimeTicks::Now(), |
| 514 NetworkQualityEstimator::OBSERVATION_SOURCE_URL_REQUEST)); |
501 estimator.SimulateNetworkChangeTo( | 515 estimator.SimulateNetworkChangeTo( |
502 NetworkChangeNotifier::ConnectionType::CONNECTION_2G, "test-1"); | 516 NetworkChangeNotifier::ConnectionType::CONNECTION_2G, "test-1"); |
503 EXPECT_EQ(expected_cache_size, estimator.cached_network_qualities_.size()); | 517 EXPECT_EQ(expected_cache_size, estimator.cached_network_qualities_.size()); |
504 | 518 |
505 // Entry will be added for (2G, "test1"). | 519 // Entry will be added for (2G, "test1"). |
506 // Also, set the network quality for (2G, "test1") so that it is stored in | 520 // Also, set the network quality for (2G, "test1") so that it is stored in |
507 // the cache. | 521 // the cache. |
508 estimator.downstream_throughput_kbps_observations_.AddObservation( | 522 estimator.downstream_throughput_kbps_observations_.AddObservation( |
509 NetworkQualityEstimator::Observation(1, base::TimeTicks::Now())); | 523 NetworkQualityEstimator::Observation( |
| 524 1, base::TimeTicks::Now(), |
| 525 NetworkQualityEstimator::OBSERVATION_SOURCE_URL_REQUEST)); |
510 estimator.rtt_msec_observations_.AddObservation( | 526 estimator.rtt_msec_observations_.AddObservation( |
511 NetworkQualityEstimator::Observation(1000, base::TimeTicks::Now())); | 527 NetworkQualityEstimator::Observation( |
| 528 1000, base::TimeTicks::Now(), |
| 529 NetworkQualityEstimator::OBSERVATION_SOURCE_URL_REQUEST)); |
512 | 530 |
513 estimator.SimulateNetworkChangeTo( | 531 estimator.SimulateNetworkChangeTo( |
514 NetworkChangeNotifier::ConnectionType::CONNECTION_3G, "test-1"); | 532 NetworkChangeNotifier::ConnectionType::CONNECTION_3G, "test-1"); |
515 ++expected_cache_size; | 533 ++expected_cache_size; |
516 EXPECT_EQ(expected_cache_size, estimator.cached_network_qualities_.size()); | 534 EXPECT_EQ(expected_cache_size, estimator.cached_network_qualities_.size()); |
517 | 535 |
518 // Entry will be added for (3G, "test1"). | 536 // Entry will be added for (3G, "test1"). |
519 // Also, set the network quality for (3G, "test1") so that it is stored in | 537 // Also, set the network quality for (3G, "test1") so that it is stored in |
520 // the cache. | 538 // the cache. |
521 estimator.downstream_throughput_kbps_observations_.AddObservation( | 539 estimator.downstream_throughput_kbps_observations_.AddObservation( |
522 NetworkQualityEstimator::Observation(2, base::TimeTicks::Now())); | 540 NetworkQualityEstimator::Observation( |
| 541 2, base::TimeTicks::Now(), |
| 542 NetworkQualityEstimator::OBSERVATION_SOURCE_URL_REQUEST)); |
523 estimator.rtt_msec_observations_.AddObservation( | 543 estimator.rtt_msec_observations_.AddObservation( |
524 NetworkQualityEstimator::Observation(500, base::TimeTicks::Now())); | 544 NetworkQualityEstimator::Observation( |
| 545 500, base::TimeTicks::Now(), |
| 546 NetworkQualityEstimator::OBSERVATION_SOURCE_URL_REQUEST)); |
525 estimator.SimulateNetworkChangeTo( | 547 estimator.SimulateNetworkChangeTo( |
526 NetworkChangeNotifier::ConnectionType::CONNECTION_3G, "test-2"); | 548 NetworkChangeNotifier::ConnectionType::CONNECTION_3G, "test-2"); |
527 ++expected_cache_size; | 549 ++expected_cache_size; |
528 EXPECT_EQ(expected_cache_size, estimator.cached_network_qualities_.size()); | 550 EXPECT_EQ(expected_cache_size, estimator.cached_network_qualities_.size()); |
529 | 551 |
530 // Entry will not be added for (3G, "test2"). | 552 // Entry will not be added for (3G, "test2"). |
531 estimator.SimulateNetworkChangeTo( | 553 estimator.SimulateNetworkChangeTo( |
532 NetworkChangeNotifier::ConnectionType::CONNECTION_2G, "test-1"); | 554 NetworkChangeNotifier::ConnectionType::CONNECTION_2G, "test-1"); |
533 EXPECT_EQ(expected_cache_size, estimator.cached_network_qualities_.size()); | 555 EXPECT_EQ(expected_cache_size, estimator.cached_network_qualities_.size()); |
534 | 556 |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
578 std::string()); | 600 std::string()); |
579 EXPECT_EQ(0U, estimator.cached_network_qualities_.size()); | 601 EXPECT_EQ(0U, estimator.cached_network_qualities_.size()); |
580 | 602 |
581 // Add 100 more networks than the maximum size of the cache. | 603 // Add 100 more networks than the maximum size of the cache. |
582 size_t network_count = | 604 size_t network_count = |
583 NetworkQualityEstimator::kMaximumNetworkQualityCacheSize + 100; | 605 NetworkQualityEstimator::kMaximumNetworkQualityCacheSize + 100; |
584 | 606 |
585 base::TimeTicks update_time_of_network_100; | 607 base::TimeTicks update_time_of_network_100; |
586 for (size_t i = 0; i < network_count; ++i) { | 608 for (size_t i = 0; i < network_count; ++i) { |
587 estimator.downstream_throughput_kbps_observations_.AddObservation( | 609 estimator.downstream_throughput_kbps_observations_.AddObservation( |
588 NetworkQualityEstimator::Observation(2, base::TimeTicks::Now())); | 610 NetworkQualityEstimator::Observation( |
| 611 2, base::TimeTicks::Now(), |
| 612 NetworkQualityEstimator::OBSERVATION_SOURCE_URL_REQUEST)); |
589 estimator.rtt_msec_observations_.AddObservation( | 613 estimator.rtt_msec_observations_.AddObservation( |
590 NetworkQualityEstimator::Observation(500, base::TimeTicks::Now())); | 614 NetworkQualityEstimator::Observation( |
| 615 500, base::TimeTicks::Now(), |
| 616 NetworkQualityEstimator::OBSERVATION_SOURCE_URL_REQUEST)); |
591 | 617 |
592 if (i == 100) | 618 if (i == 100) |
593 update_time_of_network_100 = base::TimeTicks::Now(); | 619 update_time_of_network_100 = base::TimeTicks::Now(); |
594 | 620 |
595 estimator.SimulateNetworkChangeTo( | 621 estimator.SimulateNetworkChangeTo( |
596 net::NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI, | 622 net::NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI, |
597 base::IntToString(i)); | 623 base::IntToString(i)); |
598 if (i < NetworkQualityEstimator::kMaximumNetworkQualityCacheSize) | 624 if (i < NetworkQualityEstimator::kMaximumNetworkQualityCacheSize) |
599 EXPECT_EQ(i, estimator.cached_network_qualities_.size()); | 625 EXPECT_EQ(i, estimator.cached_network_qualities_.size()); |
600 EXPECT_LE(estimator.cached_network_qualities_.size(), | 626 EXPECT_LE(estimator.cached_network_qualities_.size(), |
601 static_cast<size_t>( | 627 static_cast<size_t>( |
602 NetworkQualityEstimator::kMaximumNetworkQualityCacheSize)); | 628 NetworkQualityEstimator::kMaximumNetworkQualityCacheSize)); |
603 } | 629 } |
604 // One more call so that the last network is also written to cache. | 630 // One more call so that the last network is also written to cache. |
605 estimator.downstream_throughput_kbps_observations_.AddObservation( | 631 estimator.downstream_throughput_kbps_observations_.AddObservation( |
606 NetworkQualityEstimator::Observation(2, base::TimeTicks::Now())); | 632 NetworkQualityEstimator::Observation( |
| 633 2, base::TimeTicks::Now(), |
| 634 NetworkQualityEstimator::OBSERVATION_SOURCE_URL_REQUEST)); |
607 estimator.rtt_msec_observations_.AddObservation( | 635 estimator.rtt_msec_observations_.AddObservation( |
608 NetworkQualityEstimator::Observation(500, base::TimeTicks::Now())); | 636 NetworkQualityEstimator::Observation( |
| 637 500, base::TimeTicks::Now(), |
| 638 NetworkQualityEstimator::OBSERVATION_SOURCE_URL_REQUEST)); |
609 estimator.SimulateNetworkChangeTo( | 639 estimator.SimulateNetworkChangeTo( |
610 net::NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI, | 640 net::NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI, |
611 base::IntToString(network_count - 1)); | 641 base::IntToString(network_count - 1)); |
612 EXPECT_EQ(static_cast<size_t>( | 642 EXPECT_EQ(static_cast<size_t>( |
613 NetworkQualityEstimator::kMaximumNetworkQualityCacheSize), | 643 NetworkQualityEstimator::kMaximumNetworkQualityCacheSize), |
614 estimator.cached_network_qualities_.size()); | 644 estimator.cached_network_qualities_.size()); |
615 | 645 |
616 // Test that the cache is LRU by examining its contents. Networks in cache | 646 // Test that the cache is LRU by examining its contents. Networks in cache |
617 // must all be newer than the 100th network. | 647 // must all be newer than the 100th network. |
618 for (NetworkQualityEstimator::CachedNetworkQualities::iterator it = | 648 for (NetworkQualityEstimator::CachedNetworkQualities::iterator it = |
619 estimator.cached_network_qualities_.begin(); | 649 estimator.cached_network_qualities_.begin(); |
620 it != estimator.cached_network_qualities_.end(); ++it) { | 650 it != estimator.cached_network_qualities_.end(); ++it) { |
621 EXPECT_GE((it->second).last_update_time_, update_time_of_network_100); | 651 EXPECT_GE((it->second).last_update_time_, update_time_of_network_100); |
622 } | 652 } |
623 } | 653 } |
624 | 654 |
625 TEST(NetworkQualityEstimatorTest, TestGetMedianRTTSince) { | 655 TEST(NetworkQualityEstimatorTest, TestGetMedianRTTSince) { |
626 std::map<std::string, std::string> variation_params; | 656 std::map<std::string, std::string> variation_params; |
627 TestNetworkQualityEstimator estimator(variation_params); | 657 TestNetworkQualityEstimator estimator(variation_params); |
628 base::TimeTicks now = base::TimeTicks::Now(); | 658 base::TimeTicks now = base::TimeTicks::Now(); |
629 base::TimeTicks old = | 659 base::TimeTicks old = |
630 base::TimeTicks::Now() - base::TimeDelta::FromMilliseconds(1); | 660 base::TimeTicks::Now() - base::TimeDelta::FromMilliseconds(1); |
631 | 661 |
632 // First sample has very old timestamp. | 662 // First sample has very old timestamp. |
633 estimator.downstream_throughput_kbps_observations_.AddObservation( | 663 estimator.downstream_throughput_kbps_observations_.AddObservation( |
634 NetworkQualityEstimator::Observation(1, old)); | 664 NetworkQualityEstimator::Observation( |
| 665 1, old, NetworkQualityEstimator::OBSERVATION_SOURCE_URL_REQUEST)); |
635 estimator.rtt_msec_observations_.AddObservation( | 666 estimator.rtt_msec_observations_.AddObservation( |
636 NetworkQualityEstimator::Observation(1, old)); | 667 NetworkQualityEstimator::Observation( |
| 668 1, old, NetworkQualityEstimator::OBSERVATION_SOURCE_URL_REQUEST)); |
637 | 669 |
638 estimator.downstream_throughput_kbps_observations_.AddObservation( | 670 estimator.downstream_throughput_kbps_observations_.AddObservation( |
639 NetworkQualityEstimator::Observation(100, now)); | 671 NetworkQualityEstimator::Observation( |
| 672 100, now, NetworkQualityEstimator::OBSERVATION_SOURCE_URL_REQUEST)); |
640 estimator.rtt_msec_observations_.AddObservation( | 673 estimator.rtt_msec_observations_.AddObservation( |
641 NetworkQualityEstimator::Observation(100, now)); | 674 NetworkQualityEstimator::Observation( |
| 675 100, now, NetworkQualityEstimator::OBSERVATION_SOURCE_URL_REQUEST)); |
642 | 676 |
643 base::TimeDelta rtt; | 677 base::TimeDelta rtt; |
644 EXPECT_FALSE(estimator.GetRecentMedianRTT( | 678 EXPECT_FALSE(estimator.GetRecentMedianRTT( |
645 now + base::TimeDelta::FromSeconds(10), &rtt)); | 679 now + base::TimeDelta::FromSeconds(10), &rtt)); |
646 EXPECT_TRUE(estimator.GetRecentMedianRTT(now, &rtt)); | 680 EXPECT_TRUE(estimator.GetRecentMedianRTT(now, &rtt)); |
647 EXPECT_EQ(100, rtt.InMilliseconds()); | 681 EXPECT_EQ(100, rtt.InMilliseconds()); |
648 | 682 |
649 int32_t downstream_throughput_kbps; | 683 int32_t downstream_throughput_kbps; |
650 EXPECT_FALSE(estimator.GetRecentMedianDownlinkThroughputKbps( | 684 EXPECT_FALSE(estimator.GetRecentMedianDownlinkThroughputKbps( |
651 now + base::TimeDelta::FromSeconds(10), &downstream_throughput_kbps)); | 685 now + base::TimeDelta::FromSeconds(10), &downstream_throughput_kbps)); |
652 EXPECT_TRUE(estimator.GetRecentMedianDownlinkThroughputKbps( | 686 EXPECT_TRUE(estimator.GetRecentMedianDownlinkThroughputKbps( |
653 now, &downstream_throughput_kbps)); | 687 now, &downstream_throughput_kbps)); |
654 EXPECT_EQ(100, downstream_throughput_kbps); | 688 EXPECT_EQ(100, downstream_throughput_kbps); |
655 } | 689 } |
656 | 690 |
657 } // namespace net | 691 } // namespace net |
OLD | NEW |