stats: add dtlsRole to transport

https://w3c.github.io/webrtc-stats/#dom-rtctransportstats-dtlsrole

BUG=webrtc:13978

Change-Id: Ib158427d2df0307884381bdd46c411f60f56a371
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/259761
Reviewed-by: Henrik Boström <hbos@webrtc.org>
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Commit-Queue: Philipp Hancke <philipp.hancke@googlemail.com>
Cr-Commit-Position: refs/heads/main@{#36730}
diff --git a/api/stats/rtcstats_objects.h b/api/stats/rtcstats_objects.h
index bcf606f..a6d78f8 100644
--- a/api/stats/rtcstats_objects.h
+++ b/api/stats/rtcstats_objects.h
@@ -90,6 +90,13 @@
   static const char* const kScreenshare;
 };
 
+// https://w3c.github.io/webrtc-stats/#dom-rtcdtlsrole
+struct RTCDtlsRole {
+  static const char* const kUnknown;
+  static const char* const kClient;
+  static const char* const kServer;
+};
+
 // https://w3c.github.io/webrtc-stats/#certificatestats-dict*
 class RTC_EXPORT RTCCertificateStats final : public RTCStats {
  public:
@@ -689,6 +696,7 @@
   RTCStatsMember<std::string> remote_certificate_id;
   RTCStatsMember<std::string> tls_version;
   RTCStatsMember<std::string> dtls_cipher;
+  RTCStatsMember<std::string> dtls_role;
   RTCStatsMember<std::string> srtp_cipher;
   RTCStatsMember<uint32_t> selected_candidate_pair_changes;
 };
diff --git a/pc/jsep_transport.cc b/pc/jsep_transport.cc
index b6fb189..65dd703 100644
--- a/pc/jsep_transport.cc
+++ b/pc/jsep_transport.cc
@@ -714,6 +714,10 @@
   dtls_transport->GetSrtpCryptoSuite(&substats.srtp_crypto_suite);
   dtls_transport->GetSslCipherSuite(&substats.ssl_cipher_suite);
   substats.dtls_state = dtls_transport->dtls_state();
+  rtc::SSLRole dtls_role;
+  if (dtls_transport->GetDtlsRole(&dtls_role)) {
+    substats.dtls_role = dtls_role;
+  }
   if (!dtls_transport->ice_transport()->GetStats(
           &substats.ice_transport_stats)) {
     return false;
diff --git a/pc/rtc_stats_collector.cc b/pc/rtc_stats_collector.cc
index 0a8f531..5ceeba8 100644
--- a/pc/rtc_stats_collector.cc
+++ b/pc/rtc_stats_collector.cc
@@ -2118,6 +2118,15 @@
         snprintf(bytes, sizeof(bytes), "%04X", channel_stats.ssl_version_bytes);
         transport_stats->tls_version = bytes;
       }
+
+      if (channel_stats.dtls_role) {
+        transport_stats->dtls_role = *channel_stats.dtls_role == rtc::SSL_CLIENT
+                                         ? webrtc::RTCDtlsRole::kClient
+                                         : webrtc::RTCDtlsRole::kServer;
+      } else {
+        transport_stats->dtls_role = webrtc::RTCDtlsRole::kUnknown;
+      }
+
       if (channel_stats.ssl_cipher_suite != rtc::kTlsNullWithNullNull &&
           rtc::SSLStreamAdapter::SslCipherSuiteToName(
               channel_stats.ssl_cipher_suite)
diff --git a/pc/rtc_stats_collector_unittest.cc b/pc/rtc_stats_collector_unittest.cc
index 82de9f0..942d308 100644
--- a/pc/rtc_stats_collector_unittest.cc
+++ b/pc/rtc_stats_collector_unittest.cc
@@ -2460,6 +2460,7 @@
   expected_rtp_transport.bytes_received = 1337;
   expected_rtp_transport.packets_received = 4;
   expected_rtp_transport.dtls_state = RTCDtlsTransportState::kNew;
+  expected_rtp_transport.dtls_role = RTCDtlsRole::kUnknown;
   expected_rtp_transport.selected_candidate_pair_changes = 1;
 
   ASSERT_TRUE(report->Get(expected_rtp_transport.id()));
@@ -2501,6 +2502,7 @@
   expected_rtcp_transport.bytes_received = 42;
   expected_rtcp_transport.packets_received = 4;
   expected_rtcp_transport.dtls_state = RTCDtlsTransportState::kConnecting;
+  expected_rtcp_transport.dtls_role = RTCDtlsRole::kUnknown;
   expected_rtcp_transport.selected_candidate_pair_changes = 0;
 
   expected_rtp_transport.rtcp_transport_stats_id = expected_rtcp_transport.id();
@@ -2600,6 +2602,7 @@
   rtp_transport_channel_stats.ice_transport_stats
       .selected_candidate_pair_changes = 1;
   rtp_transport_channel_stats.ssl_version_bytes = 0x0203;
+  rtp_transport_channel_stats.dtls_role = rtc::SSL_CLIENT;
   // 0x2F is TLS_RSA_WITH_AES_128_CBC_SHA according to IANA
   rtp_transport_channel_stats.ssl_cipher_suite = 0x2F;
   rtp_transport_channel_stats.srtp_crypto_suite = rtc::kSrtpAes128CmSha1_80;
@@ -2620,6 +2623,7 @@
   expected_rtp_transport.packets_received = 0;
   // Crypto parameters
   expected_rtp_transport.tls_version = "0203";
+  expected_rtp_transport.dtls_role = RTCDtlsRole::kClient;
   expected_rtp_transport.dtls_cipher = "TLS_RSA_WITH_AES_128_CBC_SHA";
   expected_rtp_transport.srtp_cipher = "AES_CM_128_HMAC_SHA1_80";
 
diff --git a/pc/rtc_stats_integrationtest.cc b/pc/rtc_stats_integrationtest.cc
index 956f414..07a8bdc 100644
--- a/pc/rtc_stats_integrationtest.cc
+++ b/pc/rtc_stats_integrationtest.cc
@@ -1136,6 +1136,7 @@
                                      RTCCertificateStats::kType);
     verifier.TestMemberIsDefined(transport.tls_version);
     verifier.TestMemberIsDefined(transport.dtls_cipher);
+    verifier.TestMemberIsDefined(transport.dtls_role);
     verifier.TestMemberIsDefined(transport.srtp_cipher);
     verifier.TestMemberIsPositive<uint32_t>(
         transport.selected_candidate_pair_changes);
diff --git a/pc/transport_stats.h b/pc/transport_stats.h
index 2f43d45..e554385 100644
--- a/pc/transport_stats.h
+++ b/pc/transport_stats.h
@@ -31,6 +31,7 @@
   int ssl_version_bytes = 0;
   int srtp_crypto_suite = rtc::kSrtpInvalidCryptoSuite;
   int ssl_cipher_suite = rtc::kTlsNullWithNullNull;
+  absl::optional<rtc::SSLRole> dtls_role;
   webrtc::DtlsTransportState dtls_state = webrtc::DtlsTransportState::kNew;
   IceTransportStats ice_transport_stats;
 };
diff --git a/stats/rtcstats_objects.cc b/stats/rtcstats_objects.cc
index 3b962b6..ae90bf3 100644
--- a/stats/rtcstats_objects.cc
+++ b/stats/rtcstats_objects.cc
@@ -62,6 +62,11 @@
 const char* const RTCContentType::kUnspecified = "unspecified";
 const char* const RTCContentType::kScreenshare = "screenshare";
 
+// https://w3c.github.io/webrtc-stats/#dom-rtcdtlsrole
+const char* const RTCDtlsRole::kUnknown = "unknown";
+const char* const RTCDtlsRole::kClient = "client";
+const char* const RTCDtlsRole::kServer = "server";
+
 // clang-format off
 WEBRTC_RTCSTATS_IMPL(RTCCertificateStats, RTCStats, "certificate",
     &fingerprint,
@@ -1082,6 +1087,7 @@
     &remote_certificate_id,
     &tls_version,
     &dtls_cipher,
+    &dtls_role,
     &srtp_cipher,
     &selected_candidate_pair_changes)
 // clang-format on
@@ -1103,6 +1109,7 @@
       remote_certificate_id("remoteCertificateId"),
       tls_version("tlsVersion"),
       dtls_cipher("dtlsCipher"),
+      dtls_role("dtlsRole"),
       srtp_cipher("srtpCipher"),
       selected_candidate_pair_changes("selectedCandidatePairChanges") {}
 
@@ -1119,6 +1126,7 @@
       remote_certificate_id(other.remote_certificate_id),
       tls_version(other.tls_version),
       dtls_cipher(other.dtls_cipher),
+      dtls_role(other.dtls_role),
       srtp_cipher(other.srtp_cipher),
       selected_candidate_pair_changes(other.selected_candidate_pair_changes) {}