diff --git a/api/candidate.h b/api/candidate.h index ecfdee3fcb..b8aaebc14a 100644 --- a/api/candidate.h +++ b/api/candidate.h @@ -109,6 +109,13 @@ class RTC_EXPORT Candidate { network_type_ = network_type; } + rtc::AdapterType underlying_type_for_vpn() const { + return underlying_type_for_vpn_; + } + void set_underlying_type_for_vpn(rtc::AdapterType network_type) { + underlying_type_for_vpn_ = network_type; + } + // Candidates in a new generation replace those in the old generation. uint32_t generation() const { return generation_; } void set_generation(uint32_t generation) { generation_ = generation; } @@ -195,6 +202,7 @@ class RTC_EXPORT Candidate { std::string type_; std::string network_name_; rtc::AdapterType network_type_; + rtc::AdapterType underlying_type_for_vpn_; uint32_t generation_; std::string foundation_; rtc::SocketAddress related_address_; diff --git a/api/stats/rtcstats_objects.h b/api/stats/rtcstats_objects.h index f38d962e15..ccaf095e3d 100644 --- a/api/stats/rtcstats_objects.h +++ b/api/stats/rtcstats_objects.h @@ -106,6 +106,20 @@ class RTC_EXPORT RTCCertificateStats final : public RTCStats { RTCStatsMember issuer_certificate_id; }; +// Non standard extension mapping to rtc::AdapterType +struct RTCNetworkAdapterType { + static constexpr char kUnknown[] = "unknown"; + static constexpr char kEthernet[] = "ethernet"; + static constexpr char kWifi[] = "wifi"; + static constexpr char kCellular[] = "cellular"; + static constexpr char kLoopback[] = "loopback"; + static constexpr char kAny[] = "any"; + static constexpr char kCellular2g[] = "cellular2g"; + static constexpr char kCellular3g[] = "cellular3g"; + static constexpr char kCellular4g[] = "cellular4g"; + static constexpr char kCellular5g[] = "cellular5g"; +}; + // https://w3c.github.io/webrtc-stats/#codec-dict* class RTC_EXPORT RTCCodecStats final : public RTCStats { public: @@ -227,6 +241,9 @@ class RTC_EXPORT RTCIceCandidateStats : public RTCStats { RTCStatsMember priority; RTCStatsMember url; + RTCNonStandardStatsMember vpn; + RTCNonStandardStatsMember network_adapter_type; + protected: RTCIceCandidateStats(const std::string& id, int64_t timestamp_us, diff --git a/p2p/base/port.cc b/p2p/base/port.cc index c616658fba..5d3552b7f6 100644 --- a/p2p/base/port.cc +++ b/p2p/base/port.cc @@ -276,6 +276,7 @@ void Port::AddAddress(const rtc::SocketAddress& address, c.set_tcptype(tcptype); c.set_network_name(network_->name()); c.set_network_type(network_->type()); + c.set_underlying_type_for_vpn(network_->underlying_type_for_vpn()); c.set_url(url); c.set_related_address(related_address); diff --git a/pc/rtc_stats_collector.cc b/pc/rtc_stats_collector.cc index 0ed8c14d51..c965161b0e 100644 --- a/pc/rtc_stats_collector.cc +++ b/pc/rtc_stats_collector.cc @@ -230,7 +230,7 @@ const char* DtlsTransportStateToRTCDtlsTransportState( } } -const char* NetworkAdapterTypeToStatsType(rtc::AdapterType type) { +const char* NetworkTypeToStatsType(rtc::AdapterType type) { switch (type) { case rtc::ADAPTER_TYPE_CELLULAR: case rtc::ADAPTER_TYPE_CELLULAR_2G: @@ -253,6 +253,36 @@ const char* NetworkAdapterTypeToStatsType(rtc::AdapterType type) { return nullptr; } +absl::string_view NetworkTypeToStatsNetworkAdapterType(rtc::AdapterType type) { + switch (type) { + case rtc::ADAPTER_TYPE_CELLULAR: + return RTCNetworkAdapterType::kCellular; + case rtc::ADAPTER_TYPE_CELLULAR_2G: + return RTCNetworkAdapterType::kCellular2g; + case rtc::ADAPTER_TYPE_CELLULAR_3G: + return RTCNetworkAdapterType::kCellular3g; + case rtc::ADAPTER_TYPE_CELLULAR_4G: + return RTCNetworkAdapterType::kCellular4g; + case rtc::ADAPTER_TYPE_CELLULAR_5G: + return RTCNetworkAdapterType::kCellular5g; + case rtc::ADAPTER_TYPE_ETHERNET: + return RTCNetworkAdapterType::kEthernet; + case rtc::ADAPTER_TYPE_WIFI: + return RTCNetworkAdapterType::kWifi; + case rtc::ADAPTER_TYPE_UNKNOWN: + return RTCNetworkAdapterType::kUnknown; + case rtc::ADAPTER_TYPE_LOOPBACK: + return RTCNetworkAdapterType::kLoopback; + case rtc::ADAPTER_TYPE_ANY: + return RTCNetworkAdapterType::kAny; + case rtc::ADAPTER_TYPE_VPN: + /* should not be handled here. Vpn is modelled as a bool */ + break; + } + RTC_DCHECK_NOTREACHED(); + return nullptr; +} + const char* QualityLimitationReasonToRTCQualityLimitationReason( QualityLimitationReason reason) { switch (reason) { @@ -733,7 +763,7 @@ const std::string& ProduceIceCandidateStats(int64_t timestamp_us, candidate_stats->transport_id = transport_id; if (is_local) { candidate_stats->network_type = - NetworkAdapterTypeToStatsType(candidate.network_type()); + NetworkTypeToStatsType(candidate.network_type()); const std::string& candidate_type = candidate.type(); const std::string& relay_protocol = candidate.relay_protocol(); const std::string& url = candidate.url(); @@ -752,6 +782,16 @@ const std::string& ProduceIceCandidateStats(int64_t timestamp_us, candidate_stats->url = url; } } + if (candidate.network_type() == rtc::ADAPTER_TYPE_VPN) { + candidate_stats->vpn = true; + candidate_stats->network_adapter_type = + std::string(NetworkTypeToStatsNetworkAdapterType( + candidate.underlying_type_for_vpn())); + } else { + candidate_stats->vpn = false; + candidate_stats->network_adapter_type = std::string( + NetworkTypeToStatsNetworkAdapterType(candidate.network_type())); + } } else { // We don't expect to know the adapter type of remote candidates. RTC_DCHECK_EQ(rtc::ADAPTER_TYPE_UNKNOWN, candidate.network_type()); diff --git a/pc/rtc_stats_collector_unittest.cc b/pc/rtc_stats_collector_unittest.cc index ec44b4dbe1..1438615ee6 100644 --- a/pc/rtc_stats_collector_unittest.cc +++ b/pc/rtc_stats_collector_unittest.cc @@ -216,11 +216,14 @@ std::unique_ptr CreateFakeCandidate( const std::string& protocol, const rtc::AdapterType adapter_type, const std::string& candidate_type, - uint32_t priority) { + uint32_t priority, + const rtc::AdapterType underlying_type_for_vpn = + rtc::ADAPTER_TYPE_UNKNOWN) { std::unique_ptr candidate(new cricket::Candidate()); candidate->set_address(rtc::SocketAddress(hostname, port)); candidate->set_protocol(protocol); candidate->set_network_type(adapter_type); + candidate->set_underlying_type_for_vpn(underlying_type_for_vpn); candidate->set_type(candidate_type); candidate->set_priority(priority); return candidate; @@ -1256,9 +1259,9 @@ TEST_F(RTCStatsCollectorTest, CollectRTCDataChannelStats) { TEST_F(RTCStatsCollectorTest, CollectRTCIceCandidateStats) { // Candidates in the first transport stats. - std::unique_ptr a_local_host = - CreateFakeCandidate("1.2.3.4", 5, "a_local_host's protocol", - rtc::ADAPTER_TYPE_VPN, cricket::LOCAL_PORT_TYPE, 0); + std::unique_ptr a_local_host = CreateFakeCandidate( + "1.2.3.4", 5, "a_local_host's protocol", rtc::ADAPTER_TYPE_VPN, + cricket::LOCAL_PORT_TYPE, 0, rtc::ADAPTER_TYPE_ETHERNET); RTCLocalIceCandidateStats expected_a_local_host( "RTCIceCandidate_" + a_local_host->id(), 0); expected_a_local_host.transport_id = "RTCTransport_a_0"; @@ -1269,6 +1272,8 @@ TEST_F(RTCStatsCollectorTest, CollectRTCIceCandidateStats) { expected_a_local_host.protocol = "a_local_host's protocol"; expected_a_local_host.candidate_type = "host"; expected_a_local_host.priority = 0; + expected_a_local_host.vpn = true; + expected_a_local_host.network_adapter_type = RTCNetworkAdapterType::kEthernet; std::unique_ptr a_remote_srflx = CreateFakeCandidate( "6.7.8.9", 10, "remote_srflx's protocol", rtc::ADAPTER_TYPE_UNKNOWN, @@ -1284,8 +1289,8 @@ TEST_F(RTCStatsCollectorTest, CollectRTCIceCandidateStats) { expected_a_remote_srflx.priority = 1; std::unique_ptr a_local_prflx = CreateFakeCandidate( - "11.12.13.14", 15, "a_local_prflx's protocol", rtc::ADAPTER_TYPE_CELLULAR, - cricket::PRFLX_PORT_TYPE, 2); + "11.12.13.14", 15, "a_local_prflx's protocol", + rtc::ADAPTER_TYPE_CELLULAR_2G, cricket::PRFLX_PORT_TYPE, 2); RTCLocalIceCandidateStats expected_a_local_prflx( "RTCIceCandidate_" + a_local_prflx->id(), 0); expected_a_local_prflx.transport_id = "RTCTransport_a_0"; @@ -1296,6 +1301,9 @@ TEST_F(RTCStatsCollectorTest, CollectRTCIceCandidateStats) { expected_a_local_prflx.protocol = "a_local_prflx's protocol"; expected_a_local_prflx.candidate_type = "prflx"; expected_a_local_prflx.priority = 2; + expected_a_local_prflx.vpn = false; + expected_a_local_prflx.network_adapter_type = + RTCNetworkAdapterType::kCellular2g; std::unique_ptr a_remote_relay = CreateFakeCandidate( "16.17.18.19", 20, "a_remote_relay's protocol", rtc::ADAPTER_TYPE_UNKNOWN, @@ -1328,6 +1336,8 @@ TEST_F(RTCStatsCollectorTest, CollectRTCIceCandidateStats) { expected_a_local_relay.candidate_type = "relay"; expected_a_local_relay.priority = 1; expected_a_local_relay.url = "turn:url1"; + expected_a_local_relay.vpn = false; + expected_a_local_relay.network_adapter_type = RTCNetworkAdapterType::kUnknown; std::unique_ptr a_local_relay_prflx = CreateFakeCandidate( "11.12.13.20", 22, "a_local_relay_prflx's protocol", @@ -1345,6 +1355,9 @@ TEST_F(RTCStatsCollectorTest, CollectRTCIceCandidateStats) { expected_a_local_relay_prflx.relay_protocol = "udp"; expected_a_local_relay_prflx.candidate_type = "prflx"; expected_a_local_relay_prflx.priority = 1; + expected_a_local_relay_prflx.vpn = false; + expected_a_local_relay_prflx.network_adapter_type = + RTCNetworkAdapterType::kUnknown; // Candidates in the second transport stats. std::unique_ptr b_local = @@ -1360,6 +1373,8 @@ TEST_F(RTCStatsCollectorTest, CollectRTCIceCandidateStats) { expected_b_local.protocol = "b_local's protocol"; expected_b_local.candidate_type = "host"; expected_b_local.priority = 42; + expected_b_local.vpn = false; + expected_b_local.network_adapter_type = RTCNetworkAdapterType::kWifi; std::unique_ptr b_remote = CreateFakeCandidate( "42.42.42.42", 42, "b_remote's protocol", rtc::ADAPTER_TYPE_UNKNOWN, @@ -1594,6 +1609,8 @@ TEST_F(RTCStatsCollectorTest, CollectRTCIceCandidatePairStats) { expected_local_candidate.protocol = "protocol"; expected_local_candidate.candidate_type = "host"; expected_local_candidate.priority = 42; + expected_local_candidate.vpn = false; + expected_local_candidate.network_adapter_type = RTCNetworkAdapterType::kWifi; ASSERT_TRUE(report->Get(expected_local_candidate.id())); EXPECT_EQ(expected_local_candidate, report->Get(expected_local_candidate.id()) diff --git a/pc/rtc_stats_integrationtest.cc b/pc/rtc_stats_integrationtest.cc index be9cd6fbc0..085f0636a4 100644 --- a/pc/rtc_stats_integrationtest.cc +++ b/pc/rtc_stats_integrationtest.cc @@ -521,6 +521,7 @@ class RTCStatsReportVerifier { candidate_pair.consent_requests_sent); verifier.TestMemberIsUndefined(candidate_pair.consent_responses_received); verifier.TestMemberIsUndefined(candidate_pair.consent_responses_sent); + return verifier.ExpectAllMembersSuccessfullyTested(); } @@ -531,8 +532,12 @@ class RTCStatsReportVerifier { verifier.TestMemberIsDefined(candidate.is_remote); if (*candidate.is_remote) { verifier.TestMemberIsUndefined(candidate.network_type); + verifier.TestMemberIsUndefined(candidate.network_adapter_type); + verifier.TestMemberIsUndefined(candidate.vpn); } else { verifier.TestMemberIsDefined(candidate.network_type); + verifier.TestMemberIsDefined(candidate.network_adapter_type); + verifier.TestMemberIsDefined(candidate.vpn); } verifier.TestMemberIsDefined(candidate.ip); verifier.TestMemberIsDefined(candidate.address); diff --git a/stats/rtcstats_objects.cc b/stats/rtcstats_objects.cc index 961d17c7eb..3b962b68ae 100644 --- a/stats/rtcstats_objects.cc +++ b/stats/rtcstats_objects.cc @@ -277,7 +277,9 @@ WEBRTC_RTCSTATS_IMPL(RTCIceCandidateStats, RTCStats, "abstract-ice-candidate", &relay_protocol, &candidate_type, &priority, - &url) + &url, + &vpn, + &network_adapter_type) // clang-format on RTCIceCandidateStats::RTCIceCandidateStats(const std::string& id, @@ -299,7 +301,9 @@ RTCIceCandidateStats::RTCIceCandidateStats(std::string&& id, relay_protocol("relayProtocol"), candidate_type("candidateType"), priority("priority"), - url("url") {} + url("url"), + vpn("vpn"), + network_adapter_type("networkAdapterType") {} RTCIceCandidateStats::RTCIceCandidateStats(const RTCIceCandidateStats& other) : RTCStats(other.id(), other.timestamp_us()), @@ -313,7 +317,9 @@ RTCIceCandidateStats::RTCIceCandidateStats(const RTCIceCandidateStats& other) relay_protocol(other.relay_protocol), candidate_type(other.candidate_type), priority(other.priority), - url(other.url) {} + url(other.url), + vpn(other.vpn), + network_adapter_type(other.network_adapter_type) {} RTCIceCandidateStats::~RTCIceCandidateStats() {}