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:
parent
be77872d2c
commit
7bea1ffe77
@ -102,6 +102,15 @@ static const char kVideoTrackLabelBase[] = "video_track";
|
|||||||
static const char kAudioTrackLabelBase[] = "audio_track";
|
static const char kAudioTrackLabelBase[] = "audio_track";
|
||||||
static const char kDataChannelLabel[] = "data_channel";
|
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,
|
static void RemoveLinesFromSdp(const std::string& line_start,
|
||||||
std::string* sdp) {
|
std::string* sdp) {
|
||||||
const char kSdpLineEnd[] = "\r\n";
|
const char kSdpLineEnd[] = "\r\n";
|
||||||
@ -380,6 +389,24 @@ class PeerConnectionTestClientBase
|
|||||||
return bw;
|
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() {
|
int rendered_width() {
|
||||||
EXPECT_FALSE(fake_video_renderers_.empty());
|
EXPECT_FALSE(fake_video_renderers_.empty());
|
||||||
return fake_video_renderers_.empty() ? 1 :
|
return fake_video_renderers_.empty() ? 1 :
|
||||||
@ -1280,6 +1307,22 @@ TEST_F(JsepPeerConnectionP2PTestClient, GetBytesSentStats) {
|
|||||||
kMaxWaitForStatsMs);
|
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.
|
// This test sets up a call between two parties with audio, video and data.
|
||||||
TEST_F(JsepPeerConnectionP2PTestClient, LocalP2PTestDataChannel) {
|
TEST_F(JsepPeerConnectionP2PTestClient, LocalP2PTestDataChannel) {
|
||||||
FakeConstraints setup_constraints;
|
FakeConstraints setup_constraints;
|
||||||
|
@ -715,6 +715,18 @@ void StatsCollector::ExtractSessionInfo() {
|
|||||||
StatsReport::kStatsValueNameRemoteCertificateId,
|
StatsReport::kStatsValueNameRemoteCertificateId,
|
||||||
remote_cert_report_id);
|
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;
|
for (size_t i = 0;
|
||||||
i < channel_iter->connection_infos.size();
|
i < channel_iter->connection_infos.size();
|
||||||
++i) {
|
++i) {
|
||||||
@ -742,8 +754,6 @@ void StatsCollector::ExtractSessionInfo() {
|
|||||||
info.writable);
|
info.writable);
|
||||||
report->AddBoolean(StatsReport::kStatsValueNameReadable,
|
report->AddBoolean(StatsReport::kStatsValueNameReadable,
|
||||||
info.readable);
|
info.readable);
|
||||||
report->AddBoolean(StatsReport::kStatsValueNameActiveConnection,
|
|
||||||
info.best_connection);
|
|
||||||
report->AddValue(StatsReport::kStatsValueNameLocalCandidateId,
|
report->AddValue(StatsReport::kStatsValueNameLocalCandidateId,
|
||||||
AddCandidateReport(info.local_candidate, true));
|
AddCandidateReport(info.local_candidate, true));
|
||||||
report->AddValue(
|
report->AddValue(
|
||||||
@ -760,6 +770,13 @@ void StatsCollector::ExtractSessionInfo() {
|
|||||||
info.local_candidate.type());
|
info.local_candidate.type());
|
||||||
report->AddValue(StatsReport::kStatsValueNameRemoteCandidateType,
|
report->AddValue(StatsReport::kStatsValueNameRemoteCandidateType,
|
||||||
info.remote_candidate.type());
|
info.remote_candidate.type());
|
||||||
|
report->AddBoolean(StatsReport::kStatsValueNameActiveConnection,
|
||||||
|
info.best_connection);
|
||||||
|
if (info.best_connection) {
|
||||||
|
channel_report->AddValue(
|
||||||
|
StatsReport::kStatsValueNameSelectedCandidatePairId,
|
||||||
|
report->id().ToString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -644,6 +644,8 @@ class StatsCollectorTest : public testing::Test {
|
|||||||
// Fake stats to process.
|
// Fake stats to process.
|
||||||
cricket::TransportChannelStats channel_stats;
|
cricket::TransportChannelStats channel_stats;
|
||||||
channel_stats.component = 1;
|
channel_stats.component = 1;
|
||||||
|
channel_stats.srtp_cipher = "the-srtp-cipher";
|
||||||
|
channel_stats.ssl_cipher = "the-ssl-cipher";
|
||||||
|
|
||||||
cricket::TransportStats transport_stats;
|
cricket::TransportStats transport_stats;
|
||||||
transport_stats.content_name = "audio";
|
transport_stats.content_name = "audio";
|
||||||
@ -713,6 +715,18 @@ class StatsCollectorTest : public testing::Test {
|
|||||||
} else {
|
} else {
|
||||||
EXPECT_EQ(kNotFound, remote_certificate_id);
|
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_;
|
cricket::FakeMediaEngine* media_engine_;
|
||||||
@ -1318,6 +1332,18 @@ TEST_F(StatsCollectorTest, NoTransport) {
|
|||||||
reports,
|
reports,
|
||||||
StatsReport::kStatsValueNameRemoteCertificateId);
|
StatsReport::kStatsValueNameRemoteCertificateId);
|
||||||
ASSERT_EQ(kNotFound, remote_certificate_id);
|
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
|
// This test verifies that the stats are generated correctly when the transport
|
||||||
|
@ -54,7 +54,7 @@ const char* InternalTypeToString(StatsReport::StatsType type) {
|
|||||||
case StatsReport::kStatsReportTypeIceRemoteCandidate:
|
case StatsReport::kStatsReportTypeIceRemoteCandidate:
|
||||||
return "remotecandidate";
|
return "remotecandidate";
|
||||||
case StatsReport::kStatsReportTypeTransport:
|
case StatsReport::kStatsReportTypeTransport:
|
||||||
return "googTransport";
|
return "transport";
|
||||||
case StatsReport::kStatsReportTypeComponent:
|
case StatsReport::kStatsReportTypeComponent:
|
||||||
return "googComponent";
|
return "googComponent";
|
||||||
case StatsReport::kStatsReportTypeCandidatePair:
|
case StatsReport::kStatsReportTypeCandidatePair:
|
||||||
@ -244,6 +244,8 @@ const char* StatsReport::Value::display_name() const {
|
|||||||
return "protocol";
|
return "protocol";
|
||||||
case kStatsValueNameTransportId:
|
case kStatsValueNameTransportId:
|
||||||
return "transportId";
|
return "transportId";
|
||||||
|
case kStatsValueNameSelectedCandidatePairId:
|
||||||
|
return "selectedCandidatePairId";
|
||||||
case kStatsValueNameSsrc:
|
case kStatsValueNameSsrc:
|
||||||
return "ssrc";
|
return "ssrc";
|
||||||
case kStatsValueNameState:
|
case kStatsValueNameState:
|
||||||
@ -310,6 +312,8 @@ const char* StatsReport::Value::display_name() const {
|
|||||||
return "googDecodingPLCCNG";
|
return "googDecodingPLCCNG";
|
||||||
case kStatsValueNameDer:
|
case kStatsValueNameDer:
|
||||||
return "googDerBase64";
|
return "googDerBase64";
|
||||||
|
case kStatsValueNameDtlsCipher:
|
||||||
|
return "dtlsCipher";
|
||||||
case kStatsValueNameEchoCancellationQualityMin:
|
case kStatsValueNameEchoCancellationQualityMin:
|
||||||
return "googEchoCancellationQualityMin";
|
return "googEchoCancellationQualityMin";
|
||||||
case kStatsValueNameEchoDelayMedian:
|
case kStatsValueNameEchoDelayMedian:
|
||||||
@ -383,7 +387,7 @@ const char* StatsReport::Value::display_name() const {
|
|||||||
case kStatsValueNameLocalCandidateType:
|
case kStatsValueNameLocalCandidateType:
|
||||||
return "googLocalCandidateType";
|
return "googLocalCandidateType";
|
||||||
case kStatsValueNameLocalCertificateId:
|
case kStatsValueNameLocalCertificateId:
|
||||||
return "googLocalCertificateId";
|
return "localCertificateId";
|
||||||
case kStatsValueNameAdaptationChanges:
|
case kStatsValueNameAdaptationChanges:
|
||||||
return "googAdaptationChanges";
|
return "googAdaptationChanges";
|
||||||
case kStatsValueNameNacksReceived:
|
case kStatsValueNameNacksReceived:
|
||||||
@ -411,7 +415,7 @@ const char* StatsReport::Value::display_name() const {
|
|||||||
case kStatsValueNameRemoteCandidateType:
|
case kStatsValueNameRemoteCandidateType:
|
||||||
return "googRemoteCandidateType";
|
return "googRemoteCandidateType";
|
||||||
case kStatsValueNameRemoteCertificateId:
|
case kStatsValueNameRemoteCertificateId:
|
||||||
return "googRemoteCertificateId";
|
return "remoteCertificateId";
|
||||||
case kStatsValueNameRetransmitBitrate:
|
case kStatsValueNameRetransmitBitrate:
|
||||||
return "googRetransmitBitrate";
|
return "googRetransmitBitrate";
|
||||||
case kStatsValueNameRtt:
|
case kStatsValueNameRtt:
|
||||||
@ -422,6 +426,8 @@ const char* StatsReport::Value::display_name() const {
|
|||||||
return "packetsDiscardedOnSend";
|
return "packetsDiscardedOnSend";
|
||||||
case kStatsValueNameSpeechExpandRate:
|
case kStatsValueNameSpeechExpandRate:
|
||||||
return "googSpeechExpandRate";
|
return "googSpeechExpandRate";
|
||||||
|
case kStatsValueNameSrtpCipher:
|
||||||
|
return "srtpCipher";
|
||||||
case kStatsValueNameTargetEncBitrate:
|
case kStatsValueNameTargetEncBitrate:
|
||||||
return "googTargetEncBitrate";
|
return "googTargetEncBitrate";
|
||||||
case kStatsValueNameTransmitBitrate:
|
case kStatsValueNameTransmitBitrate:
|
||||||
|
@ -125,6 +125,7 @@ class StatsReport {
|
|||||||
kStatsValueNamePacketsSent,
|
kStatsValueNamePacketsSent,
|
||||||
kStatsValueNameProtocol,
|
kStatsValueNameProtocol,
|
||||||
kStatsValueNameReadable,
|
kStatsValueNameReadable,
|
||||||
|
kStatsValueNameSelectedCandidatePairId,
|
||||||
kStatsValueNameSsrc,
|
kStatsValueNameSsrc,
|
||||||
kStatsValueNameState,
|
kStatsValueNameState,
|
||||||
kStatsValueNameTransportId,
|
kStatsValueNameTransportId,
|
||||||
@ -160,6 +161,7 @@ class StatsReport {
|
|||||||
kStatsValueNameDecodingPLC,
|
kStatsValueNameDecodingPLC,
|
||||||
kStatsValueNameDecodingPLCCNG,
|
kStatsValueNameDecodingPLCCNG,
|
||||||
kStatsValueNameDer,
|
kStatsValueNameDer,
|
||||||
|
kStatsValueNameDtlsCipher,
|
||||||
kStatsValueNameEchoCancellationQualityMin,
|
kStatsValueNameEchoCancellationQualityMin,
|
||||||
kStatsValueNameEchoDelayMedian,
|
kStatsValueNameEchoDelayMedian,
|
||||||
kStatsValueNameEchoDelayStdDev,
|
kStatsValueNameEchoDelayStdDev,
|
||||||
@ -211,6 +213,7 @@ class StatsReport {
|
|||||||
kStatsValueNameSecondaryDecodedRate,
|
kStatsValueNameSecondaryDecodedRate,
|
||||||
kStatsValueNameSendPacketsDiscarded,
|
kStatsValueNameSendPacketsDiscarded,
|
||||||
kStatsValueNameSpeechExpandRate,
|
kStatsValueNameSpeechExpandRate,
|
||||||
|
kStatsValueNameSrtpCipher,
|
||||||
kStatsValueNameTargetDelayMs,
|
kStatsValueNameTargetDelayMs,
|
||||||
kStatsValueNameTargetEncBitrate,
|
kStatsValueNameTargetEncBitrate,
|
||||||
kStatsValueNameTrackId,
|
kStatsValueNameTrackId,
|
||||||
|
@ -123,7 +123,7 @@ class MockStatsObserver : public webrtc::StatsObserver {
|
|||||||
virtual void OnComplete(const StatsReports& reports) {
|
virtual void OnComplete(const StatsReports& reports) {
|
||||||
ASSERT(!called_);
|
ASSERT(!called_);
|
||||||
called_ = true;
|
called_ = true;
|
||||||
memset(&stats_, 0, sizeof(stats_));
|
stats_.Clear();
|
||||||
stats_.number_of_reports = reports.size();
|
stats_.number_of_reports = reports.size();
|
||||||
for (const auto* r : reports) {
|
for (const auto* r : reports) {
|
||||||
if (r->type() == StatsReport::kStatsReportTypeSsrc) {
|
if (r->type() == StatsReport::kStatsReportTypeSsrc) {
|
||||||
@ -138,6 +138,11 @@ class MockStatsObserver : public webrtc::StatsObserver {
|
|||||||
} else if (r->type() == StatsReport::kStatsReportTypeBwe) {
|
} else if (r->type() == StatsReport::kStatsReportTypeBwe) {
|
||||||
GetIntValue(r, StatsReport::kStatsValueNameAvailableReceiveBandwidth,
|
GetIntValue(r, StatsReport::kStatsValueNameAvailableReceiveBandwidth,
|
||||||
&stats_.available_receive_bandwidth);
|
&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;
|
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:
|
private:
|
||||||
bool GetIntValue(const StatsReport* report,
|
bool GetIntValue(const StatsReport* report,
|
||||||
StatsReport::StatsValueName name,
|
StatsReport::StatsValueName name,
|
||||||
@ -182,15 +197,39 @@ class MockStatsObserver : public webrtc::StatsObserver {
|
|||||||
}
|
}
|
||||||
return false;
|
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_;
|
bool called_;
|
||||||
struct {
|
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;
|
size_t number_of_reports;
|
||||||
int audio_output_level;
|
int audio_output_level;
|
||||||
int audio_input_level;
|
int audio_input_level;
|
||||||
int bytes_received;
|
int bytes_received;
|
||||||
int bytes_sent;
|
int bytes_sent;
|
||||||
int available_receive_bandwidth;
|
int available_receive_bandwidth;
|
||||||
|
std::string dtls_cipher;
|
||||||
|
std::string srtp_cipher;
|
||||||
} stats_;
|
} stats_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user