Add counting of PCs with private IP addresses exposed

Bug: chromium:718508
Change-Id: I37f166808297c565cbb4b4393a23f7a18ab2862d
Reviewed-on: https://webrtc-review.googlesource.com/88640
Reviewed-by: Henrik Boström <hbos@webrtc.org>
Commit-Queue: Harald Alvestrand <hta@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#23990}
diff --git a/pc/peerconnection.cc b/pc/peerconnection.cc
index a137f05..4d6244a 100644
--- a/pc/peerconnection.cc
+++ b/pc/peerconnection.cc
@@ -3525,6 +3525,10 @@
     return;
   }
   NoteUsageEvent(UsageEvent::CANDIDATE_COLLECTED);
+  if (candidate->candidate().type() == LOCAL_PORT_TYPE &&
+      candidate->candidate().address().IsPrivateIP()) {
+    NoteUsageEvent(UsageEvent::PRIVATE_CANDIDATE_COLLECTED);
+  }
   observer_->OnIceCandidate(candidate.get());
 }
 
diff --git a/pc/peerconnection.h b/pc/peerconnection.h
index 33abbc7..0efe8b5 100644
--- a/pc/peerconnection.h
+++ b/pc/peerconnection.h
@@ -67,7 +67,8 @@
     REMOTE_CANDIDATE_ADDED = 0x100,
     ICE_STATE_CONNECTED = 0x200,
     CLOSE_CALLED = 0x400,
-    MAX_VALUE = 0x800,
+    PRIVATE_CANDIDATE_COLLECTED = 0x800,
+    MAX_VALUE = 0x1000,
   };
 
   explicit PeerConnection(PeerConnectionFactory* factory,
diff --git a/pc/peerconnection_histogram_unittest.cc b/pc/peerconnection_histogram_unittest.cc
index 049d4c5..0067cd6 100644
--- a/pc/peerconnection_histogram_unittest.cc
+++ b/pc/peerconnection_histogram_unittest.cc
@@ -14,12 +14,14 @@
 #include "api/jsep.h"
 #include "api/peerconnectionproxy.h"
 #include "media/base/fakemediaengine.h"
+#include "p2p/client/basicportallocator.h"
 #include "pc/mediasession.h"
 #include "pc/peerconnection.h"
 #include "pc/peerconnectionfactory.h"
 #include "pc/peerconnectionwrapper.h"
 #include "pc/sdputils.h"
 #include "pc/test/fakesctptransport.h"
+#include "rtc_base/fakenetwork.h"
 #include "rtc_base/gunit.h"
 #include "rtc_base/virtualsocketserver.h"
 #include "system_wrappers/include/metrics_default.h"
@@ -31,6 +33,8 @@
 using ::testing::Values;
 
 static constexpr int kDefaultTimeout = 10000;
+static const rtc::SocketAddress kDefaultLocalAddress("1.1.1.1", 0);
+static const rtc::SocketAddress kPrivateLocalAddress("10.1.1.1", 0);
 
 int MakeUsageFingerprint(std::set<PeerConnection::UsageEvent> events) {
   int signature = 0;
@@ -74,7 +78,6 @@
   void PrepareToExchangeCandidates(RawWrapperPtr other) {
     candidate_target_ = other;
   }
-
   bool HaveDataChannel() { return last_datachannel_; }
 
  private:
@@ -122,22 +125,41 @@
       buffered_candidates_.push_back(std::move(candidate_copy));
     }
   }
+
   void AddBufferedIceCandidates() {
     for (const auto& candidate : buffered_candidates_) {
       EXPECT_TRUE(pc()->AddIceCandidate(candidate.get()));
     }
     buffered_candidates_.clear();
   }
+
   bool ConnectTo(PeerConnectionWrapperForUsageHistogramTest* callee) {
     PrepareToExchangeCandidates(callee);
-    EXPECT_TRUE(ExchangeOfferAnswerWith(callee));
+    if (!ExchangeOfferAnswerWith(callee)) {
+      return false;
+    }
     AddBufferedIceCandidates();
     callee->AddBufferedIceCandidates();
-    EXPECT_TRUE_WAIT(IsConnected(), kDefaultTimeout);
-    EXPECT_TRUE_WAIT(callee->IsConnected(), kDefaultTimeout);
+    WAIT(IsConnected(), kDefaultTimeout);
+    WAIT(callee->IsConnected(), kDefaultTimeout);
     return IsConnected() && callee->IsConnected();
   }
 
+  bool GenerateOfferAndCollectCandidates() {
+    auto offer = CreateOffer(RTCOfferAnswerOptions());
+    if (!offer) {
+      return false;
+    }
+    bool set_local_offer =
+        SetLocalDescription(CloneSessionDescription(offer.get()));
+    EXPECT_TRUE(set_local_offer);
+    if (!set_local_offer) {
+      return false;
+    }
+    EXPECT_TRUE_WAIT(observer()->ice_gathering_complete_, kDefaultTimeout);
+    return true;
+  }
+
  private:
   // Candidates that have been sent but not yet configured
   std::vector<std::unique_ptr<webrtc::IceCandidateInterface>>
@@ -148,9 +170,8 @@
     const webrtc::IceCandidateInterface* candidate) {
   if (candidate_target_) {
     this->candidate_target_->AddOrBufferIceCandidate(candidate);
-  } else {
-    FAIL() << "Early candidate detected";
   }
+  // If target is not set, ignore. This happens in one-ended unit tests.
 }
 
 class PeerConnectionUsageHistogramTest : public ::testing::Test {
@@ -164,23 +185,37 @@
   }
 
   WrapperPtr CreatePeerConnection() {
-    return CreatePeerConnection(
-        RTCConfiguration(), PeerConnectionFactoryInterface::Options(), false);
+    return CreatePeerConnection(RTCConfiguration(),
+                                PeerConnectionFactoryInterface::Options(),
+                                nullptr, false);
   }
 
   WrapperPtr CreatePeerConnection(const RTCConfiguration& config) {
     return CreatePeerConnection(
-        config, PeerConnectionFactoryInterface::Options(), false);
+        config, PeerConnectionFactoryInterface::Options(), nullptr, false);
   }
 
   WrapperPtr CreatePeerConnectionWithImmediateReport() {
-    return CreatePeerConnection(
-        RTCConfiguration(), PeerConnectionFactoryInterface::Options(), true);
+    return CreatePeerConnection(RTCConfiguration(),
+                                PeerConnectionFactoryInterface::Options(),
+                                nullptr, true);
+  }
+
+  WrapperPtr CreatePeerConnectionWithPrivateLocalAddresses() {
+    fake_network_manager_.reset(new rtc::FakeNetworkManager());
+    fake_network_manager_->AddInterface(kDefaultLocalAddress);
+    fake_network_manager_->AddInterface(kPrivateLocalAddress);
+    std::unique_ptr<cricket::BasicPortAllocator> port_allocator(
+        new cricket::BasicPortAllocator(fake_network_manager_.get()));
+    return CreatePeerConnection(RTCConfiguration(),
+                                PeerConnectionFactoryInterface::Options(),
+                                std::move(port_allocator), false);
   }
 
   WrapperPtr CreatePeerConnection(
       const RTCConfiguration& config,
       const PeerConnectionFactoryInterface::Options factory_options,
+      std::unique_ptr<cricket::PortAllocator> allocator,
       bool immediate_report) {
     rtc::scoped_refptr<PeerConnectionFactoryForUsageHistogramTest> pc_factory(
         new PeerConnectionFactoryForUsageHistogramTest());
@@ -190,8 +225,8 @@
       pc_factory->ReturnHistogramVeryQuickly();
     }
     auto observer = absl::make_unique<ObserverForUsageHistogramTest>();
-    auto pc = pc_factory->CreatePeerConnection(config, nullptr, nullptr,
-                                               observer.get());
+    auto pc = pc_factory->CreatePeerConnection(config, std::move(allocator),
+                                               nullptr, observer.get());
     if (!pc) {
       return nullptr;
     }
@@ -202,6 +237,7 @@
     return wrapper;
   }
 
+  std::unique_ptr<rtc::FakeNetworkManager> fake_network_manager_;
   std::unique_ptr<rtc::VirtualSocketServer> vss_;
   rtc::AutoSocketServerThread main_;
 };
@@ -239,6 +275,46 @@
        PeerConnection::UsageEvent::REMOTE_CANDIDATE_ADDED,
        PeerConnection::UsageEvent::ICE_STATE_CONNECTED,
        PeerConnection::UsageEvent::CLOSE_CALLED});
+  // In this case, we may or may not have PRIVATE_CANDIDATE_COLLECTED,
+  // depending on the machine configuration.
+  EXPECT_EQ(2,
+            webrtc::metrics::NumSamples("WebRTC.PeerConnection.UsagePattern"));
+  EXPECT_TRUE(
+      webrtc::metrics::NumEvents("WebRTC.PeerConnection.UsagePattern",
+                                 expected_fingerprint) == 2 ||
+      webrtc::metrics::NumEvents(
+          "WebRTC.PeerConnection.UsagePattern",
+          expected_fingerprint |
+              static_cast<int>(
+                  PeerConnection::UsageEvent::PRIVATE_CANDIDATE_COLLECTED)) ==
+          2);
+}
+
+// Test getting the usage fingerprint when there are no host candidates.
+TEST_F(PeerConnectionUsageHistogramTest, FingerprintWithNoHostCandidates) {
+  RTCConfiguration config;
+  config.type = PeerConnectionInterface::kNoHost;
+  auto caller = CreatePeerConnection(config);
+  auto callee = CreatePeerConnection(config);
+  caller->AddAudioTrack("audio");
+  caller->AddVideoTrack("video");
+  // Under some bot configurations, this will fail - presumably bots where
+  // no working non-host addresses exist.
+  if (!caller->ConnectTo(callee.get())) {
+    return;
+  }
+  // If we manage to connect, we should get this precise fingerprint.
+  caller->pc()->Close();
+  callee->pc()->Close();
+  int expected_fingerprint = MakeUsageFingerprint(
+      {PeerConnection::UsageEvent::AUDIO_ADDED,
+       PeerConnection::UsageEvent::VIDEO_ADDED,
+       PeerConnection::UsageEvent::SET_LOCAL_DESCRIPTION_CALLED,
+       PeerConnection::UsageEvent::SET_REMOTE_DESCRIPTION_CALLED,
+       PeerConnection::UsageEvent::CANDIDATE_COLLECTED,
+       PeerConnection::UsageEvent::REMOTE_CANDIDATE_ADDED,
+       PeerConnection::UsageEvent::ICE_STATE_CONNECTED,
+       PeerConnection::UsageEvent::CLOSE_CALLED});
   EXPECT_EQ(2,
             webrtc::metrics::NumSamples("WebRTC.PeerConnection.UsagePattern"));
   EXPECT_EQ(2, webrtc::metrics::NumEvents("WebRTC.PeerConnection.UsagePattern",
@@ -264,8 +340,15 @@
        PeerConnection::UsageEvent::CLOSE_CALLED});
   EXPECT_EQ(2,
             webrtc::metrics::NumSamples("WebRTC.PeerConnection.UsagePattern"));
-  EXPECT_EQ(2, webrtc::metrics::NumEvents("WebRTC.PeerConnection.UsagePattern",
-                                          expected_fingerprint));
+  EXPECT_TRUE(
+      webrtc::metrics::NumEvents("WebRTC.PeerConnection.UsagePattern",
+                                 expected_fingerprint) == 2 ||
+      webrtc::metrics::NumEvents(
+          "WebRTC.PeerConnection.UsagePattern",
+          expected_fingerprint |
+              static_cast<int>(
+                  PeerConnection::UsageEvent::PRIVATE_CANDIDATE_COLLECTED)) ==
+          2);
 }
 #endif  // HAVE_SCTP
 #endif  // WEBRTC_ANDROID
@@ -317,4 +400,21 @@
                                           expected_fingerprint));
 }
 
+TEST_F(PeerConnectionUsageHistogramTest, FingerprintWithPrivateIP) {
+  auto caller = CreatePeerConnectionWithPrivateLocalAddresses();
+  caller->AddAudioTrack("audio");
+  ASSERT_TRUE(caller->GenerateOfferAndCollectCandidates());
+  caller->pc()->Close();
+  int expected_fingerprint = MakeUsageFingerprint(
+      {PeerConnection::UsageEvent::AUDIO_ADDED,
+       PeerConnection::UsageEvent::SET_LOCAL_DESCRIPTION_CALLED,
+       PeerConnection::UsageEvent::CANDIDATE_COLLECTED,
+       PeerConnection::UsageEvent::CLOSE_CALLED,
+       PeerConnection::UsageEvent::PRIVATE_CANDIDATE_COLLECTED});
+  EXPECT_EQ(1,
+            webrtc::metrics::NumSamples("WebRTC.PeerConnection.UsagePattern"));
+  EXPECT_EQ(1, webrtc::metrics::NumEvents("WebRTC.PeerConnection.UsagePattern",
+                                          expected_fingerprint));
+}
+
 }  // namespace webrtc