Expose negotiated ciphers through stats API.

Use the new internal API to expose the negotiated SRTP/SSL ciphers
through the stats API.
This is a follow-up to https://webrtc-codereview.appspot.com/37209004.

BUG=3976
R=juberti@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/35169004

Cr-Commit-Position: refs/heads/master@{#8584}
git-svn-id: http://webrtc.googlecode.com/svn/trunk@8584 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
pthatcher@webrtc.org 2015-03-04 01:38:30 +00:00
parent be77872d2c
commit 7bea1ffe77
6 changed files with 140 additions and 6 deletions

View File

@ -102,6 +102,15 @@ static const char kVideoTrackLabelBase[] = "video_track";
static const char kAudioTrackLabelBase[] = "audio_track";
static const char kDataChannelLabel[] = "data_channel";
// Disable for TSan v2, see
// https://code.google.com/p/webrtc/issues/detail?id=1205 for details.
// This declaration is also #ifdef'd as it causes unused-variable errors.
#if !defined(THREAD_SANITIZER)
// SRTP cipher name negotiated by the tests. This must be updated if the
// default changes.
static const char kDefaultSrtpCipher[] = "AES_CM_128_HMAC_SHA1_32";
#endif
static void RemoveLinesFromSdp(const std::string& line_start,
std::string* sdp) {
const char kSdpLineEnd[] = "\r\n";
@ -380,6 +389,24 @@ class PeerConnectionTestClientBase
return bw;
}
std::string GetDtlsCipherStats() {
rtc::scoped_refptr<MockStatsObserver>
observer(new rtc::RefCountedObject<MockStatsObserver>());
EXPECT_TRUE(peer_connection_->GetStats(
observer, NULL, PeerConnectionInterface::kStatsOutputLevelStandard));
EXPECT_TRUE_WAIT(observer->called(), kMaxWaitMs);
return observer->DtlsCipher();
}
std::string GetSrtpCipherStats() {
rtc::scoped_refptr<MockStatsObserver>
observer(new rtc::RefCountedObject<MockStatsObserver>());
EXPECT_TRUE(peer_connection_->GetStats(
observer, NULL, PeerConnectionInterface::kStatsOutputLevelStandard));
EXPECT_TRUE_WAIT(observer->called(), kMaxWaitMs);
return observer->SrtpCipher();
}
int rendered_width() {
EXPECT_FALSE(fake_video_renderers_.empty());
return fake_video_renderers_.empty() ? 1 :
@ -1280,6 +1307,22 @@ TEST_F(JsepPeerConnectionP2PTestClient, GetBytesSentStats) {
kMaxWaitForStatsMs);
}
// Test that we can get negotiated ciphers.
TEST_F(JsepPeerConnectionP2PTestClient, GetNegotiatedCiphersStats) {
ASSERT_TRUE(CreateTestClients());
LocalP2PTest();
EXPECT_EQ_WAIT(
rtc::SSLStreamAdapter::GetDefaultSslCipher(),
initializing_client()->GetDtlsCipherStats(),
kMaxWaitForStatsMs);
EXPECT_EQ_WAIT(
kDefaultSrtpCipher,
initializing_client()->GetSrtpCipherStats(),
kMaxWaitForStatsMs);
}
// This test sets up a call between two parties with audio, video and data.
TEST_F(JsepPeerConnectionP2PTestClient, LocalP2PTestDataChannel) {
FakeConstraints setup_constraints;

View File

@ -715,6 +715,18 @@ void StatsCollector::ExtractSessionInfo() {
StatsReport::kStatsValueNameRemoteCertificateId,
remote_cert_report_id);
}
const std::string& srtp_cipher = channel_iter->srtp_cipher;
if (!srtp_cipher.empty()) {
channel_report->AddValue(
StatsReport::kStatsValueNameSrtpCipher,
srtp_cipher);
}
const std::string& ssl_cipher = channel_iter->ssl_cipher;
if (!ssl_cipher.empty()) {
channel_report->AddValue(
StatsReport::kStatsValueNameDtlsCipher,
ssl_cipher);
}
for (size_t i = 0;
i < channel_iter->connection_infos.size();
++i) {
@ -742,8 +754,6 @@ void StatsCollector::ExtractSessionInfo() {
info.writable);
report->AddBoolean(StatsReport::kStatsValueNameReadable,
info.readable);
report->AddBoolean(StatsReport::kStatsValueNameActiveConnection,
info.best_connection);
report->AddValue(StatsReport::kStatsValueNameLocalCandidateId,
AddCandidateReport(info.local_candidate, true));
report->AddValue(
@ -760,6 +770,13 @@ void StatsCollector::ExtractSessionInfo() {
info.local_candidate.type());
report->AddValue(StatsReport::kStatsValueNameRemoteCandidateType,
info.remote_candidate.type());
report->AddBoolean(StatsReport::kStatsValueNameActiveConnection,
info.best_connection);
if (info.best_connection) {
channel_report->AddValue(
StatsReport::kStatsValueNameSelectedCandidatePairId,
report->id().ToString());
}
}
}
}

View File

@ -644,6 +644,8 @@ class StatsCollectorTest : public testing::Test {
// Fake stats to process.
cricket::TransportChannelStats channel_stats;
channel_stats.component = 1;
channel_stats.srtp_cipher = "the-srtp-cipher";
channel_stats.ssl_cipher = "the-ssl-cipher";
cricket::TransportStats transport_stats;
transport_stats.content_name = "audio";
@ -713,6 +715,18 @@ class StatsCollectorTest : public testing::Test {
} else {
EXPECT_EQ(kNotFound, remote_certificate_id);
}
// Check negotiated ciphers.
std::string dtls_cipher = ExtractStatsValue(
StatsReport::kStatsReportTypeComponent,
reports,
StatsReport::kStatsValueNameDtlsCipher);
EXPECT_EQ("the-ssl-cipher", dtls_cipher);
std::string srtp_cipher = ExtractStatsValue(
StatsReport::kStatsReportTypeComponent,
reports,
StatsReport::kStatsValueNameSrtpCipher);
EXPECT_EQ("the-srtp-cipher", srtp_cipher);
}
cricket::FakeMediaEngine* media_engine_;
@ -1318,6 +1332,18 @@ TEST_F(StatsCollectorTest, NoTransport) {
reports,
StatsReport::kStatsValueNameRemoteCertificateId);
ASSERT_EQ(kNotFound, remote_certificate_id);
// Check that the negotiated ciphers are absent.
std::string dtls_cipher = ExtractStatsValue(
StatsReport::kStatsReportTypeComponent,
reports,
StatsReport::kStatsValueNameDtlsCipher);
ASSERT_EQ(kNotFound, dtls_cipher);
std::string srtp_cipher = ExtractStatsValue(
StatsReport::kStatsReportTypeComponent,
reports,
StatsReport::kStatsValueNameSrtpCipher);
ASSERT_EQ(kNotFound, srtp_cipher);
}
// This test verifies that the stats are generated correctly when the transport

View File

@ -54,7 +54,7 @@ const char* InternalTypeToString(StatsReport::StatsType type) {
case StatsReport::kStatsReportTypeIceRemoteCandidate:
return "remotecandidate";
case StatsReport::kStatsReportTypeTransport:
return "googTransport";
return "transport";
case StatsReport::kStatsReportTypeComponent:
return "googComponent";
case StatsReport::kStatsReportTypeCandidatePair:
@ -244,6 +244,8 @@ const char* StatsReport::Value::display_name() const {
return "protocol";
case kStatsValueNameTransportId:
return "transportId";
case kStatsValueNameSelectedCandidatePairId:
return "selectedCandidatePairId";
case kStatsValueNameSsrc:
return "ssrc";
case kStatsValueNameState:
@ -310,6 +312,8 @@ const char* StatsReport::Value::display_name() const {
return "googDecodingPLCCNG";
case kStatsValueNameDer:
return "googDerBase64";
case kStatsValueNameDtlsCipher:
return "dtlsCipher";
case kStatsValueNameEchoCancellationQualityMin:
return "googEchoCancellationQualityMin";
case kStatsValueNameEchoDelayMedian:
@ -383,7 +387,7 @@ const char* StatsReport::Value::display_name() const {
case kStatsValueNameLocalCandidateType:
return "googLocalCandidateType";
case kStatsValueNameLocalCertificateId:
return "googLocalCertificateId";
return "localCertificateId";
case kStatsValueNameAdaptationChanges:
return "googAdaptationChanges";
case kStatsValueNameNacksReceived:
@ -411,7 +415,7 @@ const char* StatsReport::Value::display_name() const {
case kStatsValueNameRemoteCandidateType:
return "googRemoteCandidateType";
case kStatsValueNameRemoteCertificateId:
return "googRemoteCertificateId";
return "remoteCertificateId";
case kStatsValueNameRetransmitBitrate:
return "googRetransmitBitrate";
case kStatsValueNameRtt:
@ -422,6 +426,8 @@ const char* StatsReport::Value::display_name() const {
return "packetsDiscardedOnSend";
case kStatsValueNameSpeechExpandRate:
return "googSpeechExpandRate";
case kStatsValueNameSrtpCipher:
return "srtpCipher";
case kStatsValueNameTargetEncBitrate:
return "googTargetEncBitrate";
case kStatsValueNameTransmitBitrate:

View File

@ -125,6 +125,7 @@ class StatsReport {
kStatsValueNamePacketsSent,
kStatsValueNameProtocol,
kStatsValueNameReadable,
kStatsValueNameSelectedCandidatePairId,
kStatsValueNameSsrc,
kStatsValueNameState,
kStatsValueNameTransportId,
@ -160,6 +161,7 @@ class StatsReport {
kStatsValueNameDecodingPLC,
kStatsValueNameDecodingPLCCNG,
kStatsValueNameDer,
kStatsValueNameDtlsCipher,
kStatsValueNameEchoCancellationQualityMin,
kStatsValueNameEchoDelayMedian,
kStatsValueNameEchoDelayStdDev,
@ -211,6 +213,7 @@ class StatsReport {
kStatsValueNameSecondaryDecodedRate,
kStatsValueNameSendPacketsDiscarded,
kStatsValueNameSpeechExpandRate,
kStatsValueNameSrtpCipher,
kStatsValueNameTargetDelayMs,
kStatsValueNameTargetEncBitrate,
kStatsValueNameTrackId,

View File

@ -123,7 +123,7 @@ class MockStatsObserver : public webrtc::StatsObserver {
virtual void OnComplete(const StatsReports& reports) {
ASSERT(!called_);
called_ = true;
memset(&stats_, 0, sizeof(stats_));
stats_.Clear();
stats_.number_of_reports = reports.size();
for (const auto* r : reports) {
if (r->type() == StatsReport::kStatsReportTypeSsrc) {
@ -138,6 +138,11 @@ class MockStatsObserver : public webrtc::StatsObserver {
} else if (r->type() == StatsReport::kStatsReportTypeBwe) {
GetIntValue(r, StatsReport::kStatsValueNameAvailableReceiveBandwidth,
&stats_.available_receive_bandwidth);
} else if (r->type() == StatsReport::kStatsReportTypeComponent) {
GetStringValue(r, StatsReport::kStatsValueNameDtlsCipher,
&stats_.dtls_cipher);
GetStringValue(r, StatsReport::kStatsValueNameSrtpCipher,
&stats_.srtp_cipher);
}
}
}
@ -170,6 +175,16 @@ class MockStatsObserver : public webrtc::StatsObserver {
return stats_.available_receive_bandwidth;
}
std::string DtlsCipher() const {
ASSERT(called_);
return stats_.dtls_cipher;
}
std::string SrtpCipher() const {
ASSERT(called_);
return stats_.srtp_cipher;
}
private:
bool GetIntValue(const StatsReport* report,
StatsReport::StatsValueName name,
@ -182,15 +197,39 @@ class MockStatsObserver : public webrtc::StatsObserver {
}
return false;
}
bool GetStringValue(const StatsReport* report,
StatsReport::StatsValueName name,
std::string* value) {
for (const auto& v : report->values()) {
if (v->name == name) {
*value = v->value;
return true;
}
}
return false;
}
bool called_;
struct {
void Clear() {
number_of_reports = 0;
audio_output_level = 0;
audio_input_level = 0;
bytes_received = 0;
bytes_sent = 0;
available_receive_bandwidth = 0;
dtls_cipher.clear();
srtp_cipher.clear();
}
size_t number_of_reports;
int audio_output_level;
int audio_input_level;
int bytes_received;
int bytes_sent;
int available_receive_bandwidth;
std::string dtls_cipher;
std::string srtp_cipher;
} stats_;
};