Revert "TransportController refactoring."
This reverts commit 9af63f473e1d0d6c47a741a046c41642dfc1c178.
Cr-Commit-Position: refs/heads/master@{#9994}
diff --git a/talk/app/webrtc/objctests/RTCPeerConnectionSyncObserver.m b/talk/app/webrtc/objctests/RTCPeerConnectionSyncObserver.m
index daebc95..5070b78 100644
--- a/talk/app/webrtc/objctests/RTCPeerConnectionSyncObserver.m
+++ b/talk/app/webrtc/objctests/RTCPeerConnectionSyncObserver.m
@@ -196,11 +196,8 @@
if (newState == RTCICEGatheringGathering) {
return;
}
- NSAssert([_expectedICEGatheringChanges count] > 0,
- @"Unexpected ICE gathering state change");
int expectedState = [self popFirstElementAsInt:_expectedICEGatheringChanges];
- NSAssert(expectedState == (int)newState,
- @"ICE gathering state should match expectation");
+ NSAssert(expectedState == (int)newState, @"Empty expectation array");
}
- (void)peerConnection:(RTCPeerConnection*)peerConnection
@@ -208,11 +205,8 @@
// See TODO(fischman) in RTCPeerConnectionTest.mm about Completed.
if (newState == RTCICEConnectionCompleted)
return;
- NSAssert([_expectedICEConnectionChanges count] > 0,
- @"Unexpected ICE connection state change");
int expectedState = [self popFirstElementAsInt:_expectedICEConnectionChanges];
- NSAssert(expectedState == (int)newState,
- @"ICE connection state should match expectation");
+ NSAssert(expectedState == (int)newState, @"Empty expectation array");
}
- (void)peerConnection:(RTCPeerConnection*)peerConnection
diff --git a/talk/app/webrtc/peerconnection.cc b/talk/app/webrtc/peerconnection.cc
index 7e68949..41df847 100644
--- a/talk/app/webrtc/peerconnection.cc
+++ b/talk/app/webrtc/peerconnection.cc
@@ -868,11 +868,6 @@
void PeerConnection::OnIceConnectionChange(
PeerConnectionInterface::IceConnectionState new_state) {
ASSERT(signaling_thread()->IsCurrent());
- // After transitioning to "closed", ignore any additional states from
- // WebRtcSession (such as "disconnected").
- if (ice_connection_state_ == kIceConnectionClosed) {
- return;
- }
ice_connection_state_ = new_state;
observer_->OnIceConnectionChange(ice_connection_state_);
}
diff --git a/talk/app/webrtc/statscollector.cc b/talk/app/webrtc/statscollector.cc
index 3583f61..6327445 100644
--- a/talk/app/webrtc/statscollector.cc
+++ b/talk/app/webrtc/statscollector.cc
@@ -697,18 +697,24 @@
// expose them in stats reports. All channels in a transport share the
// same local and remote certificates.
//
+ // Note that Transport::GetCertificate and Transport::GetRemoteCertificate
+ // invoke method calls on the worker thread and block this thread, but
+ // messages are still processed on this thread, which may blow way the
+ // existing transports. So we cannot reuse |transport| after these calls.
StatsReport::Id local_cert_report_id, remote_cert_report_id;
+
+ cricket::Transport* transport =
+ session_->GetTransport(transport_iter.second.content_name);
rtc::scoped_refptr<rtc::RTCCertificate> certificate;
- if (session_->GetLocalCertificate(transport_iter.second.transport_name,
- &certificate)) {
+ if (transport && transport->GetCertificate(&certificate)) {
StatsReport* r = AddCertificateReports(&(certificate->ssl_certificate()));
if (r)
local_cert_report_id = r->id();
}
+ transport = session_->GetTransport(transport_iter.second.content_name);
rtc::scoped_ptr<rtc::SSLCertificate> cert;
- if (session_->GetRemoteSSLCertificate(transport_iter.second.transport_name,
- cert.accept())) {
+ if (transport && transport->GetRemoteSSLCertificate(cert.accept())) {
StatsReport* r = AddCertificateReports(cert.get());
if (r)
remote_cert_report_id = r->id();
@@ -716,7 +722,7 @@
for (const auto& channel_iter : transport_iter.second.channel_stats) {
StatsReport::Id id(StatsReport::NewComponentId(
- transport_iter.second.transport_name, channel_iter.component));
+ transport_iter.second.content_name, channel_iter.component));
StatsReport* channel_report = reports_.ReplaceOrAddNew(id);
channel_report->set_timestamp(stats_gathering_started_);
channel_report->AddInt(StatsReport::kStatsValueNameComponent,
@@ -933,6 +939,7 @@
StatsReport* report = entry.second;
report->set_timestamp(stats_gathering_started_);
}
+
}
void StatsCollector::ClearUpdateStatsCacheForTest() {
diff --git a/talk/app/webrtc/statscollector_unittest.cc b/talk/app/webrtc/statscollector_unittest.cc
index 0a9d947..9b037c4 100644
--- a/talk/app/webrtc/statscollector_unittest.cc
+++ b/talk/app/webrtc/statscollector_unittest.cc
@@ -27,8 +27,6 @@
#include <stdio.h>
-#include <algorithm>
-
#include "talk/app/webrtc/statscollector.h"
#include "talk/app/webrtc/mediastream.h"
@@ -47,7 +45,7 @@
#include "webrtc/base/fakesslidentity.h"
#include "webrtc/base/gunit.h"
#include "webrtc/base/network.h"
-#include "webrtc/p2p/base/faketransportcontroller.h"
+#include "webrtc/p2p/base/fakesession.h"
using rtc::scoped_ptr;
using testing::_;
@@ -91,12 +89,7 @@
MOCK_METHOD2(GetLocalTrackIdBySsrc, bool(uint32, std::string*));
MOCK_METHOD2(GetRemoteTrackIdBySsrc, bool(uint32, std::string*));
MOCK_METHOD1(GetTransportStats, bool(cricket::SessionStats*));
- MOCK_METHOD2(GetLocalCertificate,
- bool(const std::string& transport_name,
- rtc::scoped_refptr<rtc::RTCCertificate>* certificate));
- MOCK_METHOD2(GetRemoteSSLCertificate,
- bool(const std::string& transport_name,
- rtc::SSLCertificate** cert));
+ MOCK_METHOD1(GetTransport, cricket::Transport*(const std::string&));
};
class MockVideoMediaChannel : public cricket::FakeVideoMediaChannel {
@@ -507,7 +500,7 @@
cricket::TransportStats transport_stats;
cricket::TransportChannelStats channel_stats;
channel_stats.component = 1;
- transport_stats.transport_name = kTransportName;
+ transport_stats.content_name = kTransportName;
transport_stats.channel_stats.push_back(channel_stats);
session_stats_.transport_stats[kTransportName] = transport_stats;
@@ -654,27 +647,36 @@
channel_stats.ssl_cipher = "the-ssl-cipher";
cricket::TransportStats transport_stats;
- transport_stats.transport_name = "audio";
+ transport_stats.content_name = "audio";
transport_stats.channel_stats.push_back(channel_stats);
cricket::SessionStats session_stats;
- session_stats.transport_stats[transport_stats.transport_name] =
+ session_stats.transport_stats[transport_stats.content_name] =
transport_stats;
- // Fake certificate to report
+ // Fake certificates to report.
rtc::scoped_refptr<rtc::RTCCertificate> local_certificate(
rtc::RTCCertificate::Create(rtc::scoped_ptr<rtc::FakeSSLIdentity>(
- new rtc::FakeSSLIdentity(local_cert))
- .Pass()));
+ new rtc::FakeSSLIdentity(local_cert)).Pass()));
+ rtc::scoped_ptr<rtc::FakeSSLCertificate> remote_cert_copy(
+ remote_cert.GetReference());
+
+ // Fake transport object.
+ rtc::scoped_ptr<cricket::FakeTransport> transport(
+ new cricket::FakeTransport(
+ session_.signaling_thread(),
+ session_.worker_thread(),
+ transport_stats.content_name));
+ transport->SetCertificate(local_certificate);
+ cricket::FakeTransportChannel* channel =
+ static_cast<cricket::FakeTransportChannel*>(
+ transport->CreateChannel(channel_stats.component));
+ EXPECT_FALSE(channel == NULL);
+ channel->SetRemoteSSLCertificate(remote_cert_copy.get());
// Configure MockWebRtcSession
- EXPECT_CALL(session_,
- GetLocalCertificate(transport_stats.transport_name, _))
- .WillOnce(DoAll(SetArgPointee<1>(local_certificate), Return(true)));
- EXPECT_CALL(session_,
- GetRemoteSSLCertificate(transport_stats.transport_name, _))
- .WillOnce(
- DoAll(SetArgPointee<1>(remote_cert.GetReference()), Return(true)));
+ EXPECT_CALL(session_, GetTransport(transport_stats.content_name))
+ .WillRepeatedly(Return(transport.get()));
EXPECT_CALL(session_, GetTransportStats(_))
.WillOnce(DoAll(SetArgPointee<0>(session_stats),
Return(true)));
@@ -788,17 +790,14 @@
TEST_F(StatsCollectorTest, BytesCounterHandles64Bits) {
StatsCollectorForTest stats(&session_);
- EXPECT_CALL(session_, GetLocalCertificate(_, _))
- .WillRepeatedly(Return(false));
- EXPECT_CALL(session_, GetRemoteSSLCertificate(_, _))
- .WillRepeatedly(Return(false));
-
const char kVideoChannelName[] = "video";
InitSessionStats(kVideoChannelName);
EXPECT_CALL(session_, GetTransportStats(_))
.WillRepeatedly(DoAll(SetArgPointee<0>(session_stats_),
Return(true)));
+ EXPECT_CALL(session_, GetTransport(_))
+ .WillRepeatedly(Return(static_cast<cricket::Transport*>(NULL)));
MockVideoMediaChannel* media_channel = new MockVideoMediaChannel();
cricket::VideoChannel video_channel(rtc::Thread::Current(),
@@ -834,17 +833,14 @@
TEST_F(StatsCollectorTest, BandwidthEstimationInfoIsReported) {
StatsCollectorForTest stats(&session_);
- EXPECT_CALL(session_, GetLocalCertificate(_, _))
- .WillRepeatedly(Return(false));
- EXPECT_CALL(session_, GetRemoteSSLCertificate(_, _))
- .WillRepeatedly(Return(false));
-
const char kVideoChannelName[] = "video";
InitSessionStats(kVideoChannelName);
EXPECT_CALL(session_, GetTransportStats(_))
.WillRepeatedly(DoAll(SetArgPointee<0>(session_stats_),
Return(true)));
+ EXPECT_CALL(session_, GetTransport(_))
+ .WillRepeatedly(Return(static_cast<cricket::Transport*>(NULL)));
MockVideoMediaChannel* media_channel = new MockVideoMediaChannel();
cricket::VideoChannel video_channel(rtc::Thread::Current(),
@@ -950,16 +946,13 @@
TEST_F(StatsCollectorTest, TrackAndSsrcObjectExistAfterUpdateSsrcStats) {
StatsCollectorForTest stats(&session_);
- EXPECT_CALL(session_, GetLocalCertificate(_, _))
- .WillRepeatedly(Return(false));
- EXPECT_CALL(session_, GetRemoteSSLCertificate(_, _))
- .WillRepeatedly(Return(false));
-
const char kVideoChannelName[] = "video";
InitSessionStats(kVideoChannelName);
EXPECT_CALL(session_, GetTransportStats(_))
.WillRepeatedly(DoAll(SetArgPointee<0>(session_stats_),
Return(true)));
+ EXPECT_CALL(session_, GetTransport(_))
+ .WillRepeatedly(Return(static_cast<cricket::Transport*>(NULL)));
MockVideoMediaChannel* media_channel = new MockVideoMediaChannel();
cricket::VideoChannel video_channel(rtc::Thread::Current(),
@@ -1018,13 +1011,11 @@
TEST_F(StatsCollectorTest, TransportObjectLinkedFromSsrcObject) {
StatsCollectorForTest stats(&session_);
- EXPECT_CALL(session_, GetLocalCertificate(_, _))
- .WillRepeatedly(Return(false));
- EXPECT_CALL(session_, GetRemoteSSLCertificate(_, _))
- .WillRepeatedly(Return(false));
-
+ // Ignore unused callback (logspam).
+ EXPECT_CALL(session_, GetTransport(_))
+ .WillRepeatedly(Return(static_cast<cricket::Transport*>(NULL)));
MockVideoMediaChannel* media_channel = new MockVideoMediaChannel();
- // The transport_name known by the video channel.
+ // The content_name known by the video channel.
const std::string kVcName("vcname");
cricket::VideoChannel video_channel(rtc::Thread::Current(),
media_channel, NULL, kVcName, false);
@@ -1082,7 +1073,7 @@
StatsCollectorForTest stats(&session_);
MockVideoMediaChannel* media_channel = new MockVideoMediaChannel();
- // The transport_name known by the video channel.
+ // The content_name known by the video channel.
const std::string kVcName("vcname");
cricket::VideoChannel video_channel(rtc::Thread::Current(),
media_channel, NULL, kVcName, false);
@@ -1105,13 +1096,11 @@
TEST_F(StatsCollectorTest, RemoteSsrcInfoIsPresent) {
StatsCollectorForTest stats(&session_);
- EXPECT_CALL(session_, GetLocalCertificate(_, _))
- .WillRepeatedly(Return(false));
- EXPECT_CALL(session_, GetRemoteSSLCertificate(_, _))
- .WillRepeatedly(Return(false));
-
+ // Ignore unused callback (logspam).
+ EXPECT_CALL(session_, GetTransport(_))
+ .WillRepeatedly(Return(static_cast<cricket::Transport*>(NULL)));
MockVideoMediaChannel* media_channel = new MockVideoMediaChannel();
- // The transport_name known by the video channel.
+ // The content_name known by the video channel.
const std::string kVcName("vcname");
cricket::VideoChannel video_channel(rtc::Thread::Current(),
media_channel, NULL, kVcName, false);
@@ -1156,16 +1145,13 @@
TEST_F(StatsCollectorTest, ReportsFromRemoteTrack) {
StatsCollectorForTest stats(&session_);
- EXPECT_CALL(session_, GetLocalCertificate(_, _))
- .WillRepeatedly(Return(false));
- EXPECT_CALL(session_, GetRemoteSSLCertificate(_, _))
- .WillRepeatedly(Return(false));
-
const char kVideoChannelName[] = "video";
InitSessionStats(kVideoChannelName);
EXPECT_CALL(session_, GetTransportStats(_))
.WillRepeatedly(DoAll(SetArgPointee<0>(session_stats_),
Return(true)));
+ EXPECT_CALL(session_, GetTransport(_))
+ .WillRepeatedly(Return(static_cast<cricket::Transport*>(NULL)));
MockVideoMediaChannel* media_channel = new MockVideoMediaChannel();
cricket::VideoChannel video_channel(rtc::Thread::Current(),
@@ -1344,11 +1330,6 @@
TEST_F(StatsCollectorTest, NoTransport) {
StatsCollectorForTest stats(&session_);
- EXPECT_CALL(session_, GetLocalCertificate(_, _))
- .WillRepeatedly(Return(false));
- EXPECT_CALL(session_, GetRemoteSSLCertificate(_, _))
- .WillRepeatedly(Return(false));
-
StatsReports reports; // returned values.
// Fake stats to process.
@@ -1356,14 +1337,16 @@
channel_stats.component = 1;
cricket::TransportStats transport_stats;
- transport_stats.transport_name = "audio";
+ transport_stats.content_name = "audio";
transport_stats.channel_stats.push_back(channel_stats);
cricket::SessionStats session_stats;
- session_stats.transport_stats[transport_stats.transport_name] =
+ session_stats.transport_stats[transport_stats.content_name] =
transport_stats;
// Configure MockWebRtcSession
+ EXPECT_CALL(session_, GetTransport(transport_stats.content_name))
+ .WillRepeatedly(ReturnNull());
EXPECT_CALL(session_, GetTransportStats(_))
.WillOnce(DoAll(SetArgPointee<0>(session_stats),
Return(true)));
@@ -1406,11 +1389,6 @@
TEST_F(StatsCollectorTest, NoCertificates) {
StatsCollectorForTest stats(&session_);
- EXPECT_CALL(session_, GetLocalCertificate(_, _))
- .WillRepeatedly(Return(false));
- EXPECT_CALL(session_, GetRemoteSSLCertificate(_, _))
- .WillRepeatedly(Return(false));
-
StatsReports reports; // returned values.
// Fake stats to process.
@@ -1418,18 +1396,23 @@
channel_stats.component = 1;
cricket::TransportStats transport_stats;
- transport_stats.transport_name = "audio";
+ transport_stats.content_name = "audio";
transport_stats.channel_stats.push_back(channel_stats);
cricket::SessionStats session_stats;
- session_stats.transport_stats[transport_stats.transport_name] =
+ session_stats.transport_stats[transport_stats.content_name] =
transport_stats;
// Fake transport object.
rtc::scoped_ptr<cricket::FakeTransport> transport(
- new cricket::FakeTransport(transport_stats.transport_name));
+ new cricket::FakeTransport(
+ session_.signaling_thread(),
+ session_.worker_thread(),
+ transport_stats.content_name));
// Configure MockWebRtcSession
+ EXPECT_CALL(session_, GetTransport(transport_stats.content_name))
+ .WillRepeatedly(Return(transport.get()));
EXPECT_CALL(session_, GetTransportStats(_))
.WillOnce(DoAll(SetArgPointee<0>(session_stats),
Return(true)));
@@ -1475,13 +1458,12 @@
TEST_F(StatsCollectorTest, GetStatsFromLocalAudioTrack) {
StatsCollectorForTest stats(&session_);
- EXPECT_CALL(session_, GetLocalCertificate(_, _))
- .WillRepeatedly(Return(false));
- EXPECT_CALL(session_, GetRemoteSSLCertificate(_, _))
- .WillRepeatedly(Return(false));
+ // Ignore unused callback (logspam).
+ EXPECT_CALL(session_, GetTransport(_))
+ .WillRepeatedly(Return(static_cast<cricket::Transport*>(NULL)));
MockVoiceMediaChannel* media_channel = new MockVoiceMediaChannel();
- // The transport_name known by the voice channel.
+ // The content_name known by the voice channel.
const std::string kVcName("vcname");
cricket::VoiceChannel voice_channel(rtc::Thread::Current(),
media_engine_, media_channel, NULL, kVcName, false);
@@ -1510,13 +1492,11 @@
TEST_F(StatsCollectorTest, GetStatsFromRemoteStream) {
StatsCollectorForTest stats(&session_);
- EXPECT_CALL(session_, GetLocalCertificate(_, _))
- .WillRepeatedly(Return(false));
- EXPECT_CALL(session_, GetRemoteSSLCertificate(_, _))
- .WillRepeatedly(Return(false));
-
+ // Ignore unused callback (logspam).
+ EXPECT_CALL(session_, GetTransport(_))
+ .WillRepeatedly(Return(static_cast<cricket::Transport*>(NULL)));
MockVoiceMediaChannel* media_channel = new MockVoiceMediaChannel();
- // The transport_name known by the voice channel.
+ // The content_name known by the voice channel.
const std::string kVcName("vcname");
cricket::VoiceChannel voice_channel(rtc::Thread::Current(),
media_engine_, media_channel, NULL, kVcName, false);
@@ -1539,13 +1519,11 @@
TEST_F(StatsCollectorTest, GetStatsAfterRemoveAudioStream) {
StatsCollectorForTest stats(&session_);
- EXPECT_CALL(session_, GetLocalCertificate(_, _))
- .WillRepeatedly(Return(false));
- EXPECT_CALL(session_, GetRemoteSSLCertificate(_, _))
- .WillRepeatedly(Return(false));
-
+ // Ignore unused callback (logspam).
+ EXPECT_CALL(session_, GetTransport(_))
+ .WillRepeatedly(Return(static_cast<cricket::Transport*>(NULL)));
MockVoiceMediaChannel* media_channel = new MockVoiceMediaChannel();
- // The transport_name known by the voice channel.
+ // The content_name known by the voice channel.
const std::string kVcName("vcname");
cricket::VoiceChannel voice_channel(rtc::Thread::Current(),
media_engine_, media_channel, NULL, kVcName, false);
@@ -1600,13 +1578,11 @@
TEST_F(StatsCollectorTest, LocalAndRemoteTracksWithSameSsrc) {
StatsCollectorForTest stats(&session_);
- EXPECT_CALL(session_, GetLocalCertificate(_, _))
- .WillRepeatedly(Return(false));
- EXPECT_CALL(session_, GetRemoteSSLCertificate(_, _))
- .WillRepeatedly(Return(false));
-
+ // Ignore unused callback (logspam).
+ EXPECT_CALL(session_, GetTransport(_))
+ .WillRepeatedly(Return(static_cast<cricket::Transport*>(NULL)));
MockVoiceMediaChannel* media_channel = new MockVoiceMediaChannel();
- // The transport_name known by the voice channel.
+ // The content_name known by the voice channel.
const std::string kVcName("vcname");
cricket::VoiceChannel voice_channel(rtc::Thread::Current(),
media_engine_, media_channel, NULL, kVcName, false);
@@ -1687,13 +1663,11 @@
TEST_F(StatsCollectorTest, TwoLocalTracksWithSameSsrc) {
StatsCollectorForTest stats(&session_);
- EXPECT_CALL(session_, GetLocalCertificate(_, _))
- .WillRepeatedly(Return(false));
- EXPECT_CALL(session_, GetRemoteSSLCertificate(_, _))
- .WillRepeatedly(Return(false));
-
+ // Ignore unused callback (logspam).
+ EXPECT_CALL(session_, GetTransport(_))
+ .WillRepeatedly(Return(static_cast<cricket::Transport*>(NULL)));
MockVoiceMediaChannel* media_channel = new MockVoiceMediaChannel();
- // The transport_name known by the voice channel.
+ // The content_name known by the voice channel.
const std::string kVcName("vcname");
cricket::VoiceChannel voice_channel(rtc::Thread::Current(),
media_engine_, media_channel, NULL, kVcName, false);
diff --git a/talk/app/webrtc/webrtcsession.cc b/talk/app/webrtc/webrtcsession.cc
index bd1cd1a..0c0e44d 100644
--- a/talk/app/webrtc/webrtcsession.cc
+++ b/talk/app/webrtc/webrtcsession.cc
@@ -31,7 +31,6 @@
#include <algorithm>
#include <vector>
-#include <set>
#include "talk/app/webrtc/jsepicecandidate.h"
#include "talk/app/webrtc/jsepsessiondescription.h"
@@ -87,7 +86,6 @@
"Couldn't set up DTLS-SRTP on RTP channel.";
const char kDtlsSetupFailureRtcp[] =
"Couldn't set up DTLS-SRTP on RTCP channel.";
-const char kEnableBundleFailed[] = "Failed to enable BUNDLE.";
const int kMaxUnsignalledRecvStreams = 20;
IceCandidatePairType GetIceCandidatePairCounter(
@@ -545,6 +543,7 @@
worker_thread,
port_allocator,
rtc::ToString(rtc::CreateRandomId64() & LLONG_MAX),
+ cricket::NS_JINGLE_RTP,
false),
// RFC 3264: The numeric value of the session id and version in the
// o line MUST be representable with a "64 bit signed integer".
@@ -559,14 +558,6 @@
data_channel_type_(cricket::DCT_NONE),
ice_restart_latch_(new IceRestartAnswerLatch),
metrics_observer_(NULL) {
- transport_controller()->SignalConnectionState.connect(
- this, &WebRtcSession::OnTransportControllerConnectionState);
- transport_controller()->SignalReceiving.connect(
- this, &WebRtcSession::OnTransportControllerReceiving);
- transport_controller()->SignalGatheringState.connect(
- this, &WebRtcSession::OnTransportControllerGatheringState);
- transport_controller()->SignalCandidatesGathered.connect(
- this, &WebRtcSession::OnTransportControllerCandidatesGathered);
}
WebRtcSession::~WebRtcSession() {
@@ -592,12 +583,12 @@
bool WebRtcSession::Initialize(
const PeerConnectionFactoryInterface::Options& options,
- const MediaConstraintsInterface* constraints,
+ const MediaConstraintsInterface* constraints,
rtc::scoped_ptr<DtlsIdentityStoreInterface> dtls_identity_store,
const PeerConnectionInterface::RTCConfiguration& rtc_configuration) {
bundle_policy_ = rtc_configuration.bundle_policy;
rtcp_mux_policy_ = rtc_configuration.rtcp_mux_policy;
- transport_controller()->SetSslMaxProtocolVersion(options.ssl_max_version);
+ SetSslMaxProtocolVersion(options.ssl_max_version);
// Obtain a certificate from RTCConfiguration if any were provided (optional).
rtc::scoped_refptr<rtc::RTCCertificate> certificate;
@@ -622,8 +613,10 @@
// Enable DTLS by default if we have an identity store or a certificate.
dtls_enabled_ = (dtls_identity_store || certificate);
// |constraints| can override the default |dtls_enabled_| value.
- if (FindConstraint(constraints, MediaConstraintsInterface::kEnableDtlsSrtp,
- &value, nullptr)) {
+ if (FindConstraint(
+ constraints,
+ MediaConstraintsInterface::kEnableDtlsSrtp,
+ &value, nullptr)) {
dtls_enabled_ = value;
}
}
@@ -743,21 +736,35 @@
if (!dtls_enabled_) {
// Construct with DTLS disabled.
webrtc_session_desc_factory_.reset(new WebRtcSessionDescriptionFactory(
- signaling_thread(), channel_manager_, mediastream_signaling_, this,
- id(), data_channel_type_));
+ signaling_thread(),
+ channel_manager_,
+ mediastream_signaling_,
+ this,
+ id(),
+ data_channel_type_));
} else {
// Construct with DTLS enabled.
if (!certificate) {
// Use the |dtls_identity_store| to generate a certificate.
RTC_DCHECK(dtls_identity_store);
webrtc_session_desc_factory_.reset(new WebRtcSessionDescriptionFactory(
- signaling_thread(), channel_manager_, mediastream_signaling_,
- dtls_identity_store.Pass(), this, id(), data_channel_type_));
+ signaling_thread(),
+ channel_manager_,
+ mediastream_signaling_,
+ dtls_identity_store.Pass(),
+ this,
+ id(),
+ data_channel_type_));
} else {
// Use the already generated certificate.
webrtc_session_desc_factory_.reset(new WebRtcSessionDescriptionFactory(
- signaling_thread(), channel_manager_, mediastream_signaling_,
- certificate, this, id(), data_channel_type_));
+ signaling_thread(),
+ channel_manager_,
+ mediastream_signaling_,
+ certificate,
+ this,
+ id(),
+ data_channel_type_));
}
}
@@ -784,12 +791,26 @@
void WebRtcSession::Terminate() {
SetState(STATE_RECEIVEDTERMINATE);
- RemoveUnusedChannels(NULL);
+ RemoveUnusedChannelsAndTransports(NULL);
ASSERT(!voice_channel_);
ASSERT(!video_channel_);
ASSERT(!data_channel_);
}
+bool WebRtcSession::StartCandidatesAllocation() {
+ // SpeculativelyConnectTransportChannels, will call ConnectChannels method
+ // from TransportProxy to start gathering ice candidates.
+ SpeculativelyConnectAllTransportChannels();
+ if (!saved_candidates_.empty()) {
+ // If there are saved candidates which arrived before local description is
+ // set, copy those to remote description.
+ CopySavedCandidates(remote_desc_.get());
+ }
+ // Push remote candidates present in remote description to transport channels.
+ UseCandidatesInSessionDescription(remote_desc_.get());
+ return true;
+}
+
void WebRtcSession::SetSdesPolicy(cricket::SecurePolicy secure_policy) {
webrtc_session_desc_factory_->SetSdesPolicy(secure_policy);
}
@@ -805,7 +826,17 @@
return false;
}
- return transport_controller()->GetSslRole(role);
+ // TODO(mallinath) - Return role of each transport, as role may differ from
+ // one another.
+ // In current implementaion we just return the role of first transport in the
+ // transport map.
+ for (cricket::TransportMap::const_iterator iter = transport_proxies().begin();
+ iter != transport_proxies().end(); ++iter) {
+ if (iter->second->impl()) {
+ return iter->second->impl()->GetSslRole(role);
+ }
+ }
+ return false;
}
void WebRtcSession::CreateOffer(
@@ -821,8 +852,6 @@
bool WebRtcSession::SetLocalDescription(SessionDescriptionInterface* desc,
std::string* err_desc) {
- ASSERT(signaling_thread()->IsCurrent());
-
// Takes the ownership of |desc| regardless of the result.
rtc::scoped_ptr<SessionDescriptionInterface> desc_temp(desc);
@@ -855,24 +884,16 @@
return BadLocalSdp(desc->type(), kCreateChannelFailed, err_desc);
}
- // Remove unused channels if MediaContentDescription is rejected.
- RemoveUnusedChannels(local_desc_->description());
+ // Remove channel and transport proxies, if MediaContentDescription is
+ // rejected.
+ RemoveUnusedChannelsAndTransports(local_desc_->description());
if (!UpdateSessionState(action, cricket::CS_LOCAL, err_desc)) {
return false;
}
- if (remote_description()) {
- // Now that we have a local description, we can push down remote candidates
- // that we stored, and those from the remote description.
- if (!saved_candidates_.empty()) {
- // If there are saved candidates which arrived before the local
- // description was set, copy those to the remote description.
- CopySavedCandidates(remote_desc_.get());
- }
- // Push remote candidates in remote description to transport channels.
- UseCandidatesInSessionDescription(remote_desc_.get());
- }
+ // Kick starting the ice candidates allocation.
+ StartCandidatesAllocation();
// Update state and SSRC of local MediaStreams and DataChannels based on the
// local session description.
@@ -890,8 +911,6 @@
bool WebRtcSession::SetRemoteDescription(SessionDescriptionInterface* desc,
std::string* err_desc) {
- ASSERT(signaling_thread()->IsCurrent());
-
// Takes the ownership of |desc| regardless of the result.
rtc::scoped_ptr<SessionDescriptionInterface> desc_temp(desc);
@@ -908,8 +927,9 @@
return BadRemoteSdp(desc->type(), kCreateChannelFailed, err_desc);
}
- // Remove unused channels if MediaContentDescription is rejected.
- RemoveUnusedChannels(desc->description());
+ // Remove channel and transport proxies, if MediaContentDescription is
+ // rejected.
+ RemoveUnusedChannelsAndTransports(desc->description());
// NOTE: Candidates allocation will be initiated only when SetLocalDescription
// is called.
@@ -968,8 +988,6 @@
bool WebRtcSession::UpdateSessionState(
Action action, cricket::ContentSource source,
std::string* err_desc) {
- ASSERT(signaling_thread()->IsCurrent());
-
// If there's already a pending error then no state transition should happen.
// But all call-sites should be verifying this before calling us!
ASSERT(error() == cricket::BaseSession::ERROR_NONE);
@@ -1003,21 +1021,7 @@
if (!PushdownTransportDescription(source, cricket::CA_ANSWER, &td_err)) {
return BadAnswerSdp(source, MakeTdErrorString(td_err), err_desc);
}
- const cricket::ContentGroup* local_bundle =
- BaseSession::local_description()->GetGroupByName(
- cricket::GROUP_TYPE_BUNDLE);
- const cricket::ContentGroup* remote_bundle =
- BaseSession::remote_description()->GetGroupByName(
- cricket::GROUP_TYPE_BUNDLE);
- if (local_bundle && remote_bundle) {
- // The answerer decides the transport to bundle on
- const cricket::ContentGroup* answer_bundle =
- (source == cricket::CS_LOCAL ? local_bundle : remote_bundle);
- if (!EnableBundle(*answer_bundle)) {
- LOG(LS_WARNING) << "Failed to enable BUNDLE.";
- return BadAnswerSdp(source, kEnableBundleFailed, err_desc);
- }
- }
+ MaybeEnableMuxingSupport();
EnableChannels();
SetState(source == cricket::CS_LOCAL ?
STATE_SENTACCEPT : STATE_RECEIVEDACCEPT);
@@ -1066,101 +1070,32 @@
bool WebRtcSession::GetTransportStats(cricket::SessionStats* stats) {
ASSERT(signaling_thread()->IsCurrent());
- return (GetChannelTransportStats(voice_channel(), stats) &&
- GetChannelTransportStats(video_channel(), stats) &&
- GetChannelTransportStats(data_channel(), stats));
-}
-bool WebRtcSession::GetChannelTransportStats(cricket::BaseChannel* ch,
- cricket::SessionStats* stats) {
- ASSERT(signaling_thread()->IsCurrent());
- if (!ch) {
- // Not using this channel.
- return true;
- }
-
- const std::string& content_name = ch->content_name();
- const std::string& transport_name = ch->transport_name();
- stats->proxy_to_transport[content_name] = transport_name;
- if (stats->transport_stats.find(transport_name) !=
- stats->transport_stats.end()) {
- // Transport stats already done for this transport.
- return true;
- }
-
- cricket::TransportStats tstats;
- if (!transport_controller()->GetStats(transport_name, &tstats)) {
- return false;
- }
-
- stats->transport_stats[transport_name] = tstats;
- return true;
-}
-
-bool WebRtcSession::GetLocalCertificate(
- const std::string& transport_name,
- rtc::scoped_refptr<rtc::RTCCertificate>* certificate) {
- ASSERT(signaling_thread()->IsCurrent());
- return transport_controller()->GetLocalCertificate(transport_name,
- certificate);
-}
-
-bool WebRtcSession::GetRemoteSSLCertificate(const std::string& transport_name,
- rtc::SSLCertificate** cert) {
- ASSERT(signaling_thread()->IsCurrent());
- return transport_controller()->GetRemoteSSLCertificate(transport_name, cert);
-}
-
-cricket::BaseChannel* WebRtcSession::GetChannel(
- const std::string& content_name) {
- if (voice_channel() && voice_channel()->content_name() == content_name) {
- return voice_channel();
- }
- if (video_channel() && video_channel()->content_name() == content_name) {
- return video_channel();
- }
- if (data_channel() && data_channel()->content_name() == content_name) {
- return data_channel();
- }
- return nullptr;
-}
-
-bool WebRtcSession::EnableBundle(const cricket::ContentGroup& bundle) {
- const std::string* first_content_name = bundle.FirstContentName();
- if (!first_content_name) {
- LOG(LS_WARNING) << "Tried to BUNDLE with no contents.";
- return false;
- }
- const std::string& transport_name = *first_content_name;
- cricket::BaseChannel* first_channel = GetChannel(transport_name);
-
- auto maybe_set_transport = [this, bundle, transport_name,
- first_channel](cricket::BaseChannel* ch) {
- if (!ch || !bundle.HasContentName(ch->content_name())) {
+ const auto get_transport_stats = [stats](const std::string& content_name,
+ cricket::Transport* transport) {
+ const std::string& transport_id = transport->content_name();
+ stats->proxy_to_transport[content_name] = transport_id;
+ if (stats->transport_stats.find(transport_id)
+ != stats->transport_stats.end()) {
+ // Transport stats already done for this transport.
return true;
}
- if (ch->transport_name() == transport_name) {
- LOG(LS_INFO) << "BUNDLE already enabled for " << ch->content_name()
- << " on " << transport_name << ".";
- return true;
- }
-
- if (!ch->SetTransport(transport_name)) {
- LOG(LS_WARNING) << "Failed to enable BUNDLE for " << ch->content_name();
+ cricket::TransportStats tstats;
+ if (!transport->GetStats(&tstats)) {
return false;
}
- LOG(LS_INFO) << "Enabled BUNDLE for " << ch->content_name() << " on "
- << transport_name << ".";
+
+ stats->transport_stats[transport_id] = tstats;
return true;
};
- if (!maybe_set_transport(voice_channel()) ||
- !maybe_set_transport(video_channel()) ||
- !maybe_set_transport(data_channel())) {
- return false;
+ for (const auto& kv : transport_proxies()) {
+ cricket::Transport* transport = kv.second->impl();
+ if (transport && !get_transport_stats(kv.first, transport)) {
+ return false;
+ }
}
-
return true;
}
@@ -1466,18 +1401,13 @@
void WebRtcSession::OnCertificateReady(
const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) {
- transport_controller()->SetLocalCertificate(certificate);
+ SetCertificate(certificate);
}
bool WebRtcSession::waiting_for_certificate_for_testing() const {
return webrtc_session_desc_factory_->waiting_for_certificate_for_testing();
}
-const rtc::scoped_refptr<rtc::RTCCertificate>&
-WebRtcSession::certificate_for_testing() {
- return transport_controller()->certificate_for_testing();
-}
-
void WebRtcSession::SetIceConnectionState(
PeerConnectionInterface::IceConnectionState state) {
if (ice_connection_state_ == state) {
@@ -1488,8 +1418,6 @@
// WebRtcSession does not implement "kIceConnectionClosed" (that is handled
// within PeerConnection). This switch statement should compile away when
// ASSERTs are disabled.
- LOG(LS_INFO) << "Changing IceConnectionState " << ice_connection_state_
- << " => " << state;
switch (ice_connection_state_) {
case PeerConnectionInterface::kIceConnectionNew:
ASSERT(state == PeerConnectionInterface::kIceConnectionChecking);
@@ -1530,52 +1458,70 @@
}
}
-void WebRtcSession::OnTransportControllerConnectionState(
- cricket::IceConnectionState state) {
- switch (state) {
- case cricket::kIceConnectionConnecting:
- // If the current state is Connected or Completed, then there were
- // writable channels but now there are not, so the next state must
- // be Disconnected.
- // kIceConnectionConnecting is currently used as the default,
- // un-connected state by the TransportController, so its only use is
- // detecting disconnections.
- if (ice_connection_state_ ==
- PeerConnectionInterface::kIceConnectionConnected ||
- ice_connection_state_ ==
- PeerConnectionInterface::kIceConnectionCompleted) {
- SetIceConnectionState(
- PeerConnectionInterface::kIceConnectionDisconnected);
- }
- break;
- case cricket::kIceConnectionFailed:
- SetIceConnectionState(PeerConnectionInterface::kIceConnectionFailed);
- break;
- case cricket::kIceConnectionConnected:
- LOG(LS_INFO) << "Changing to ICE connected state because "
- << "all transports are writable.";
- SetIceConnectionState(PeerConnectionInterface::kIceConnectionConnected);
- break;
- case cricket::kIceConnectionCompleted:
- LOG(LS_INFO) << "Changing to ICE completed state because "
- << "all transports are complete.";
- if (ice_connection_state_ !=
- PeerConnectionInterface::kIceConnectionConnected) {
- // If jumping directly from "checking" to "connected",
- // signal "connected" first.
- SetIceConnectionState(PeerConnectionInterface::kIceConnectionConnected);
- }
- SetIceConnectionState(PeerConnectionInterface::kIceConnectionCompleted);
- if (metrics_observer_) {
- ReportTransportStats();
- }
- break;
- default:
- ASSERT(false);
+void WebRtcSession::OnTransportRequestSignaling(
+ cricket::Transport* transport) {
+ ASSERT(signaling_thread()->IsCurrent());
+ transport->OnSignalingReady();
+ if (ice_observer_) {
+ ice_observer_->OnIceGatheringChange(
+ PeerConnectionInterface::kIceGatheringGathering);
}
}
-void WebRtcSession::OnTransportControllerReceiving(bool receiving) {
+void WebRtcSession::OnTransportConnecting(cricket::Transport* transport) {
+ ASSERT(signaling_thread()->IsCurrent());
+ // start monitoring for the write state of the transport.
+ OnTransportWritable(transport);
+}
+
+void WebRtcSession::OnTransportWritable(cricket::Transport* transport) {
+ ASSERT(signaling_thread()->IsCurrent());
+ if (transport->all_channels_writable()) {
+ SetIceConnectionState(PeerConnectionInterface::kIceConnectionConnected);
+ } else if (transport->HasChannels()) {
+ // If the current state is Connected or Completed, then there were writable
+ // channels but now there are not, so the next state must be Disconnected.
+ if (ice_connection_state_ ==
+ PeerConnectionInterface::kIceConnectionConnected ||
+ ice_connection_state_ ==
+ PeerConnectionInterface::kIceConnectionCompleted) {
+ SetIceConnectionState(
+ PeerConnectionInterface::kIceConnectionDisconnected);
+ }
+ }
+}
+
+void WebRtcSession::OnTransportCompleted(cricket::Transport* transport) {
+ ASSERT(signaling_thread()->IsCurrent());
+ PeerConnectionInterface::IceConnectionState old_state = ice_connection_state_;
+ SetIceConnectionState(PeerConnectionInterface::kIceConnectionCompleted);
+ // Only report once when Ice connection is completed.
+ if (old_state != PeerConnectionInterface::kIceConnectionCompleted) {
+ cricket::TransportStats stats;
+ if (metrics_observer_ && transport->GetStats(&stats)) {
+ ReportBestConnectionState(stats);
+ ReportNegotiatedCiphers(stats);
+ }
+ }
+}
+
+void WebRtcSession::OnTransportFailed(cricket::Transport* transport) {
+ ASSERT(signaling_thread()->IsCurrent());
+ SetIceConnectionState(PeerConnectionInterface::kIceConnectionFailed);
+}
+
+void WebRtcSession::OnTransportReceiving(cricket::Transport* transport) {
+ ASSERT(signaling_thread()->IsCurrent());
+ // The ice connection is considered receiving if at least one transport is
+ // receiving on any channels.
+ bool receiving = false;
+ for (const auto& kv : transport_proxies()) {
+ cricket::Transport* transport = kv.second->impl();
+ if (transport && transport->any_channel_receiving()) {
+ receiving = true;
+ break;
+ }
+ }
SetIceConnectionReceiving(receiving);
}
@@ -1589,27 +1535,18 @@
}
}
-void WebRtcSession::OnTransportControllerCandidatesGathered(
- const std::string& transport_name,
- const cricket::Candidates& candidates) {
+void WebRtcSession::OnTransportProxyCandidatesReady(
+ cricket::TransportProxy* proxy, const cricket::Candidates& candidates) {
ASSERT(signaling_thread()->IsCurrent());
- int sdp_mline_index;
- if (!GetLocalCandidateMediaIndex(transport_name, &sdp_mline_index)) {
- LOG(LS_ERROR) << "OnTransportControllerCandidatesGathered: content name "
- << transport_name << " not found";
- return;
- }
+ ProcessNewLocalCandidate(proxy->content_name(), candidates);
+}
- for (cricket::Candidates::const_iterator citer = candidates.begin();
- citer != candidates.end(); ++citer) {
- // Use transport_name as the candidate media id.
- JsepIceCandidate candidate(transport_name, sdp_mline_index, *citer);
- if (ice_observer_) {
- ice_observer_->OnIceCandidate(&candidate);
- }
- if (local_desc_) {
- local_desc_->AddCandidate(&candidate);
- }
+void WebRtcSession::OnCandidatesAllocationDone() {
+ ASSERT(signaling_thread()->IsCurrent());
+ if (ice_observer_) {
+ ice_observer_->OnIceGatheringChange(
+ PeerConnectionInterface::kIceGatheringComplete);
+ ice_observer_->OnIceComplete();
}
}
@@ -1625,6 +1562,29 @@
data_channel_->Enable(true);
}
+void WebRtcSession::ProcessNewLocalCandidate(
+ const std::string& content_name,
+ const cricket::Candidates& candidates) {
+ int sdp_mline_index;
+ if (!GetLocalCandidateMediaIndex(content_name, &sdp_mline_index)) {
+ LOG(LS_ERROR) << "ProcessNewLocalCandidate: content name "
+ << content_name << " not found";
+ return;
+ }
+
+ for (cricket::Candidates::const_iterator citer = candidates.begin();
+ citer != candidates.end(); ++citer) {
+ // Use content_name as the candidate media id.
+ JsepIceCandidate candidate(content_name, sdp_mline_index, *citer);
+ if (ice_observer_) {
+ ice_observer_->OnIceCandidate(&candidate);
+ }
+ if (local_desc_) {
+ local_desc_->AddCandidate(&candidate);
+ }
+ }
+}
+
// Returns the media index for a local ice candidate given the content name.
bool WebRtcSession::GetLocalCandidateMediaIndex(const std::string& content_name,
int* sdp_mline_index) {
@@ -1689,8 +1649,7 @@
candidates.push_back(candidate->candidate());
// Invoking BaseSession method to handle remote candidates.
std::string error;
- if (transport_controller()->AddRemoteCandidates(content.name, candidates,
- &error)) {
+ if (OnRemoteCandidates(content.name, candidates, &error)) {
// Candidates successfully submitted for checking.
if (ice_connection_state_ == PeerConnectionInterface::kIceConnectionNew ||
ice_connection_state_ ==
@@ -1714,7 +1673,8 @@
return true;
}
-void WebRtcSession::RemoveUnusedChannels(const SessionDescription* desc) {
+void WebRtcSession::RemoveUnusedChannelsAndTransports(
+ const SessionDescription* desc) {
// Destroy video_channel_ first since it may have a pointer to the
// voice_channel_.
const cricket::ContentInfo* video_info =
@@ -1724,6 +1684,7 @@
SignalVideoChannelDestroyed();
const std::string content_name = video_channel_->content_name();
channel_manager_->DestroyVideoChannel(video_channel_.release());
+ DestroyTransportProxy(content_name);
}
const cricket::ContentInfo* voice_info =
@@ -1733,6 +1694,7 @@
SignalVoiceChannelDestroyed();
const std::string content_name = voice_channel_->content_name();
channel_manager_->DestroyVoiceChannel(voice_channel_.release());
+ DestroyTransportProxy(content_name);
}
const cricket::ContentInfo* data_info =
@@ -1742,6 +1704,7 @@
SignalDataChannelDestroyed();
const std::string content_name = data_channel_->content_name();
channel_manager_->DestroyDataChannel(data_channel_.release());
+ DestroyTransportProxy(content_name);
}
}
@@ -1786,7 +1749,7 @@
}
}
- // Enable BUNDLE immediately when kBundlePolicyMaxBundle is in effect.
+ // Enable bundle before when kMaxBundle policy is in effect.
if (bundle_policy_ == PeerConnectionInterface::kBundlePolicyMaxBundle) {
const cricket::ContentGroup* bundle_group = desc->GetGroupByName(
cricket::GROUP_TYPE_BUNDLE);
@@ -1794,7 +1757,7 @@
LOG(LS_WARNING) << "max-bundle specified without BUNDLE specified";
return false;
}
- if (!EnableBundle(*bundle_group)) {
+ if (!BaseSession::BundleContentGroup(bundle_group)) {
LOG(LS_WARNING) << "max-bundle failed to enable bundling.";
return false;
}
@@ -1805,8 +1768,7 @@
bool WebRtcSession::CreateVoiceChannel(const cricket::ContentInfo* content) {
voice_channel_.reset(channel_manager_->CreateVoiceChannel(
- media_controller_.get(), transport_controller(), content->name, true,
- audio_options_));
+ media_controller_.get(), this, content->name, true, audio_options_));
if (!voice_channel_) {
return false;
}
@@ -1818,8 +1780,7 @@
bool WebRtcSession::CreateVideoChannel(const cricket::ContentInfo* content) {
video_channel_.reset(channel_manager_->CreateVideoChannel(
- media_controller_.get(), transport_controller(), content->name, true,
- video_options_));
+ media_controller_.get(), this, content->name, true, video_options_));
if (!video_channel_) {
return false;
}
@@ -1832,7 +1793,7 @@
bool WebRtcSession::CreateDataChannel(const cricket::ContentInfo* content) {
bool sctp = (data_channel_type_ == cricket::DCT_SCTP);
data_channel_.reset(channel_manager_->CreateDataChannel(
- transport_controller(), content->name, !sctp, data_channel_type_));
+ this, content->name, !sctp, data_channel_type_));
if (!data_channel_) {
return false;
}
@@ -2013,6 +1974,7 @@
const SessionDescriptionInterface* remote_desc,
bool* valid) {
*valid = true;;
+ cricket::TransportProxy* transport_proxy = NULL;
const SessionDescriptionInterface* current_remote_desc =
remote_desc ? remote_desc : remote_description();
@@ -2034,53 +1996,12 @@
cricket::ContentInfo content =
current_remote_desc->description()->contents()[mediacontent_index];
- cricket::BaseChannel* channel = GetChannel(content.name);
- if (!channel) {
- return false;
- }
+ transport_proxy = GetTransportProxy(content.name);
- return transport_controller()->ReadyForRemoteCandidates(
- channel->transport_name());
+ return transport_proxy && transport_proxy->local_description_set() &&
+ transport_proxy->remote_description_set();
}
-void WebRtcSession::OnTransportControllerGatheringState(
- cricket::IceGatheringState state) {
- ASSERT(signaling_thread()->IsCurrent());
- if (state == cricket::kIceGatheringGathering) {
- if (ice_observer_) {
- ice_observer_->OnIceGatheringChange(
- PeerConnectionInterface::kIceGatheringGathering);
- }
- } else if (state == cricket::kIceGatheringComplete) {
- if (ice_observer_) {
- ice_observer_->OnIceGatheringChange(
- PeerConnectionInterface::kIceGatheringComplete);
- ice_observer_->OnIceComplete();
- }
- }
-}
-
-void WebRtcSession::ReportTransportStats() {
- // Use a set so we don't report the same stats twice if two channels share
- // a transport.
- std::set<std::string> transport_names;
- if (voice_channel()) {
- transport_names.insert(voice_channel()->transport_name());
- }
- if (video_channel()) {
- transport_names.insert(video_channel()->transport_name());
- }
- if (data_channel()) {
- transport_names.insert(data_channel()->transport_name());
- }
- for (const auto& name : transport_names) {
- cricket::TransportStats stats;
- if (transport_controller()->GetStats(name, &stats)) {
- ReportBestConnectionState(stats);
- ReportNegotiatedCiphers(stats);
- }
- }
-}
// Walk through the ConnectionInfos to gather best connection usage
// for IPv4 and IPv6.
void WebRtcSession::ReportBestConnectionState(
@@ -2148,13 +2069,13 @@
PeerConnectionMetricsName srtp_name;
PeerConnectionMetricsName ssl_name;
- if (stats.transport_name == cricket::CN_AUDIO) {
+ if (stats.content_name == cricket::CN_AUDIO) {
srtp_name = kAudioSrtpCipher;
ssl_name = kAudioSslCipher;
- } else if (stats.transport_name == cricket::CN_VIDEO) {
+ } else if (stats.content_name == cricket::CN_VIDEO) {
srtp_name = kVideoSrtpCipher;
ssl_name = kVideoSslCipher;
- } else if (stats.transport_name == cricket::CN_DATA) {
+ } else if (stats.content_name == cricket::CN_DATA) {
srtp_name = kDataSrtpCipher;
ssl_name = kDataSslCipher;
} else {
diff --git a/talk/app/webrtc/webrtcsession.h b/talk/app/webrtc/webrtcsession.h
index 1ad9a69..582d6d0 100644
--- a/talk/app/webrtc/webrtcsession.h
+++ b/talk/app/webrtc/webrtcsession.h
@@ -29,7 +29,6 @@
#define TALK_APP_WEBRTC_WEBRTCSESSION_H_
#include <string>
-#include <vector>
#include "talk/app/webrtc/datachannel.h"
#include "talk/app/webrtc/dtmfsender.h"
@@ -50,6 +49,7 @@
class ChannelManager;
class DataChannel;
class StatsReport;
+class Transport;
class VideoCapturer;
class VideoChannel;
class VoiceChannel;
@@ -77,8 +77,6 @@
extern const char kSessionErrorDesc[];
extern const char kDtlsSetupFailureRtp[];
extern const char kDtlsSetupFailureRtcp[];
-extern const char kEnableBundleFailed[];
-
// Maximum number of received video streams that will be processed by webrtc
// even if they are not signalled beforehand.
extern const int kMaxUnsignalledRecvStreams;
@@ -237,19 +235,6 @@
// This avoids exposing the internal structures used to track them.
virtual bool GetTransportStats(cricket::SessionStats* stats);
- // Get stats for a specific channel
- bool GetChannelTransportStats(cricket::BaseChannel* ch,
- cricket::SessionStats* stats);
-
- // virtual so it can be mocked in unit tests
- virtual bool GetLocalCertificate(
- const std::string& transport_name,
- rtc::scoped_refptr<rtc::RTCCertificate>* certificate);
-
- // Caller owns returned certificate
- virtual bool GetRemoteSSLCertificate(const std::string& transport_name,
- rtc::SSLCertificate** cert);
-
// Implements DataChannelFactory.
rtc::scoped_refptr<DataChannel> CreateDataChannel(
const std::string& label,
@@ -269,7 +254,6 @@
// For unit test.
bool waiting_for_certificate_for_testing() const;
- const rtc::scoped_refptr<rtc::RTCCertificate>& certificate_for_testing();
void set_metrics_observer(
webrtc::MetricsObserverInterface* metrics_observer) {
@@ -285,6 +269,9 @@
kAnswer,
};
+ // Invokes ConnectChannels() on transport proxies, which initiates ice
+ // candidates allocation.
+ bool StartCandidatesAllocation();
bool UpdateSessionState(Action action, cricket::ContentSource source,
std::string* err_desc);
static Action GetAction(const std::string& type);
@@ -294,13 +281,25 @@
cricket::ContentSource source,
std::string* error_desc);
- cricket::BaseChannel* GetChannel(const std::string& content_name);
- // Cause all the BaseChannels in the bundle group to have the same
- // transport channel.
- bool EnableBundle(const cricket::ContentGroup& bundle);
+
+ // Transport related callbacks, override from cricket::BaseSession.
+ virtual void OnTransportRequestSignaling(cricket::Transport* transport);
+ virtual void OnTransportConnecting(cricket::Transport* transport);
+ virtual void OnTransportWritable(cricket::Transport* transport);
+ virtual void OnTransportCompleted(cricket::Transport* transport);
+ virtual void OnTransportFailed(cricket::Transport* transport);
+ virtual void OnTransportProxyCandidatesReady(
+ cricket::TransportProxy* proxy,
+ const cricket::Candidates& candidates);
+ virtual void OnCandidatesAllocationDone();
+ void OnTransportReceiving(cricket::Transport* transport) override;
// Enables media channels to allow sending of media.
void EnableChannels();
+ // Creates a JsepIceCandidate and adds it to the local session description
+ // and notify observers. Called when a new local candidate have been found.
+ void ProcessNewLocalCandidate(const std::string& content_name,
+ const cricket::Candidates& candidates);
// Returns the media index for a local ice candidate given the content name.
// Returns false if the local session description does not have a media
// content called |content_name|.
@@ -313,7 +312,8 @@
bool UseCandidate(const IceCandidateInterface* candidate);
// Deletes the corresponding channel of contents that don't exist in |desc|.
// |desc| can be null. This means that all channels are deleted.
- void RemoveUnusedChannels(const cricket::SessionDescription* desc);
+ void RemoveUnusedChannelsAndTransports(
+ const cricket::SessionDescription* desc);
// Allocates media channels based on the |desc|. If |desc| doesn't have
// the BUNDLE option, this method will disable BUNDLE in PortAllocator.
@@ -362,20 +362,10 @@
const SessionDescriptionInterface* remote_desc,
bool* valid);
- void OnTransportControllerConnectionState(cricket::IceConnectionState state);
- void OnTransportControllerReceiving(bool receiving);
- void OnTransportControllerGatheringState(cricket::IceGatheringState state);
- void OnTransportControllerCandidatesGathered(
- const std::string& transport_name,
- const cricket::Candidates& candidates);
-
std::string GetSessionErrorMsg();
- // Invoked when TransportController connection completion is signaled.
- // Reports stats for all transports in use.
- void ReportTransportStats();
-
- // Gather the usage of IPv4/IPv6 as best connection.
+ // Invoked when OnTransportCompleted is signaled to gather the usage
+ // of IPv4/IPv6 as best connection.
void ReportBestConnectionState(const cricket::TransportStats& stats);
void ReportNegotiatedCiphers(const cricket::TransportStats& stats);
diff --git a/talk/app/webrtc/webrtcsession_unittest.cc b/talk/app/webrtc/webrtcsession_unittest.cc
index 66704a2..8bd97e5 100644
--- a/talk/app/webrtc/webrtcsession_unittest.cc
+++ b/talk/app/webrtc/webrtcsession_unittest.cc
@@ -25,8 +25,6 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <vector>
-
#include "talk/app/webrtc/audiotrack.h"
#include "talk/app/webrtc/fakemetricsobserver.h"
#include "talk/app/webrtc/jsepicecandidate.h"
@@ -165,8 +163,8 @@
const std::string& newlines,
std::string* message) {
const std::string tmp = line + newlines;
- rtc::replace_substrs(line.c_str(), line.length(), tmp.c_str(), tmp.length(),
- message);
+ rtc::replace_substrs(line.c_str(), line.length(),
+ tmp.c_str(), tmp.length(), message);
}
class MockIceObserver : public webrtc::IceObserver {
@@ -246,52 +244,12 @@
}
virtual ~WebRtcSessionForTest() {}
- // Note that these methods are only safe to use if the signaling thread
- // is the same as the worker thread
- cricket::TransportChannel* voice_rtp_transport_channel() {
- return rtp_transport_channel(voice_channel());
- }
-
- cricket::TransportChannel* voice_rtcp_transport_channel() {
- return rtcp_transport_channel(voice_channel());
- }
-
- cricket::TransportChannel* video_rtp_transport_channel() {
- return rtp_transport_channel(video_channel());
- }
-
- cricket::TransportChannel* video_rtcp_transport_channel() {
- return rtcp_transport_channel(video_channel());
- }
-
- cricket::TransportChannel* data_rtp_transport_channel() {
- return rtp_transport_channel(data_channel());
- }
-
- cricket::TransportChannel* data_rtcp_transport_channel() {
- return rtcp_transport_channel(data_channel());
- }
-
+ using cricket::BaseSession::GetTransportProxy;
using webrtc::WebRtcSession::SetAudioPlayout;
using webrtc::WebRtcSession::SetAudioSend;
using webrtc::WebRtcSession::SetCaptureDevice;
using webrtc::WebRtcSession::SetVideoPlayout;
using webrtc::WebRtcSession::SetVideoSend;
-
- private:
- cricket::TransportChannel* rtp_transport_channel(cricket::BaseChannel* ch) {
- if (!ch) {
- return nullptr;
- }
- return ch->transport_channel();
- }
-
- cricket::TransportChannel* rtcp_transport_channel(cricket::BaseChannel* ch) {
- if (!ch) {
- return nullptr;
- }
- return ch->rtcp_transport_channel();
- }
};
class WebRtcSessionCreateSDPObserverForTest
@@ -417,9 +375,9 @@
EXPECT_EQ(PeerConnectionInterface::kIceGatheringNew,
observer_.ice_gathering_state_);
- EXPECT_TRUE(session_->Initialize(options_, constraints_.get(),
- dtls_identity_store.Pass(),
- rtc_configuration));
+ EXPECT_TRUE(session_->Initialize(
+ options_, constraints_.get(), dtls_identity_store.Pass(),
+ rtc_configuration));
session_->set_metrics_observer(metrics_observer_);
}
@@ -532,6 +490,13 @@
session_->video_channel() != NULL);
}
+ void CheckTransportChannels() const {
+ EXPECT_TRUE(session_->GetChannel(cricket::CN_AUDIO, 1) != NULL);
+ EXPECT_TRUE(session_->GetChannel(cricket::CN_AUDIO, 2) != NULL);
+ EXPECT_TRUE(session_->GetChannel(cricket::CN_VIDEO, 1) != NULL);
+ EXPECT_TRUE(session_->GetChannel(cricket::CN_VIDEO, 2) != NULL);
+ }
+
void VerifyCryptoParams(const cricket::SessionDescription* sdp) {
ASSERT_TRUE(session_.get() != NULL);
const cricket::ContentInfo* content = cricket::GetFirstAudioContent(sdp);
@@ -1003,10 +968,15 @@
SetRemoteDescriptionWithoutError(new_answer);
EXPECT_TRUE_WAIT(observer_.oncandidatesready_, kIceCandidatesTimeout);
EXPECT_EQ(expected_candidate_num, observer_.mline_0_candidates_.size());
- if (bundle) {
- EXPECT_EQ(0, observer_.mline_1_candidates_.size());
- } else {
- EXPECT_EQ(expected_candidate_num, observer_.mline_1_candidates_.size());
+ EXPECT_EQ(expected_candidate_num, observer_.mline_1_candidates_.size());
+ for (size_t i = 0; i < observer_.mline_0_candidates_.size(); ++i) {
+ cricket::Candidate c0 = observer_.mline_0_candidates_[i];
+ cricket::Candidate c1 = observer_.mline_1_candidates_[i];
+ if (bundle) {
+ EXPECT_TRUE(c0.IsEquivalent(c1));
+ } else {
+ EXPECT_FALSE(c0.IsEquivalent(c1));
+ }
}
}
// Tests that we can only send DTMF when the dtmf codec is supported.
@@ -1031,7 +1001,7 @@
// initial ICE convergences.
class LoopbackNetworkConfiguration {
- public:
+ public:
LoopbackNetworkConfiguration()
: test_ipv6_network_(false),
test_extra_ipv4_network_(false),
@@ -1180,8 +1150,11 @@
// Clearing the rules, session should move back to completed state.
loopback_network_manager.ClearRules(fss_.get());
+ // Session is automatically calling OnSignalingReady after creation of
+ // new portallocator session which will allocate new set of candidates.
LOG(LS_INFO) << "Firewall Rules cleared";
+
EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionCompleted,
observer_.ice_connection_state_,
kIceCandidatesTimeout);
@@ -1734,14 +1707,15 @@
// a DTLS fingerprint when DTLS is required.
TEST_P(WebRtcSessionTest, TestSetRemoteNonDtlsAnswerWhenDtlsOn) {
MAYBE_SKIP_TEST(rtc::SSLStreamAdapter::HaveDtlsSrtp);
+ // Enable both SDES and DTLS, so that offer won't be outright rejected as a
+ // result of using the "UDP/TLS/RTP/SAVPF" profile.
InitWithDtls(GetParam());
+ session_->SetSdesPolicy(cricket::SEC_ENABLED);
SessionDescriptionInterface* offer = CreateOffer();
cricket::MediaSessionOptions options;
options.recv_video = true;
- rtc::scoped_ptr<SessionDescriptionInterface> temp_offer(
- CreateRemoteOffer(options, cricket::SEC_ENABLED));
JsepSessionDescription* answer =
- CreateRemoteAnswer(temp_offer.get(), options, cricket::SEC_ENABLED);
+ CreateRemoteAnswer(offer, options, cricket::SEC_ENABLED);
// SetRemoteDescription and SetLocalDescription will take the ownership of
// the offer and answer.
@@ -2043,7 +2017,7 @@
EXPECT_LT(0u, candidates->count());
candidates = local_desc->candidates(1);
ASSERT_TRUE(candidates != NULL);
- EXPECT_EQ(0u, candidates->count());
+ EXPECT_LT(0u, candidates->count());
// Update the session descriptions.
mediastream_signaling_.SendAudioVideoStream1();
@@ -2055,7 +2029,7 @@
EXPECT_LT(0u, candidates->count());
candidates = local_desc->candidates(1);
ASSERT_TRUE(candidates != NULL);
- EXPECT_EQ(0u, candidates->count());
+ EXPECT_LT(0u, candidates->count());
}
// Test that we can set a remote session description with remote candidates.
@@ -2099,17 +2073,23 @@
// Wait until at least one local candidate has been collected.
EXPECT_TRUE_WAIT(0u < observer_.mline_0_candidates_.size(),
kIceCandidatesTimeout);
+ EXPECT_TRUE_WAIT(0u < observer_.mline_1_candidates_.size(),
+ kIceCandidatesTimeout);
rtc::scoped_ptr<SessionDescriptionInterface> local_offer(CreateOffer());
ASSERT_TRUE(local_offer->candidates(kMediaContentIndex0) != NULL);
EXPECT_LT(0u, local_offer->candidates(kMediaContentIndex0)->count());
+ ASSERT_TRUE(local_offer->candidates(kMediaContentIndex1) != NULL);
+ EXPECT_LT(0u, local_offer->candidates(kMediaContentIndex1)->count());
SessionDescriptionInterface* remote_offer(CreateRemoteOffer());
SetRemoteDescriptionWithoutError(remote_offer);
SessionDescriptionInterface* answer = CreateAnswer(NULL);
ASSERT_TRUE(answer->candidates(kMediaContentIndex0) != NULL);
EXPECT_LT(0u, answer->candidates(kMediaContentIndex0)->count());
+ ASSERT_TRUE(answer->candidates(kMediaContentIndex1) != NULL);
+ EXPECT_LT(0u, answer->candidates(kMediaContentIndex1)->count());
SetLocalDescriptionWithoutError(answer);
}
@@ -2151,14 +2131,8 @@
CreateAnswer(NULL);
SetLocalDescriptionWithoutError(answer);
- cricket::TransportChannel* voice_transport_channel =
- session_->voice_rtp_transport_channel();
- EXPECT_TRUE(voice_transport_channel != NULL);
- EXPECT_EQ(voice_transport_channel->transport_name(), "audio_content_name");
- cricket::TransportChannel* video_transport_channel =
- session_->video_rtp_transport_channel();
- EXPECT_TRUE(video_transport_channel != NULL);
- EXPECT_EQ(video_transport_channel->transport_name(), "video_content_name");
+ EXPECT_TRUE(session_->GetTransportProxy("audio_content_name") != NULL);
+ EXPECT_TRUE(session_->GetTransportProxy("video_content_name") != NULL);
EXPECT_TRUE((video_channel_ = media_engine_->GetVideoChannel(0)) != NULL);
EXPECT_TRUE((voice_channel_ = media_engine_->GetVoiceChannel(0)) != NULL);
}
@@ -2718,23 +2692,20 @@
SessionDescriptionInterface* answer = CreateAnswer(NULL);
SetLocalDescriptionWithoutError(answer);
- EXPECT_EQ(session_->voice_rtp_transport_channel(),
- session_->video_rtp_transport_channel());
+ EXPECT_EQ(session_->GetTransportProxy("audio")->impl(),
+ session_->GetTransportProxy("video")->impl());
- cricket::BaseChannel* voice_channel = session_->voice_channel();
- ASSERT(voice_channel != NULL);
+ cricket::Transport* t = session_->GetTransport("audio");
// Checks if one of the transport channels contains a connection using a given
// port.
- auto connection_with_remote_port = [this, voice_channel](int port) {
- cricket::SessionStats stats;
- session_->GetChannelTransportStats(voice_channel, &stats);
- for (auto& kv : stats.transport_stats) {
- for (auto& chan_stat : kv.second.channel_stats) {
- for (auto& conn_info : chan_stat.connection_infos) {
- if (conn_info.remote_candidate.address().port() == port) {
- return true;
- }
+ auto connection_with_remote_port = [t](int port) {
+ cricket::TransportStats stats;
+ t->GetStats(&stats);
+ for (auto& chan_stat : stats.channel_stats) {
+ for (auto& conn_info : chan_stat.connection_infos) {
+ if (conn_info.remote_candidate.address().port() == port) {
+ return true;
}
}
}
@@ -2787,7 +2758,7 @@
EXPECT_FALSE(connection_with_remote_port(6000));
}
-// kBundlePolicyBalanced BUNDLE policy and answer contains BUNDLE.
+// kBundlePolicyBalanced bundle policy and answer contains BUNDLE.
TEST_F(WebRtcSessionTest, TestBalancedBundleInAnswer) {
InitWithBundlePolicy(PeerConnectionInterface::kBundlePolicyBalanced);
mediastream_signaling_.SendAudioVideoStream1();
@@ -2798,19 +2769,19 @@
SessionDescriptionInterface* offer = CreateOffer(options);
SetLocalDescriptionWithoutError(offer);
- EXPECT_NE(session_->voice_rtp_transport_channel(),
- session_->video_rtp_transport_channel());
+ EXPECT_NE(session_->GetTransportProxy("audio")->impl(),
+ session_->GetTransportProxy("video")->impl());
mediastream_signaling_.SendAudioVideoStream2();
SessionDescriptionInterface* answer =
CreateRemoteAnswer(session_->local_description());
SetRemoteDescriptionWithoutError(answer);
- EXPECT_EQ(session_->voice_rtp_transport_channel(),
- session_->video_rtp_transport_channel());
+ EXPECT_EQ(session_->GetTransportProxy("audio")->impl(),
+ session_->GetTransportProxy("video")->impl());
}
-// kBundlePolicyBalanced BUNDLE policy but no BUNDLE in the answer.
+// kBundlePolicyBalanced bundle policy but no BUNDLE in the answer.
TEST_F(WebRtcSessionTest, TestBalancedNoBundleInAnswer) {
InitWithBundlePolicy(PeerConnectionInterface::kBundlePolicyBalanced);
mediastream_signaling_.SendAudioVideoStream1();
@@ -2821,8 +2792,8 @@
SessionDescriptionInterface* offer = CreateOffer(options);
SetLocalDescriptionWithoutError(offer);
- EXPECT_NE(session_->voice_rtp_transport_channel(),
- session_->video_rtp_transport_channel());
+ EXPECT_NE(session_->GetTransportProxy("audio")->impl(),
+ session_->GetTransportProxy("video")->impl());
mediastream_signaling_.SendAudioVideoStream2();
@@ -2836,8 +2807,8 @@
modified_answer->Initialize(answer_copy, "1", "1");
SetRemoteDescriptionWithoutError(modified_answer); //
- EXPECT_NE(session_->voice_rtp_transport_channel(),
- session_->video_rtp_transport_channel());
+ EXPECT_NE(session_->GetTransportProxy("audio")->impl(),
+ session_->GetTransportProxy("video")->impl());
}
// kBundlePolicyMaxBundle policy with BUNDLE in the answer.
@@ -2851,49 +2822,16 @@
SessionDescriptionInterface* offer = CreateOffer(options);
SetLocalDescriptionWithoutError(offer);
- EXPECT_EQ(session_->voice_rtp_transport_channel(),
- session_->video_rtp_transport_channel());
+ EXPECT_EQ(session_->GetTransportProxy("audio")->impl(),
+ session_->GetTransportProxy("video")->impl());
mediastream_signaling_.SendAudioVideoStream2();
SessionDescriptionInterface* answer =
CreateRemoteAnswer(session_->local_description());
SetRemoteDescriptionWithoutError(answer);
- EXPECT_EQ(session_->voice_rtp_transport_channel(),
- session_->video_rtp_transport_channel());
-}
-
-// kBundlePolicyMaxBundle policy with BUNDLE in the answer, but no
-// audio content in the answer.
-TEST_F(WebRtcSessionTest, TestMaxBundleRejectAudio) {
- InitWithBundlePolicy(PeerConnectionInterface::kBundlePolicyMaxBundle);
- mediastream_signaling_.SendAudioVideoStream1();
-
- PeerConnectionInterface::RTCOfferAnswerOptions options;
- options.use_rtp_mux = true;
-
- SessionDescriptionInterface* offer = CreateOffer(options);
- SetLocalDescriptionWithoutError(offer);
-
- EXPECT_EQ(session_->voice_rtp_transport_channel(),
- session_->video_rtp_transport_channel());
-
- mediastream_signaling_.SendAudioVideoStream2();
- cricket::MediaSessionOptions recv_options;
- recv_options.recv_audio = false;
- recv_options.recv_video = true;
- SessionDescriptionInterface* answer =
- CreateRemoteAnswer(session_->local_description(), recv_options);
- SetRemoteDescriptionWithoutError(answer);
-
- EXPECT_TRUE(NULL == session_->voice_channel());
- EXPECT_TRUE(NULL != session_->video_rtp_transport_channel());
-
- session_->Terminate();
- EXPECT_TRUE(NULL == session_->voice_rtp_transport_channel());
- EXPECT_TRUE(NULL == session_->voice_rtcp_transport_channel());
- EXPECT_TRUE(NULL == session_->video_rtp_transport_channel());
- EXPECT_TRUE(NULL == session_->video_rtcp_transport_channel());
+ EXPECT_EQ(session_->GetTransportProxy("audio")->impl(),
+ session_->GetTransportProxy("video")->impl());
}
// kBundlePolicyMaxBundle policy but no BUNDLE in the answer.
@@ -2907,8 +2845,8 @@
SessionDescriptionInterface* offer = CreateOffer(options);
SetLocalDescriptionWithoutError(offer);
- EXPECT_EQ(session_->voice_rtp_transport_channel(),
- session_->video_rtp_transport_channel());
+ EXPECT_EQ(session_->GetTransportProxy("audio")->impl(),
+ session_->GetTransportProxy("video")->impl());
mediastream_signaling_.SendAudioVideoStream2();
@@ -2922,45 +2860,8 @@
modified_answer->Initialize(answer_copy, "1", "1");
SetRemoteDescriptionWithoutError(modified_answer);
- EXPECT_EQ(session_->voice_rtp_transport_channel(),
- session_->video_rtp_transport_channel());
-}
-
-// kBundlePolicyMaxBundle policy with BUNDLE in the remote offer.
-TEST_F(WebRtcSessionTest, TestMaxBundleBundleInRemoteOffer) {
- InitWithBundlePolicy(PeerConnectionInterface::kBundlePolicyMaxBundle);
- mediastream_signaling_.SendAudioVideoStream1();
-
- SessionDescriptionInterface* offer = CreateRemoteOffer();
- SetRemoteDescriptionWithoutError(offer);
-
- EXPECT_EQ(session_->voice_rtp_transport_channel(),
- session_->video_rtp_transport_channel());
-
- mediastream_signaling_.SendAudioVideoStream2();
- SessionDescriptionInterface* answer = CreateAnswer(nullptr);
- SetLocalDescriptionWithoutError(answer);
-
- EXPECT_EQ(session_->voice_rtp_transport_channel(),
- session_->video_rtp_transport_channel());
-}
-
-// kBundlePolicyMaxBundle policy but no BUNDLE in the remote offer.
-TEST_F(WebRtcSessionTest, TestMaxBundleNoBundleInRemoteOffer) {
- InitWithBundlePolicy(PeerConnectionInterface::kBundlePolicyMaxBundle);
- mediastream_signaling_.SendAudioVideoStream1();
-
- // Remove BUNDLE from the offer.
- rtc::scoped_ptr<SessionDescriptionInterface> offer(CreateRemoteOffer());
- cricket::SessionDescription* offer_copy = offer->description()->Copy();
- offer_copy->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
- JsepSessionDescription* modified_offer =
- new JsepSessionDescription(JsepSessionDescription::kOffer);
- modified_offer->Initialize(offer_copy, "1", "1");
-
- // Expect an error when applying the remote description
- SetRemoteDescriptionExpectError(JsepSessionDescription::kOffer,
- kCreateChannelFailed, modified_offer);
+ EXPECT_EQ(session_->GetTransportProxy("audio")->impl(),
+ session_->GetTransportProxy("video")->impl());
}
// kBundlePolicyMaxCompat bundle policy and answer contains BUNDLE.
@@ -2974,8 +2875,8 @@
SessionDescriptionInterface* offer = CreateOffer(options);
SetLocalDescriptionWithoutError(offer);
- EXPECT_NE(session_->voice_rtp_transport_channel(),
- session_->video_rtp_transport_channel());
+ EXPECT_NE(session_->GetTransportProxy("audio")->impl(),
+ session_->GetTransportProxy("video")->impl());
mediastream_signaling_.SendAudioVideoStream2();
SessionDescriptionInterface* answer =
@@ -2984,11 +2885,11 @@
// This should lead to an audio-only call but isn't implemented
// correctly yet.
- EXPECT_EQ(session_->voice_rtp_transport_channel(),
- session_->video_rtp_transport_channel());
+ EXPECT_EQ(session_->GetTransportProxy("audio")->impl(),
+ session_->GetTransportProxy("video")->impl());
}
-// kBundlePolicyMaxCompat BUNDLE policy but no BUNDLE in the answer.
+// kBundlePolicyMaxCompat bundle policy but no BUNDLE in the answer.
TEST_F(WebRtcSessionTest, TestMaxCompatNoBundleInAnswer) {
InitWithBundlePolicy(PeerConnectionInterface::kBundlePolicyMaxCompat);
mediastream_signaling_.SendAudioVideoStream1();
@@ -2998,8 +2899,8 @@
SessionDescriptionInterface* offer = CreateOffer(options);
SetLocalDescriptionWithoutError(offer);
- EXPECT_NE(session_->voice_rtp_transport_channel(),
- session_->video_rtp_transport_channel());
+ EXPECT_NE(session_->GetTransportProxy("audio")->impl(),
+ session_->GetTransportProxy("video")->impl());
mediastream_signaling_.SendAudioVideoStream2();
@@ -3013,8 +2914,8 @@
modified_answer->Initialize(answer_copy, "1", "1");
SetRemoteDescriptionWithoutError(modified_answer); //
- EXPECT_NE(session_->voice_rtp_transport_channel(),
- session_->video_rtp_transport_channel());
+ EXPECT_NE(session_->GetTransportProxy("audio")->impl(),
+ session_->GetTransportProxy("video")->impl());
}
// kBundlePolicyMaxbundle and then we call SetRemoteDescription first.
@@ -3028,8 +2929,8 @@
SessionDescriptionInterface* offer = CreateOffer(options);
SetRemoteDescriptionWithoutError(offer);
- EXPECT_EQ(session_->voice_rtp_transport_channel(),
- session_->video_rtp_transport_channel());
+ EXPECT_EQ(session_->GetTransportProxy("audio")->impl(),
+ session_->GetTransportProxy("video")->impl());
}
TEST_F(WebRtcSessionTest, TestRequireRtcpMux) {
@@ -3040,16 +2941,16 @@
SessionDescriptionInterface* offer = CreateOffer(options);
SetLocalDescriptionWithoutError(offer);
- EXPECT_TRUE(session_->voice_rtcp_transport_channel() == NULL);
- EXPECT_TRUE(session_->video_rtcp_transport_channel() == NULL);
+ EXPECT_FALSE(session_->GetTransportProxy("audio")->impl()->HasChannel(2));
+ EXPECT_FALSE(session_->GetTransportProxy("video")->impl()->HasChannel(2));
mediastream_signaling_.SendAudioVideoStream2();
SessionDescriptionInterface* answer =
CreateRemoteAnswer(session_->local_description());
SetRemoteDescriptionWithoutError(answer);
- EXPECT_TRUE(session_->voice_rtcp_transport_channel() == NULL);
- EXPECT_TRUE(session_->video_rtcp_transport_channel() == NULL);
+ EXPECT_FALSE(session_->GetTransportProxy("audio")->impl()->HasChannel(2));
+ EXPECT_FALSE(session_->GetTransportProxy("video")->impl()->HasChannel(2));
}
TEST_F(WebRtcSessionTest, TestNegotiateRtcpMux) {
@@ -3060,16 +2961,16 @@
SessionDescriptionInterface* offer = CreateOffer(options);
SetLocalDescriptionWithoutError(offer);
- EXPECT_TRUE(session_->voice_rtcp_transport_channel() != NULL);
- EXPECT_TRUE(session_->video_rtcp_transport_channel() != NULL);
+ EXPECT_TRUE(session_->GetTransportProxy("audio")->impl()->HasChannel(2));
+ EXPECT_TRUE(session_->GetTransportProxy("video")->impl()->HasChannel(2));
mediastream_signaling_.SendAudioVideoStream2();
SessionDescriptionInterface* answer =
CreateRemoteAnswer(session_->local_description());
SetRemoteDescriptionWithoutError(answer);
- EXPECT_TRUE(session_->voice_rtcp_transport_channel() == NULL);
- EXPECT_TRUE(session_->video_rtcp_transport_channel() == NULL);
+ EXPECT_FALSE(session_->GetTransportProxy("audio")->impl()->HasChannel(2));
+ EXPECT_FALSE(session_->GetTransportProxy("video")->impl()->HasChannel(2));
}
// This test verifies that SetLocalDescription and SetRemoteDescription fails
@@ -3090,11 +2991,11 @@
rtc::replace_substrs(rtcp_mux.c_str(), rtcp_mux.length(),
xrtcp_mux.c_str(), xrtcp_mux.length(),
&offer_str);
- JsepSessionDescription* local_offer =
+ JsepSessionDescription *local_offer =
new JsepSessionDescription(JsepSessionDescription::kOffer);
EXPECT_TRUE((local_offer)->Initialize(offer_str, NULL));
SetLocalDescriptionOfferExpectError(kBundleWithoutRtcpMux, local_offer);
- JsepSessionDescription* remote_offer =
+ JsepSessionDescription *remote_offer =
new JsepSessionDescription(JsepSessionDescription::kOffer);
EXPECT_TRUE((remote_offer)->Initialize(offer_str, NULL));
SetRemoteDescriptionOfferExpectError(kBundleWithoutRtcpMux, remote_offer);
@@ -3357,8 +3258,8 @@
candidate1);
EXPECT_TRUE(offer->AddCandidate(&ice_candidate1));
SetRemoteDescriptionWithoutError(offer);
- ASSERT_TRUE(session_->voice_rtp_transport_channel() != NULL);
- ASSERT_TRUE(session_->video_rtp_transport_channel() != NULL);
+ ASSERT_TRUE(session_->GetTransportProxy("audio") != NULL);
+ ASSERT_TRUE(session_->GetTransportProxy("video") != NULL);
// Pump for 1 second and verify that no candidates are generated.
rtc::Thread::Current()->ProcessMessages(1000);
@@ -3367,6 +3268,8 @@
SessionDescriptionInterface* answer = CreateAnswer(NULL);
SetLocalDescriptionWithoutError(answer);
+ EXPECT_TRUE(session_->GetTransportProxy("audio")->negotiated());
+ EXPECT_TRUE(session_->GetTransportProxy("video")->negotiated());
EXPECT_TRUE_WAIT(observer_.oncandidatesready_, kIceCandidatesTimeout);
}
@@ -3401,7 +3304,7 @@
// will be set as per MediaSessionDescriptionFactory.
std::string offer_str;
offer->ToString(&offer_str);
- SessionDescriptionInterface* jsep_offer_str =
+ SessionDescriptionInterface *jsep_offer_str =
CreateSessionDescription(JsepSessionDescription::kOffer, offer_str, NULL);
SetLocalDescriptionWithoutError(jsep_offer_str);
EXPECT_FALSE(session_->voice_channel()->secure_required());
@@ -3754,8 +3657,8 @@
TEST_P(WebRtcSessionTest,
TestMultipleCreateOfferBeforeIdentityRequestReturnSuccess) {
MAYBE_SKIP_TEST(rtc::SSLStreamAdapter::HaveDtlsSrtp);
- VerifyMultipleAsyncCreateDescription(GetParam(),
- CreateSessionDescriptionRequest::kOffer);
+ VerifyMultipleAsyncCreateDescription(
+ GetParam(), CreateSessionDescriptionRequest::kOffer);
}
// Verifies that CreateOffer fails when Multiple CreateOffer calls are made
@@ -3978,31 +3881,31 @@
rtc::Socket::Option::OPT_RCVBUF, 8000);
int option_val;
- EXPECT_TRUE(session_->video_rtp_transport_channel()->GetOption(
+ EXPECT_TRUE(session_->video_channel()->transport_channel()->GetOption(
rtc::Socket::Option::OPT_SNDBUF, &option_val));
EXPECT_EQ(4000, option_val);
- EXPECT_FALSE(session_->voice_rtp_transport_channel()->GetOption(
+ EXPECT_FALSE(session_->voice_channel()->transport_channel()->GetOption(
rtc::Socket::Option::OPT_SNDBUF, &option_val));
- EXPECT_TRUE(session_->voice_rtp_transport_channel()->GetOption(
+ EXPECT_TRUE(session_->voice_channel()->transport_channel()->GetOption(
rtc::Socket::Option::OPT_RCVBUF, &option_val));
EXPECT_EQ(8000, option_val);
- EXPECT_FALSE(session_->video_rtp_transport_channel()->GetOption(
+ EXPECT_FALSE(session_->video_channel()->transport_channel()->GetOption(
rtc::Socket::Option::OPT_RCVBUF, &option_val));
- EXPECT_NE(session_->voice_rtp_transport_channel(),
- session_->video_rtp_transport_channel());
+ EXPECT_NE(session_->voice_channel()->transport_channel(),
+ session_->video_channel()->transport_channel());
mediastream_signaling_.SendAudioVideoStream2();
SessionDescriptionInterface* answer =
CreateRemoteAnswer(session_->local_description());
SetRemoteDescriptionWithoutError(answer);
- EXPECT_TRUE(session_->voice_rtp_transport_channel()->GetOption(
+ EXPECT_TRUE(session_->voice_channel()->transport_channel()->GetOption(
rtc::Socket::Option::OPT_SNDBUF, &option_val));
EXPECT_EQ(4000, option_val);
- EXPECT_TRUE(session_->voice_rtp_transport_channel()->GetOption(
+ EXPECT_TRUE(session_->voice_channel()->transport_channel()->GetOption(
rtc::Socket::Option::OPT_RCVBUF, &option_val));
EXPECT_EQ(8000, option_val);
}
@@ -4038,7 +3941,6 @@
// currently fails because upon disconnection and reconnection OnIceComplete is
// called more than once without returning to IceGatheringGathering.
-INSTANTIATE_TEST_CASE_P(WebRtcSessionTests,
- WebRtcSessionTest,
- testing::Values(ALREADY_GENERATED,
- DTLS_IDENTITY_STORE));
+INSTANTIATE_TEST_CASE_P(
+ WebRtcSessionTests, WebRtcSessionTest,
+ testing::Values(ALREADY_GENERATED, DTLS_IDENTITY_STORE));
diff --git a/talk/app/webrtc/webrtcsessiondescriptionfactory.cc b/talk/app/webrtc/webrtcsessiondescriptionfactory.cc
index f6414d3..caa53df 100644
--- a/talk/app/webrtc/webrtcsessiondescriptionfactory.cc
+++ b/talk/app/webrtc/webrtcsessiondescriptionfactory.cc
@@ -165,15 +165,9 @@
WebRtcSession* session,
const std::string& session_id,
cricket::DataChannelType dct)
- : WebRtcSessionDescriptionFactory(signaling_thread,
- channel_manager,
- mediastream_signaling,
- nullptr,
- nullptr,
- session,
- session_id,
- dct,
- false) {
+ : WebRtcSessionDescriptionFactory(
+ signaling_thread, channel_manager, mediastream_signaling, nullptr,
+ nullptr, session, session_id, dct, false) {
LOG(LS_VERBOSE) << "DTLS-SRTP disabled.";
}
@@ -232,9 +226,9 @@
// We already have a certificate but we wait to do SetIdentity; if we do
// it in the constructor then the caller has not had a chance to connect to
// SignalIdentityReady.
- signaling_thread_->Post(
- this, MSG_USE_CONSTRUCTOR_CERTIFICATE,
- new rtc::ScopedRefMessageData<rtc::RTCCertificate>(certificate));
+ signaling_thread_->Post(this, MSG_USE_CONSTRUCTOR_CERTIFICATE,
+ new rtc::ScopedRefMessageData<rtc::RTCCertificate>(
+ certificate));
}
WebRtcSessionDescriptionFactory::~WebRtcSessionDescriptionFactory() {
@@ -260,6 +254,8 @@
delete msg.pdata;
}
}
+
+ transport_desc_factory_.set_certificate(nullptr);
}
void WebRtcSessionDescriptionFactory::CreateOffer(
diff --git a/talk/app/webrtc/webrtcsessiondescriptionfactory.h b/talk/app/webrtc/webrtcsessiondescriptionfactory.h
index 52b8da5..b42a551 100644
--- a/talk/app/webrtc/webrtcsessiondescriptionfactory.h
+++ b/talk/app/webrtc/webrtcsessiondescriptionfactory.h
@@ -90,12 +90,13 @@
public sigslot::has_slots<> {
public:
// Construct with DTLS disabled.
- WebRtcSessionDescriptionFactory(rtc::Thread* signaling_thread,
- cricket::ChannelManager* channel_manager,
- MediaStreamSignaling* mediastream_signaling,
- WebRtcSession* session,
- const std::string& session_id,
- cricket::DataChannelType dct);
+ WebRtcSessionDescriptionFactory(
+ rtc::Thread* signaling_thread,
+ cricket::ChannelManager* channel_manager,
+ MediaStreamSignaling* mediastream_signaling,
+ WebRtcSession* session,
+ const std::string& session_id,
+ cricket::DataChannelType dct);
// Construct with DTLS enabled using the specified |dtls_identity_store| to
// generate a certificate.
diff --git a/talk/media/webrtc/webrtcvoiceengine_unittest.cc b/talk/media/webrtc/webrtcvoiceengine_unittest.cc
index 1ecfcc0..fc373db 100644
--- a/talk/media/webrtc/webrtcvoiceengine_unittest.cc
+++ b/talk/media/webrtc/webrtcvoiceengine_unittest.cc
@@ -36,7 +36,7 @@
#include "talk/media/webrtc/fakewebrtccall.h"
#include "talk/media/webrtc/fakewebrtcvoiceengine.h"
#include "talk/media/webrtc/webrtcvoiceengine.h"
-#include "webrtc/p2p/base/faketransportcontroller.h"
+#include "webrtc/p2p/base/fakesession.h"
#include "talk/session/media/channel.h"
// Tests for the WebRtcVoiceEngine/VoiceChannel code.
diff --git a/talk/session/media/channel.cc b/talk/session/media/channel.cc
index 7b58098..294681e 100644
--- a/talk/session/media/channel.cc
+++ b/talk/session/media/channel.cc
@@ -170,17 +170,15 @@
}
BaseChannel::BaseChannel(rtc::Thread* thread,
- MediaChannel* media_channel,
- TransportController* transport_controller,
- const std::string& content_name,
- bool rtcp)
+ MediaChannel* media_channel, BaseSession* session,
+ const std::string& content_name, bool rtcp)
: worker_thread_(thread),
- transport_controller_(transport_controller),
+ session_(session),
media_channel_(media_channel),
content_name_(content_name),
- rtcp_transport_enabled_(rtcp),
- transport_channel_(nullptr),
- rtcp_transport_channel_(nullptr),
+ rtcp_(rtcp),
+ transport_channel_(NULL),
+ rtcp_transport_channel_(NULL),
enabled_(false),
writable_(false),
rtp_ready_to_send_(false),
@@ -206,31 +204,20 @@
// the media channel may try to send on the dead transport channel. NULLing
// is not an effective strategy since the sends will come on another thread.
delete media_channel_;
- // Note that we don't just call set_transport_channel(nullptr) because that
- // would call a pure virtual method which we can't do from a destructor.
- if (transport_channel_) {
- DisconnectFromTransportChannel(transport_channel_);
- transport_controller_->DestroyTransportChannel_w(
- transport_name_, cricket::ICE_CANDIDATE_COMPONENT_RTP);
- }
- if (rtcp_transport_channel_) {
- DisconnectFromTransportChannel(rtcp_transport_channel_);
- transport_controller_->DestroyTransportChannel_w(
- transport_name_, cricket::ICE_CANDIDATE_COMPONENT_RTCP);
- }
+ set_transport_channel(nullptr);
+ set_rtcp_transport_channel(nullptr);
LOG(LS_INFO) << "Destroyed channel";
}
bool BaseChannel::Init() {
- if (!SetTransport(content_name())) {
+ if (!SetTransportChannels(session(), rtcp())) {
return false;
}
if (!SetDtlsSrtpCiphers(transport_channel(), false)) {
return false;
}
- if (rtcp_transport_enabled() &&
- !SetDtlsSrtpCiphers(rtcp_transport_channel(), true)) {
+ if (rtcp() && !SetDtlsSrtpCiphers(rtcp_transport_channel(), true)) {
return false;
}
@@ -244,35 +231,29 @@
media_channel_->SetInterface(NULL);
}
-bool BaseChannel::SetTransport(const std::string& transport_name) {
- return worker_thread_->Invoke<bool>(
- Bind(&BaseChannel::SetTransport_w, this, transport_name));
+bool BaseChannel::SetTransportChannels(BaseSession* session, bool rtcp) {
+ return worker_thread_->Invoke<bool>(Bind(
+ &BaseChannel::SetTransportChannels_w, this, session, rtcp));
}
-bool BaseChannel::SetTransport_w(const std::string& transport_name) {
+bool BaseChannel::SetTransportChannels_w(BaseSession* session, bool rtcp) {
ASSERT(worker_thread_ == rtc::Thread::Current());
- if (transport_name == transport_name_) {
- // Nothing to do if transport name isn't changing
- return true;
- }
-
- set_transport_channel(transport_controller_->CreateTransportChannel_w(
- transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP));
+ set_transport_channel(session->CreateChannel(
+ content_name(), cricket::ICE_CANDIDATE_COMPONENT_RTP));
if (!transport_channel()) {
return false;
}
- if (rtcp_transport_enabled()) {
- LOG(LS_INFO) << "Create RTCP TransportChannel for " << content_name()
- << " on " << transport_name << " transport ";
- set_rtcp_transport_channel(transport_controller_->CreateTransportChannel_w(
- transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTCP));
+ if (rtcp) {
+ set_rtcp_transport_channel(session->CreateChannel(
+ content_name(), cricket::ICE_CANDIDATE_COMPONENT_RTCP));
if (!rtcp_transport_channel()) {
return false;
}
+ } else {
+ set_rtcp_transport_channel(nullptr);
}
- transport_name_ = transport_name;
return true;
}
@@ -280,62 +261,42 @@
ASSERT(worker_thread_ == rtc::Thread::Current());
TransportChannel* old_tc = transport_channel_;
- if (!old_tc && !new_tc) {
- // Nothing to do
+
+ if (old_tc == new_tc) {
return;
}
- ASSERT(old_tc != new_tc);
-
if (old_tc) {
DisconnectFromTransportChannel(old_tc);
- transport_controller_->DestroyTransportChannel_w(
- transport_name_, cricket::ICE_CANDIDATE_COMPONENT_RTP);
+ session()->DestroyChannel(
+ content_name(), cricket::ICE_CANDIDATE_COMPONENT_RTP);
}
transport_channel_ = new_tc;
if (new_tc) {
ConnectToTransportChannel(new_tc);
- for (const auto& pair : socket_options_) {
- new_tc->SetOption(pair.first, pair.second);
- }
}
-
- // Update aggregate writable/ready-to-send state between RTP and RTCP upon
- // setting new channel
- UpdateWritableState_w();
- SetReadyToSend(false, new_tc && new_tc->writable());
}
void BaseChannel::set_rtcp_transport_channel(TransportChannel* new_tc) {
ASSERT(worker_thread_ == rtc::Thread::Current());
TransportChannel* old_tc = rtcp_transport_channel_;
- if (!old_tc && !new_tc) {
- // Nothing to do
+
+ if (old_tc == new_tc) {
return;
}
- ASSERT(old_tc != new_tc);
-
if (old_tc) {
DisconnectFromTransportChannel(old_tc);
- transport_controller_->DestroyTransportChannel_w(
- transport_name_, cricket::ICE_CANDIDATE_COMPONENT_RTCP);
+ session()->DestroyChannel(
+ content_name(), cricket::ICE_CANDIDATE_COMPONENT_RTCP);
}
rtcp_transport_channel_ = new_tc;
if (new_tc) {
ConnectToTransportChannel(new_tc);
- for (const auto& pair : rtcp_socket_options_) {
- new_tc->SetOption(pair.first, pair.second);
- }
}
-
- // Update aggregate writable/ready-to-send state between RTP and RTCP upon
- // setting new channel
- UpdateWritableState_w();
- SetReadyToSend(true, new_tc && new_tc->writable());
}
void BaseChannel::ConnectToTransportChannel(TransportChannel* tc) {
@@ -446,13 +407,9 @@
switch (type) {
case ST_RTP:
channel = transport_channel_;
- socket_options_.push_back(
- std::pair<rtc::Socket::Option, int>(opt, value));
break;
case ST_RTCP:
channel = rtcp_transport_channel_;
- rtcp_socket_options_.push_back(
- std::pair<rtc::Socket::Option, int>(opt, value));
break;
}
return channel ? channel->SetOption(opt, value) : -1;
@@ -460,7 +417,12 @@
void BaseChannel::OnWritableState(TransportChannel* channel) {
ASSERT(channel == transport_channel_ || channel == rtcp_transport_channel_);
- UpdateWritableState_w();
+ if (transport_channel_->writable()
+ && (!rtcp_transport_channel_ || rtcp_transport_channel_->writable())) {
+ ChannelWritable_w();
+ } else {
+ ChannelNotWritable_w();
+ }
}
void BaseChannel::OnChannelRead(TransportChannel* channel,
@@ -478,25 +440,26 @@
}
void BaseChannel::OnReadyToSend(TransportChannel* channel) {
- ASSERT(channel == transport_channel_ || channel == rtcp_transport_channel_);
- SetReadyToSend(channel == rtcp_transport_channel_, true);
+ SetReadyToSend(channel, true);
}
-void BaseChannel::SetReadyToSend(bool rtcp, bool ready) {
- if (rtcp) {
- rtcp_ready_to_send_ = ready;
- } else {
+void BaseChannel::SetReadyToSend(TransportChannel* channel, bool ready) {
+ ASSERT(channel == transport_channel_ || channel == rtcp_transport_channel_);
+ if (channel == transport_channel_) {
rtp_ready_to_send_ = ready;
}
+ if (channel == rtcp_transport_channel_) {
+ rtcp_ready_to_send_ = ready;
+ }
- if (rtp_ready_to_send_ &&
- // In the case of rtcp mux |rtcp_transport_channel_| will be null.
- (rtcp_ready_to_send_ || !rtcp_transport_channel_)) {
- // Notify the MediaChannel when both rtp and rtcp channel can send.
- media_channel_->OnReadyToSend(true);
- } else {
+ if (!ready) {
// Notify the MediaChannel when either rtp or rtcp channel can't send.
media_channel_->OnReadyToSend(false);
+ } else if (rtp_ready_to_send_ &&
+ // In the case of rtcp mux |rtcp_transport_channel_| will be null.
+ (rtcp_ready_to_send_ || !rtcp_transport_channel_)) {
+ // Notify the MediaChannel when both rtp and rtcp channel can send.
+ media_channel_->OnReadyToSend(true);
}
}
@@ -618,7 +581,7 @@
if (ret != static_cast<int>(packet->size())) {
if (channel->GetError() == EWOULDBLOCK) {
LOG(LS_WARNING) << "Got EWOULDBLOCK from socket.";
- SetReadyToSend(rtcp, false);
+ SetReadyToSend(channel, false);
}
return false;
}
@@ -752,21 +715,14 @@
ChangeState();
}
-void BaseChannel::UpdateWritableState_w() {
- if (transport_channel_ && transport_channel_->writable() &&
- (!rtcp_transport_channel_ || rtcp_transport_channel_->writable())) {
- ChannelWritable_w();
- } else {
- ChannelNotWritable_w();
- }
-}
-
void BaseChannel::ChannelWritable_w() {
ASSERT(worker_thread_ == rtc::Thread::Current());
if (writable_)
return;
- LOG(LS_INFO) << "Channel writable (" << content_name_ << ")"
+ LOG(LS_INFO) << "Channel socket writable ("
+ << transport_channel_->content_name() << ", "
+ << transport_channel_->component() << ")"
<< (was_ever_writable_ ? "" : " for the first time");
std::vector<ConnectionInfo> infos;
@@ -783,13 +739,13 @@
// If we're doing DTLS-SRTP, now is the time.
if (!was_ever_writable_ && ShouldSetupDtlsSrtp()) {
if (!SetupDtlsSrtp(false)) {
- SignalDtlsSetupFailure_w(false);
+ SignalDtlsSetupFailure(this, false);
return;
}
if (rtcp_transport_channel_) {
if (!SetupDtlsSrtp(true)) {
- SignalDtlsSetupFailure_w(true);
+ SignalDtlsSetupFailure(this, true);
return;
}
}
@@ -832,8 +788,8 @@
bool BaseChannel::SetupDtlsSrtp(bool rtcp_channel) {
bool ret = false;
- TransportChannel* channel =
- rtcp_channel ? rtcp_transport_channel_ : transport_channel_;
+ TransportChannel *channel = rtcp_channel ?
+ rtcp_transport_channel_ : transport_channel_;
// No DTLS
if (!channel->IsDtlsActive())
@@ -928,7 +884,9 @@
if (!writable_)
return;
- LOG(LS_INFO) << "Channel not writable (" << content_name_ << ")";
+ LOG(LS_INFO) << "Channel socket not writable ("
+ << transport_channel_->content_name() << ", "
+ << transport_channel_->component() << ")";
writable_ = false;
ChangeState();
}
@@ -1027,8 +985,7 @@
void BaseChannel::ActivateRtcpMux_w() {
if (!rtcp_mux_filter_.IsActive()) {
rtcp_mux_filter_.SetActive();
- set_rtcp_transport_channel(nullptr);
- rtcp_transport_enabled_ = false;
+ set_rtcp_transport_channel(NULL);
}
}
@@ -1047,11 +1004,7 @@
ret = rtcp_mux_filter_.SetAnswer(enable, src);
if (ret && rtcp_mux_filter_.IsActive()) {
// We activated RTCP mux, close down the RTCP transport.
- LOG(LS_INFO) << "Enabling rtcp-mux for " << content_name()
- << " by destroying RTCP transport channel for "
- << transport_name();
- set_rtcp_transport_channel(nullptr);
- rtcp_transport_enabled_ = false;
+ set_rtcp_transport_channel(NULL);
}
break;
case CA_UPDATE:
@@ -1278,16 +1231,14 @@
VoiceChannel::VoiceChannel(rtc::Thread* thread,
MediaEngineInterface* media_engine,
VoiceMediaChannel* media_channel,
- TransportController* transport_controller,
+ BaseSession* session,
const std::string& content_name,
bool rtcp)
- : BaseChannel(thread,
- media_channel,
- transport_controller,
- content_name,
+ : BaseChannel(thread, media_channel, session, content_name,
rtcp),
media_engine_(media_engine),
- received_media_(false) {}
+ received_media_(false) {
+}
VoiceChannel::~VoiceChannel() {
StopAudioMonitor();
@@ -1313,12 +1264,11 @@
media_channel(), ssrc, renderer));
}
-bool VoiceChannel::SetAudioSend(uint32 ssrc,
- bool mute,
+bool VoiceChannel::SetAudioSend(uint32 ssrc, bool mute,
const AudioOptions* options,
AudioRenderer* renderer) {
- return InvokeOnWorker(Bind(&VoiceMediaChannel::SetAudioSend, media_channel(),
- ssrc, mute, options, renderer));
+ return InvokeOnWorker(Bind(&VoiceMediaChannel::SetAudioSend,
+ media_channel(), ssrc, mute, options, renderer));
}
bool VoiceChannel::SetRingbackTone(const void* buf, int len) {
@@ -1657,16 +1607,14 @@
VideoChannel::VideoChannel(rtc::Thread* thread,
VideoMediaChannel* media_channel,
- TransportController* transport_controller,
+ BaseSession* session,
const std::string& content_name,
bool rtcp)
- : BaseChannel(thread,
- media_channel,
- transport_controller,
- content_name,
+ : BaseChannel(thread, media_channel, session, content_name,
rtcp),
renderer_(NULL),
- previous_we_(rtc::WE_CLOSE) {}
+ previous_we_(rtc::WE_CLOSE) {
+}
bool VideoChannel::Init() {
if (!BaseChannel::Init()) {
@@ -1759,11 +1707,10 @@
return true;
}
-bool VideoChannel::SetVideoSend(uint32 ssrc,
- bool mute,
+bool VideoChannel::SetVideoSend(uint32 ssrc, bool mute,
const VideoOptions* options) {
- return InvokeOnWorker(Bind(&VideoMediaChannel::SetVideoSend, media_channel(),
- ssrc, mute, options));
+ return InvokeOnWorker(Bind(&VideoMediaChannel::SetVideoSend,
+ media_channel(), ssrc, mute, options));
}
void VideoChannel::ChangeState() {
@@ -2098,16 +2045,13 @@
DataChannel::DataChannel(rtc::Thread* thread,
DataMediaChannel* media_channel,
- TransportController* transport_controller,
+ BaseSession* session,
const std::string& content_name,
bool rtcp)
- : BaseChannel(thread,
- media_channel,
- transport_controller,
- content_name,
- rtcp),
+ : BaseChannel(thread, media_channel, session, content_name, rtcp),
data_channel_type_(cricket::DCT_NONE),
- ready_to_send_data_(false) {}
+ ready_to_send_data_(false) {
+}
DataChannel::~DataChannel() {
StopMediaMonitor();
diff --git a/talk/session/media/channel.h b/talk/session/media/channel.h
index 9cde0d1..bb430bf 100644
--- a/talk/session/media/channel.h
+++ b/talk/session/media/channel.h
@@ -30,15 +30,12 @@
#include <string>
#include <vector>
-#include <map>
-#include <set>
-#include <utility>
#include "talk/media/base/mediachannel.h"
#include "talk/media/base/mediaengine.h"
#include "talk/media/base/streamparams.h"
#include "talk/media/base/videocapturer.h"
-#include "webrtc/p2p/base/transportcontroller.h"
+#include "webrtc/p2p/base/session.h"
#include "webrtc/p2p/client/socketmonitor.h"
#include "talk/session/media/audiomonitor.h"
#include "talk/session/media/bundlefilter.h"
@@ -77,11 +74,8 @@
public MediaChannel::NetworkInterface,
public ConnectionStatsGetter {
public:
- BaseChannel(rtc::Thread* thread,
- MediaChannel* channel,
- TransportController* transport_controller,
- const std::string& content_name,
- bool rtcp);
+ BaseChannel(rtc::Thread* thread, MediaChannel* channel, BaseSession* session,
+ const std::string& content_name, bool rtcp);
virtual ~BaseChannel();
bool Init();
// Deinit may be called multiple times and is simply ignored if it's alreay
@@ -89,8 +83,8 @@
void Deinit();
rtc::Thread* worker_thread() const { return worker_thread_; }
- const std::string& content_name() const { return content_name_; }
- const std::string& transport_name() const { return transport_name_; }
+ BaseSession* session() const { return session_; }
+ const std::string& content_name() { return content_name_; }
TransportChannel* transport_channel() const {
return transport_channel_;
}
@@ -115,7 +109,6 @@
// description doesn't support RTCP mux, setting the remote
// description will fail.
void ActivateRtcpMux();
- bool SetTransport(const std::string& transport_name);
bool PushdownLocalDescription(const SessionDescription* local_desc,
ContentAction action,
std::string* error_desc);
@@ -142,7 +135,7 @@
void StartConnectionMonitor(int cms);
void StopConnectionMonitor();
// For ConnectionStatsGetter, used by ConnectionMonitor
- bool GetConnectionStats(ConnectionInfos* infos) override;
+ virtual bool GetConnectionStats(ConnectionInfos* infos) override;
void set_srtp_signal_silent_time(uint32 silent_time) {
srtp_filter_.set_signal_silent_time(silent_time);
@@ -165,16 +158,19 @@
sigslot::signal1<BaseChannel*> SignalFirstPacketReceived;
// Made public for easier testing.
- void SetReadyToSend(bool rtcp, bool ready);
+ void SetReadyToSend(TransportChannel* channel, bool ready);
// Only public for unit tests. Otherwise, consider protected.
virtual int SetOption(SocketType type, rtc::Socket::Option o, int val);
protected:
virtual MediaChannel* media_channel() const { return media_channel_; }
- // Sets the |transport_channel_| (and |rtcp_transport_channel_|, if |rtcp_| is
- // true). Gets the transport channels from |transport_controller_|.
- bool SetTransport_w(const std::string& transport_name);
+ // Sets the transport_channel_ and rtcp_transport_channel_. If
+ // |rtcp| is false, set rtcp_transport_channel_ is set to NULL. Get
+ // the transport channels from |session|.
+ // TODO(pthatcher): Pass in a Transport instead of a BaseSession.
+ bool SetTransportChannels(BaseSession* session, bool rtcp);
+ bool SetTransportChannels_w(BaseSession* session, bool rtcp);
void set_transport_channel(TransportChannel* transport);
void set_rtcp_transport_channel(TransportChannel* transport);
bool was_ever_writable() const { return was_ever_writable_; }
@@ -189,11 +185,9 @@
}
bool IsReadyToReceive() const;
bool IsReadyToSend() const;
- rtc::Thread* signaling_thread() {
- return transport_controller_->signaling_thread();
- }
+ rtc::Thread* signaling_thread() { return session_->signaling_thread(); }
SrtpFilter* srtp_filter() { return &srtp_filter_; }
- bool rtcp_transport_enabled() const { return rtcp_transport_enabled_; }
+ bool rtcp() const { return rtcp_; }
void ConnectToTransportChannel(TransportChannel* tc);
void DisconnectFromTransportChannel(TransportChannel* tc);
@@ -223,9 +217,12 @@
void HandlePacket(bool rtcp, rtc::Buffer* packet,
const rtc::PacketTime& packet_time);
+ // Apply the new local/remote session description.
+ void OnNewLocalDescription(BaseSession* session, ContentAction action);
+ void OnNewRemoteDescription(BaseSession* session, ContentAction action);
+
void EnableMedia_w();
void DisableMedia_w();
- void UpdateWritableState_w();
void ChannelWritable_w();
void ChannelNotWritable_w();
bool AddRecvStream_w(const StreamParams& sp);
@@ -296,18 +293,15 @@
private:
rtc::Thread* worker_thread_;
- TransportController* transport_controller_;
+ BaseSession* session_;
MediaChannel* media_channel_;
std::vector<StreamParams> local_streams_;
std::vector<StreamParams> remote_streams_;
const std::string content_name_;
- std::string transport_name_;
- bool rtcp_transport_enabled_;
+ bool rtcp_;
TransportChannel* transport_channel_;
- std::vector<std::pair<rtc::Socket::Option, int> > socket_options_;
TransportChannel* rtcp_transport_channel_;
- std::vector<std::pair<rtc::Socket::Option, int> > rtcp_socket_options_;
SrtpFilter srtp_filter_;
RtcpMuxFilter rtcp_mux_filter_;
BundleFilter bundle_filter_;
@@ -329,21 +323,16 @@
// and input/output level monitoring.
class VoiceChannel : public BaseChannel {
public:
- VoiceChannel(rtc::Thread* thread,
- MediaEngineInterface* media_engine,
- VoiceMediaChannel* channel,
- TransportController* transport_controller,
- const std::string& content_name,
- bool rtcp);
+ VoiceChannel(rtc::Thread* thread, MediaEngineInterface* media_engine,
+ VoiceMediaChannel* channel, BaseSession* session,
+ const std::string& content_name, bool rtcp);
~VoiceChannel();
bool Init();
bool SetRemoteRenderer(uint32 ssrc, AudioRenderer* renderer);
// Configure sending media on the stream with SSRC |ssrc|
// If there is only one sending stream SSRC 0 can be used.
- bool SetAudioSend(uint32 ssrc,
- bool mute,
- const AudioOptions* options,
+ bool SetAudioSend(uint32 ssrc, bool mute, const AudioOptions* options,
AudioRenderer* renderer);
// downcasts a MediaChannel
@@ -444,10 +433,8 @@
// VideoChannel is a specialization for video.
class VideoChannel : public BaseChannel {
public:
- VideoChannel(rtc::Thread* thread,
- VideoMediaChannel* channel,
- TransportController* transport_controller,
- const std::string& content_name,
+ VideoChannel(rtc::Thread* thread, VideoMediaChannel* channel,
+ BaseSession* session, const std::string& content_name,
bool rtcp);
~VideoChannel();
bool Init();
@@ -546,7 +533,7 @@
public:
DataChannel(rtc::Thread* thread,
DataMediaChannel* media_channel,
- TransportController* transport_controller,
+ BaseSession* session,
const std::string& content_name,
bool rtcp);
~DataChannel();
diff --git a/talk/session/media/channel_unittest.cc b/talk/session/media/channel_unittest.cc
index 499f9de..9020caf 100644
--- a/talk/session/media/channel_unittest.cc
+++ b/talk/session/media/channel_unittest.cc
@@ -33,7 +33,7 @@
#include "talk/media/base/rtpdump.h"
#include "talk/media/base/screencastid.h"
#include "talk/media/base/testutils.h"
-#include "webrtc/p2p/base/faketransportcontroller.h"
+#include "webrtc/p2p/base/fakesession.h"
#include "talk/session/media/channel.h"
#include "webrtc/base/fileutils.h"
#include "webrtc/base/gunit.h"
@@ -73,12 +73,12 @@
static const int kAudioPts[] = {0, 8};
static const int kVideoPts[] = {97, 99};
-template <class ChannelT,
- class MediaChannelT,
- class ContentT,
- class CodecT,
- class MediaInfoT,
- class OptionsT>
+template<class ChannelT,
+ class MediaChannelT,
+ class ContentT,
+ class CodecT,
+ class MediaInfoT,
+ class OptionsT>
class Traits {
public:
typedef ChannelT Channel;
@@ -98,21 +98,25 @@
cricket::AudioContentDescription,
cricket::AudioCodec,
cricket::VoiceMediaInfo,
- cricket::AudioOptions> {};
+ cricket::AudioOptions> {
+};
class VideoTraits : public Traits<cricket::VideoChannel,
cricket::FakeVideoMediaChannel,
cricket::VideoContentDescription,
cricket::VideoCodec,
cricket::VideoMediaInfo,
- cricket::VideoOptions> {};
+ cricket::VideoOptions> {
+};
class DataTraits : public Traits<cricket::DataChannel,
cricket::FakeDataMediaChannel,
cricket::DataContentDescription,
cricket::DataCodec,
cricket::DataMediaInfo,
- cricket::DataOptions> {};
+ cricket::DataOptions> {
+};
+
rtc::StreamInterface* Open(const std::string& path) {
return rtc::Filesystem::OpenFile(
@@ -126,12 +130,10 @@
enum Flags { RTCP = 0x1, RTCP_MUX = 0x2, SECURE = 0x4, SSRC_MUX = 0x8,
DTLS = 0x10 };
- ChannelTest(const uint8* rtp_data,
- int rtp_len,
- const uint8* rtcp_data,
- int rtcp_len)
- : transport_controller1_(cricket::ICEROLE_CONTROLLING),
- transport_controller2_(cricket::ICEROLE_CONTROLLED),
+ ChannelTest(const uint8* rtp_data, int rtp_len,
+ const uint8* rtcp_data, int rtcp_len)
+ : session1_(true),
+ session2_(false),
media_channel1_(NULL),
media_channel2_(NULL),
rtp_packet_(reinterpret_cast<const char*>(rtp_data), rtp_len),
@@ -139,7 +141,8 @@
media_info_callbacks1_(),
media_info_callbacks2_(),
ssrc_(0),
- error_(T::MediaChannel::ERROR_NONE) {}
+ error_(T::MediaChannel::ERROR_NONE) {
+ }
void CreateChannels(int flags1, int flags2) {
CreateChannels(new typename T::MediaChannel(NULL, typename T::Options()),
@@ -151,11 +154,9 @@
int flags1, int flags2, rtc::Thread* thread) {
media_channel1_ = ch1;
media_channel2_ = ch2;
- channel1_.reset(CreateChannel(thread, &media_engine_, ch1,
- &transport_controller1_,
+ channel1_.reset(CreateChannel(thread, &media_engine_, ch1, &session1_,
(flags1 & RTCP) != 0));
- channel2_.reset(CreateChannel(thread, &media_engine_, ch2,
- &transport_controller2_,
+ channel2_.reset(CreateChannel(thread, &media_engine_, ch2, &session2_,
(flags2 & RTCP) != 0));
channel1_->SignalMediaMonitor.connect(
this, &ChannelTest<T>::OnMediaMonitor);
@@ -178,17 +179,15 @@
if (flags1 & DTLS) {
// Confirmed to work with KT_RSA and KT_ECDSA.
- transport_controller1_.SetLocalCertificate(rtc::RTCCertificate::Create(
- rtc::scoped_ptr<rtc::SSLIdentity>(
- rtc::SSLIdentity::Generate("session1", rtc::KT_DEFAULT))
- .Pass()));
+ session1_.set_ssl_rtccertificate(rtc::RTCCertificate::Create(
+ rtc::scoped_ptr<rtc::SSLIdentity>(rtc::SSLIdentity::Generate(
+ "session1", rtc::KT_DEFAULT)).Pass()));
}
if (flags2 & DTLS) {
// Confirmed to work with KT_RSA and KT_ECDSA.
- transport_controller2_.SetLocalCertificate(rtc::RTCCertificate::Create(
- rtc::scoped_ptr<rtc::SSLIdentity>(
- rtc::SSLIdentity::Generate("session2", rtc::KT_DEFAULT))
- .Pass()));
+ session2_.set_ssl_rtccertificate(rtc::RTCCertificate::Create(
+ rtc::scoped_ptr<rtc::SSLIdentity>(rtc::SSLIdentity::Generate(
+ "session2", rtc::KT_DEFAULT)).Pass()));
}
// Add stream information (SSRC) to the local content but not to the remote
@@ -205,14 +204,13 @@
AddLegacyStreamInContent(kSsrc2, flags2, &remote_media_content2_);
}
}
- typename T::Channel* CreateChannel(
- rtc::Thread* thread,
- cricket::MediaEngineInterface* engine,
- typename T::MediaChannel* ch,
- cricket::TransportController* transport_controller,
- bool rtcp) {
+ typename T::Channel* CreateChannel(rtc::Thread* thread,
+ cricket::MediaEngineInterface* engine,
+ typename T::MediaChannel* ch,
+ cricket::BaseSession* session,
+ bool rtcp) {
typename T::Channel* channel = new typename T::Channel(
- thread, engine, ch, transport_controller, cricket::CN_AUDIO, rtcp);
+ thread, engine, ch, session, cricket::CN_AUDIO, rtcp);
if (!channel->Init()) {
delete channel;
channel = NULL;
@@ -228,7 +226,7 @@
result = channel2_->SetRemoteContent(&remote_media_content1_,
CA_OFFER, NULL);
if (result) {
- transport_controller1_.Connect(&transport_controller2_);
+ session1_.Connect(&session2_);
result = channel2_->SetLocalContent(&local_media_content2_,
CA_ANSWER, NULL);
@@ -261,7 +259,7 @@
channel2_->Enable(true);
result = channel1_->SetRemoteContent(&remote_media_content2_,
CA_PRANSWER, NULL);
- transport_controller1_.Connect(&transport_controller2_);
+ session1_.Connect(&session2_);
}
return result;
}
@@ -288,12 +286,11 @@
return channel1_->RemoveRecvStream(id);
}
- // Calling "_w" method here is ok since we only use one thread for this test
cricket::FakeTransport* GetTransport1() {
- return transport_controller1_.GetTransport_w(channel1_->content_name());
+ return session1_.GetTransport(channel1_->content_name());
}
cricket::FakeTransport* GetTransport2() {
- return transport_controller2_.GetTransport_w(channel2_->content_name());
+ return session2_.GetTransport(channel2_->content_name());
}
bool SendRtp1() {
@@ -772,7 +769,7 @@
EXPECT_TRUE(channel2_->SetRemoteContent(&content1, CA_OFFER, NULL));
EXPECT_EQ(1u, media_channel2_->recv_streams().size());
- transport_controller1_.Connect(&transport_controller2_);
+ session1_.Connect(&session2_);
// Channel 2 do not send anything.
typename T::Content content2;
@@ -835,7 +832,7 @@
CA_ANSWER, NULL));
EXPECT_FALSE(media_channel2_->playout());
EXPECT_FALSE(media_channel2_->sending());
- transport_controller1_.Connect(&transport_controller2_);
+ session1_.Connect(&session2_);
EXPECT_TRUE(media_channel1_->playout());
EXPECT_FALSE(media_channel1_->sending());
EXPECT_FALSE(media_channel2_->playout());
@@ -871,7 +868,7 @@
EXPECT_TRUE(channel2_->SetRemoteContent(&content1, CA_OFFER, NULL));
EXPECT_TRUE(channel2_->SetLocalContent(&content2, CA_PRANSWER, NULL));
EXPECT_TRUE(channel1_->SetRemoteContent(&content2, CA_PRANSWER, NULL));
- transport_controller1_.Connect(&transport_controller2_);
+ session1_.Connect(&session2_);
EXPECT_TRUE(media_channel1_->playout());
EXPECT_FALSE(media_channel1_->sending()); // remote InActive
@@ -941,8 +938,6 @@
CreateChannels(0, 0);
EXPECT_TRUE(SendInitiate());
EXPECT_TRUE(SendAccept());
- ASSERT_TRUE(GetTransport1());
- ASSERT_TRUE(GetTransport2());
EXPECT_EQ(1U, GetTransport1()->channels().size());
EXPECT_EQ(1U, GetTransport2()->channels().size());
EXPECT_TRUE(SendRtp1());
@@ -958,8 +953,6 @@
CreateChannels(0, 0);
EXPECT_TRUE(SendInitiate());
EXPECT_TRUE(SendAccept());
- ASSERT_TRUE(GetTransport1());
- ASSERT_TRUE(GetTransport2());
EXPECT_EQ(1U, GetTransport1()->channels().size());
EXPECT_EQ(1U, GetTransport2()->channels().size());
EXPECT_FALSE(SendRtcp1());
@@ -973,8 +966,6 @@
CreateChannels(0, RTCP);
EXPECT_TRUE(SendInitiate());
EXPECT_TRUE(SendAccept());
- ASSERT_TRUE(GetTransport1());
- ASSERT_TRUE(GetTransport2());
EXPECT_EQ(1U, GetTransport1()->channels().size());
EXPECT_EQ(2U, GetTransport2()->channels().size());
EXPECT_FALSE(SendRtcp1());
@@ -988,8 +979,6 @@
CreateChannels(RTCP, 0);
EXPECT_TRUE(SendInitiate());
EXPECT_TRUE(SendAccept());
- ASSERT_TRUE(GetTransport1());
- ASSERT_TRUE(GetTransport2());
EXPECT_EQ(2U, GetTransport1()->channels().size());
EXPECT_EQ(1U, GetTransport2()->channels().size());
EXPECT_FALSE(SendRtcp1());
@@ -1003,8 +992,6 @@
CreateChannels(RTCP, RTCP);
EXPECT_TRUE(SendInitiate());
EXPECT_TRUE(SendAccept());
- ASSERT_TRUE(GetTransport1());
- ASSERT_TRUE(GetTransport2());
EXPECT_EQ(2U, GetTransport1()->channels().size());
EXPECT_EQ(2U, GetTransport2()->channels().size());
EXPECT_TRUE(SendRtcp1());
@@ -1020,8 +1007,6 @@
CreateChannels(RTCP | RTCP_MUX, RTCP);
EXPECT_TRUE(SendInitiate());
EXPECT_TRUE(SendAccept());
- ASSERT_TRUE(GetTransport1());
- ASSERT_TRUE(GetTransport2());
EXPECT_EQ(2U, GetTransport1()->channels().size());
EXPECT_EQ(2U, GetTransport2()->channels().size());
EXPECT_TRUE(SendRtcp1());
@@ -1036,8 +1021,6 @@
void SendRtcpMuxToRtcpMux() {
CreateChannels(RTCP | RTCP_MUX, RTCP | RTCP_MUX);
EXPECT_TRUE(SendInitiate());
- ASSERT_TRUE(GetTransport1());
- ASSERT_TRUE(GetTransport2());
EXPECT_EQ(2U, GetTransport1()->channels().size());
EXPECT_EQ(1U, GetTransport2()->channels().size());
EXPECT_TRUE(SendAccept());
@@ -1062,8 +1045,6 @@
CreateChannels(RTCP | RTCP_MUX, RTCP | RTCP_MUX);
channel1_->ActivateRtcpMux();
EXPECT_TRUE(SendInitiate());
- ASSERT_TRUE(GetTransport1());
- ASSERT_TRUE(GetTransport2());
EXPECT_EQ(1U, GetTransport1()->channels().size());
EXPECT_EQ(1U, GetTransport2()->channels().size());
EXPECT_TRUE(SendAccept());
@@ -1087,8 +1068,6 @@
CreateChannels(RTCP | RTCP_MUX, RTCP | RTCP_MUX);
channel2_->ActivateRtcpMux();
EXPECT_TRUE(SendInitiate());
- ASSERT_TRUE(GetTransport1());
- ASSERT_TRUE(GetTransport2());
EXPECT_EQ(2U, GetTransport1()->channels().size());
EXPECT_EQ(1U, GetTransport2()->channels().size());
EXPECT_TRUE(SendAccept());
@@ -1114,8 +1093,6 @@
channel1_->ActivateRtcpMux();
channel2_->ActivateRtcpMux();
EXPECT_TRUE(SendInitiate());
- ASSERT_TRUE(GetTransport1());
- ASSERT_TRUE(GetTransport2());
EXPECT_EQ(1U, GetTransport1()->channels().size());
EXPECT_EQ(1U, GetTransport2()->channels().size());
EXPECT_TRUE(SendAccept());
@@ -1140,8 +1117,6 @@
CreateChannels(RTCP | RTCP_MUX, RTCP);
channel1_->ActivateRtcpMux();
EXPECT_TRUE(SendInitiate());
- ASSERT_TRUE(GetTransport1());
- ASSERT_TRUE(GetTransport2());
EXPECT_EQ(1U, GetTransport1()->channels().size());
EXPECT_EQ(2U, GetTransport2()->channels().size());
EXPECT_FALSE(SendAccept());
@@ -1151,8 +1126,6 @@
void SendEarlyRtcpMuxToRtcp() {
CreateChannels(RTCP | RTCP_MUX, RTCP);
EXPECT_TRUE(SendInitiate());
- ASSERT_TRUE(GetTransport1());
- ASSERT_TRUE(GetTransport2());
EXPECT_EQ(2U, GetTransport1()->channels().size());
EXPECT_EQ(2U, GetTransport2()->channels().size());
@@ -1183,8 +1156,6 @@
void SendEarlyRtcpMuxToRtcpMux() {
CreateChannels(RTCP | RTCP_MUX, RTCP | RTCP_MUX);
EXPECT_TRUE(SendInitiate());
- ASSERT_TRUE(GetTransport1());
- ASSERT_TRUE(GetTransport2());
EXPECT_EQ(2U, GetTransport1()->channels().size());
EXPECT_EQ(1U, GetTransport2()->channels().size());
@@ -1275,8 +1246,6 @@
EXPECT_TRUE(SendProvisionalAnswer());
EXPECT_TRUE(channel1_->secure());
EXPECT_TRUE(channel2_->secure());
- ASSERT_TRUE(GetTransport1());
- ASSERT_TRUE(GetTransport2());
EXPECT_EQ(2U, GetTransport1()->channels().size());
EXPECT_EQ(2U, GetTransport2()->channels().size());
EXPECT_TRUE(SendCustomRtcp1(kSsrc1));
@@ -1360,8 +1329,6 @@
CreateChannels(0, 0);
EXPECT_TRUE(SendInitiate());
EXPECT_TRUE(SendAccept());
- ASSERT_TRUE(GetTransport1());
- ASSERT_TRUE(GetTransport2());
EXPECT_EQ(1U, GetTransport1()->channels().size());
EXPECT_EQ(1U, GetTransport2()->channels().size());
EXPECT_TRUE(SendRtp1());
@@ -1426,8 +1393,6 @@
}
CreateChannels(flags, flags);
EXPECT_TRUE(SendInitiate());
- ASSERT_TRUE(GetTransport1());
- ASSERT_TRUE(GetTransport2());
EXPECT_EQ(2U, GetTransport1()->channels().size());
EXPECT_EQ(expected_channels, GetTransport2()->channels().size());
EXPECT_TRUE(SendAccept());
@@ -1616,8 +1581,6 @@
CreateChannels(RTCP, RTCP);
EXPECT_TRUE(SendInitiate());
EXPECT_TRUE(SendAccept());
- ASSERT_TRUE(GetTransport1());
- ASSERT_TRUE(GetTransport2());
EXPECT_EQ(2U, GetTransport1()->channels().size());
EXPECT_EQ(2U, GetTransport2()->channels().size());
@@ -1706,15 +1669,15 @@
EXPECT_TRUE(media_channel1_->ready_to_send());
// rtp channel becomes not ready to send will be propagated to mediachannel
- channel1_->SetReadyToSend(false, false);
+ channel1_->SetReadyToSend(rtp, false);
EXPECT_FALSE(media_channel1_->ready_to_send());
- channel1_->SetReadyToSend(false, true);
+ channel1_->SetReadyToSend(rtp, true);
EXPECT_TRUE(media_channel1_->ready_to_send());
// rtcp channel becomes not ready to send will be propagated to mediachannel
- channel1_->SetReadyToSend(true, false);
+ channel1_->SetReadyToSend(rtcp, false);
EXPECT_FALSE(media_channel1_->ready_to_send());
- channel1_->SetReadyToSend(true, true);
+ channel1_->SetReadyToSend(rtcp, true);
EXPECT_TRUE(media_channel1_->ready_to_send());
}
@@ -1733,13 +1696,13 @@
// should trigger the MediaChannel's OnReadyToSend.
rtp->SignalReadyToSend(rtp);
EXPECT_TRUE(media_channel1_->ready_to_send());
- channel1_->SetReadyToSend(false, false);
+ channel1_->SetReadyToSend(rtp, false);
EXPECT_FALSE(media_channel1_->ready_to_send());
}
protected:
- cricket::FakeTransportController transport_controller1_;
- cricket::FakeTransportController transport_controller2_;
+ cricket::FakeSession session1_;
+ cricket::FakeSession session2_;
cricket::FakeMediaEngine media_engine_;
// The media channels are owned by the voice channel objects below.
typename T::MediaChannel* media_channel1_;
@@ -1800,21 +1763,18 @@
: public ChannelTest<VoiceTraits> {
public:
typedef ChannelTest<VoiceTraits> Base;
- VoiceChannelTest()
- : Base(kPcmuFrame, sizeof(kPcmuFrame), kRtcpReport, sizeof(kRtcpReport)) {
- }
+ VoiceChannelTest() : Base(kPcmuFrame, sizeof(kPcmuFrame),
+ kRtcpReport, sizeof(kRtcpReport)) {}
};
// override to add NULL parameter
-template <>
+template<>
cricket::VideoChannel* ChannelTest<VideoTraits>::CreateChannel(
- rtc::Thread* thread,
- cricket::MediaEngineInterface* engine,
- cricket::FakeVideoMediaChannel* ch,
- cricket::TransportController* transport_controller,
+ rtc::Thread* thread, cricket::MediaEngineInterface* engine,
+ cricket::FakeVideoMediaChannel* ch, cricket::BaseSession* session,
bool rtcp) {
cricket::VideoChannel* channel = new cricket::VideoChannel(
- thread, ch, transport_controller, cricket::CN_VIDEO, rtcp);
+ thread, ch, session, cricket::CN_VIDEO, rtcp);
if (!channel->Init()) {
delete channel;
channel = NULL;
@@ -1867,11 +1827,8 @@
: public ChannelTest<VideoTraits> {
public:
typedef ChannelTest<VideoTraits> Base;
- VideoChannelTest()
- : Base(kH264Packet,
- sizeof(kH264Packet),
- kRtcpReport,
- sizeof(kRtcpReport)) {}
+ VideoChannelTest() : Base(kH264Packet, sizeof(kH264Packet),
+ kRtcpReport, sizeof(kRtcpReport)) {}
};
@@ -2589,15 +2546,13 @@
};
// Override to avoid engine channel parameter.
-template <>
+template<>
cricket::DataChannel* ChannelTest<DataTraits>::CreateChannel(
- rtc::Thread* thread,
- cricket::MediaEngineInterface* engine,
- cricket::FakeDataMediaChannel* ch,
- cricket::TransportController* transport_controller,
+ rtc::Thread* thread, cricket::MediaEngineInterface* engine,
+ cricket::FakeDataMediaChannel* ch, cricket::BaseSession* session,
bool rtcp) {
cricket::DataChannel* channel = new cricket::DataChannel(
- thread, ch, transport_controller, cricket::CN_DATA, rtcp);
+ thread, ch, session, cricket::CN_DATA, rtcp);
if (!channel->Init()) {
delete channel;
channel = NULL;
diff --git a/talk/session/media/channelmanager.cc b/talk/session/media/channelmanager.cc
index 11fd41d..c109d60 100644
--- a/talk/session/media/channelmanager.cc
+++ b/talk/session/media/channelmanager.cc
@@ -319,18 +319,23 @@
VoiceChannel* ChannelManager::CreateVoiceChannel(
webrtc::MediaControllerInterface* media_controller,
- TransportController* transport_controller,
+ BaseSession* session,
const std::string& content_name,
bool rtcp,
const AudioOptions& options) {
return worker_thread_->Invoke<VoiceChannel*>(
- Bind(&ChannelManager::CreateVoiceChannel_w, this, media_controller,
- transport_controller, content_name, rtcp, options));
+ Bind(&ChannelManager::CreateVoiceChannel_w,
+ this,
+ media_controller,
+ session,
+ content_name,
+ rtcp,
+ options));
}
VoiceChannel* ChannelManager::CreateVoiceChannel_w(
webrtc::MediaControllerInterface* media_controller,
- TransportController* transport_controller,
+ BaseSession* session,
const std::string& content_name,
bool rtcp,
const AudioOptions& options) {
@@ -342,9 +347,9 @@
if (!media_channel)
return nullptr;
- VoiceChannel* voice_channel =
- new VoiceChannel(worker_thread_, media_engine_.get(), media_channel,
- transport_controller, content_name, rtcp);
+ VoiceChannel* voice_channel = new VoiceChannel(
+ worker_thread_, media_engine_.get(), media_channel,
+ session, content_name, rtcp);
if (!voice_channel->Init()) {
delete voice_channel;
return nullptr;
@@ -375,18 +380,23 @@
VideoChannel* ChannelManager::CreateVideoChannel(
webrtc::MediaControllerInterface* media_controller,
- TransportController* transport_controller,
+ BaseSession* session,
const std::string& content_name,
bool rtcp,
const VideoOptions& options) {
return worker_thread_->Invoke<VideoChannel*>(
- Bind(&ChannelManager::CreateVideoChannel_w, this, media_controller,
- transport_controller, content_name, rtcp, options));
+ Bind(&ChannelManager::CreateVideoChannel_w,
+ this,
+ media_controller,
+ session,
+ content_name,
+ rtcp,
+ options));
}
VideoChannel* ChannelManager::CreateVideoChannel_w(
webrtc::MediaControllerInterface* media_controller,
- TransportController* transport_controller,
+ BaseSession* session,
const std::string& content_name,
bool rtcp,
const VideoOptions& options) {
@@ -395,12 +405,12 @@
ASSERT(nullptr != media_controller);
VideoMediaChannel* media_channel =
media_engine_->CreateVideoChannel(media_controller->call_w(), options);
- if (media_channel == NULL) {
+ if (media_channel == NULL)
return NULL;
- }
VideoChannel* video_channel = new VideoChannel(
- worker_thread_, media_channel, transport_controller, content_name, rtcp);
+ worker_thread_, media_channel,
+ session, content_name, rtcp);
if (!video_channel->Init()) {
delete video_channel;
return NULL;
@@ -431,20 +441,16 @@
}
DataChannel* ChannelManager::CreateDataChannel(
- TransportController* transport_controller,
- const std::string& content_name,
- bool rtcp,
- DataChannelType channel_type) {
+ BaseSession* session, const std::string& content_name,
+ bool rtcp, DataChannelType channel_type) {
return worker_thread_->Invoke<DataChannel*>(
- Bind(&ChannelManager::CreateDataChannel_w, this, transport_controller,
- content_name, rtcp, channel_type));
+ Bind(&ChannelManager::CreateDataChannel_w, this, session, content_name,
+ rtcp, channel_type));
}
DataChannel* ChannelManager::CreateDataChannel_w(
- TransportController* transport_controller,
- const std::string& content_name,
- bool rtcp,
- DataChannelType data_channel_type) {
+ BaseSession* session, const std::string& content_name,
+ bool rtcp, DataChannelType data_channel_type) {
// This is ok to alloc from a thread other than the worker thread.
ASSERT(initialized_);
DataMediaChannel* media_channel = data_media_engine_->CreateChannel(
@@ -456,7 +462,8 @@
}
DataChannel* data_channel = new DataChannel(
- worker_thread_, media_channel, transport_controller, content_name, rtcp);
+ worker_thread_, media_channel,
+ session, content_name, rtcp);
if (!data_channel->Init()) {
LOG(LS_WARNING) << "Failed to init data channel.";
delete data_channel;
diff --git a/talk/session/media/channelmanager.h b/talk/session/media/channelmanager.h
index 31fec0e..3bfef84 100644
--- a/talk/session/media/channelmanager.h
+++ b/talk/session/media/channelmanager.h
@@ -105,10 +105,11 @@
void Terminate();
// The operations below all occur on the worker thread.
+
// Creates a voice channel, to be associated with the specified session.
VoiceChannel* CreateVoiceChannel(
webrtc::MediaControllerInterface* media_controller,
- TransportController* transport_controller,
+ BaseSession* session,
const std::string& content_name,
bool rtcp,
const AudioOptions& options);
@@ -118,16 +119,15 @@
// associated with the specified session.
VideoChannel* CreateVideoChannel(
webrtc::MediaControllerInterface* media_controller,
- TransportController* transport_controller,
+ BaseSession* session,
const std::string& content_name,
bool rtcp,
const VideoOptions& options);
// Destroys a video channel created with the Create API.
void DestroyVideoChannel(VideoChannel* video_channel);
- DataChannel* CreateDataChannel(TransportController* transport_controller,
- const std::string& content_name,
- bool rtcp,
- DataChannelType data_channel_type);
+ DataChannel* CreateDataChannel(
+ BaseSession* session, const std::string& content_name,
+ bool rtcp, DataChannelType data_channel_type);
// Destroys a data channel created with the Create API.
void DestroyDataChannel(DataChannel* data_channel);
@@ -251,22 +251,21 @@
void Terminate_w();
VoiceChannel* CreateVoiceChannel_w(
webrtc::MediaControllerInterface* media_controller,
- TransportController* transport_controller,
+ BaseSession* session,
const std::string& content_name,
bool rtcp,
const AudioOptions& options);
void DestroyVoiceChannel_w(VoiceChannel* voice_channel);
VideoChannel* CreateVideoChannel_w(
webrtc::MediaControllerInterface* media_controller,
- TransportController* transport_controller,
+ BaseSession* session,
const std::string& content_name,
bool rtcp,
const VideoOptions& options);
void DestroyVideoChannel_w(VideoChannel* video_channel);
- DataChannel* CreateDataChannel_w(TransportController* transport_controller,
- const std::string& content_name,
- bool rtcp,
- DataChannelType data_channel_type);
+ DataChannel* CreateDataChannel_w(
+ BaseSession* session, const std::string& content_name,
+ bool rtcp, DataChannelType data_channel_type);
void DestroyDataChannel_w(DataChannel* data_channel);
bool SetAudioOptions_w(const AudioOptions& options, int delay_offset,
const Device* in_dev, const Device* out_dev);
diff --git a/talk/session/media/channelmanager_unittest.cc b/talk/session/media/channelmanager_unittest.cc
index c699ee1..71493c8 100644
--- a/talk/session/media/channelmanager_unittest.cc
+++ b/talk/session/media/channelmanager_unittest.cc
@@ -32,11 +32,11 @@
#include "talk/media/base/testutils.h"
#include "talk/media/devices/fakedevicemanager.h"
#include "talk/media/webrtc/fakewebrtccall.h"
+#include "webrtc/p2p/base/fakesession.h"
#include "talk/session/media/channelmanager.h"
#include "webrtc/base/gunit.h"
#include "webrtc/base/logging.h"
#include "webrtc/base/thread.h"
-#include "webrtc/p2p/base/faketransportcontroller.h"
namespace cricket {
@@ -58,20 +58,14 @@
}
~FakeMediaController() override {}
webrtc::Call* call_w() override { return call_; }
-
private:
webrtc::Call* call_;
};
class ChannelManagerTest : public testing::Test {
protected:
- ChannelManagerTest()
- : fake_call_(webrtc::Call::Config()),
- fake_mc_(&fake_call_),
- fme_(NULL),
- fdm_(NULL),
- fcm_(NULL),
- cm_(NULL) {}
+ ChannelManagerTest() : fake_call_(webrtc::Call::Config()),
+ fake_mc_(&fake_call_), fme_(NULL), fdm_(NULL), fcm_(NULL), cm_(NULL) {}
virtual void SetUp() {
fme_ = new cricket::FakeMediaEngine();
@@ -82,8 +76,7 @@
fcm_ = new cricket::FakeCaptureManager();
cm_ = new cricket::ChannelManager(
fme_, fdme_, fdm_, fcm_, rtc::Thread::Current());
- transport_controller_ =
- new cricket::FakeTransportController(ICEROLE_CONTROLLING);
+ session_ = new cricket::FakeSession(true);
std::vector<std::string> in_device_list, out_device_list, vid_device_list;
in_device_list.push_back("audio-in1");
@@ -98,7 +91,7 @@
}
virtual void TearDown() {
- delete transport_controller_;
+ delete session_;
delete cm_;
cm_ = NULL;
fdm_ = NULL;
@@ -115,7 +108,7 @@
cricket::FakeDeviceManager* fdm_;
cricket::FakeCaptureManager* fcm_;
cricket::ChannelManager* cm_;
- cricket::FakeTransportController* transport_controller_;
+ cricket::FakeSession* session_;
};
// Test that we startup/shutdown properly.
@@ -146,16 +139,15 @@
// Test that we can create and destroy a voice and video channel.
TEST_F(ChannelManagerTest, CreateDestroyChannels) {
EXPECT_TRUE(cm_->Init());
- cricket::VoiceChannel* voice_channel =
- cm_->CreateVoiceChannel(&fake_mc_, transport_controller_,
- cricket::CN_AUDIO, false, AudioOptions());
+ cricket::VoiceChannel* voice_channel = cm_->CreateVoiceChannel(
+ &fake_mc_, session_, cricket::CN_AUDIO, false, AudioOptions());
EXPECT_TRUE(voice_channel != nullptr);
- cricket::VideoChannel* video_channel =
- cm_->CreateVideoChannel(&fake_mc_, transport_controller_,
- cricket::CN_VIDEO, false, VideoOptions());
+ cricket::VideoChannel* video_channel = cm_->CreateVideoChannel(
+ &fake_mc_, session_, cricket::CN_VIDEO, false, VideoOptions());
EXPECT_TRUE(video_channel != nullptr);
- cricket::DataChannel* data_channel = cm_->CreateDataChannel(
- transport_controller_, cricket::CN_DATA, false, cricket::DCT_RTP);
+ cricket::DataChannel* data_channel =
+ cm_->CreateDataChannel(session_, cricket::CN_DATA,
+ false, cricket::DCT_RTP);
EXPECT_TRUE(data_channel != nullptr);
cm_->DestroyVideoChannel(video_channel);
cm_->DestroyVoiceChannel(voice_channel);
@@ -168,19 +160,17 @@
worker_.Start();
EXPECT_TRUE(cm_->set_worker_thread(&worker_));
EXPECT_TRUE(cm_->Init());
- delete transport_controller_;
- transport_controller_ =
- new cricket::FakeTransportController(&worker_, ICEROLE_CONTROLLING);
- cricket::VoiceChannel* voice_channel =
- cm_->CreateVoiceChannel(&fake_mc_, transport_controller_,
- cricket::CN_AUDIO, false, AudioOptions());
+ delete session_;
+ session_ = new cricket::FakeSession(&worker_, true);
+ cricket::VoiceChannel* voice_channel = cm_->CreateVoiceChannel(
+ &fake_mc_, session_, cricket::CN_AUDIO, false, AudioOptions());
EXPECT_TRUE(voice_channel != nullptr);
- cricket::VideoChannel* video_channel =
- cm_->CreateVideoChannel(&fake_mc_, transport_controller_,
- cricket::CN_VIDEO, false, VideoOptions());
+ cricket::VideoChannel* video_channel = cm_->CreateVideoChannel(
+ &fake_mc_, session_, cricket::CN_VIDEO, false, VideoOptions());
EXPECT_TRUE(video_channel != nullptr);
- cricket::DataChannel* data_channel = cm_->CreateDataChannel(
- transport_controller_, cricket::CN_DATA, false, cricket::DCT_RTP);
+ cricket::DataChannel* data_channel =
+ cm_->CreateDataChannel(session_, cricket::CN_DATA,
+ false, cricket::DCT_RTP);
EXPECT_TRUE(data_channel != nullptr);
cm_->DestroyVideoChannel(video_channel);
cm_->DestroyVoiceChannel(voice_channel);
@@ -192,22 +182,21 @@
// to create a cricket::TransportChannel
TEST_F(ChannelManagerTest, NoTransportChannelTest) {
EXPECT_TRUE(cm_->Init());
- transport_controller_->set_fail_channel_creation(true);
+ session_->set_fail_channel_creation(true);
// The test is useless unless the session does not fail creating
// cricket::TransportChannel.
- ASSERT_TRUE(transport_controller_->CreateTransportChannel_w(
+ ASSERT_TRUE(session_->CreateChannel(
"audio", cricket::ICE_CANDIDATE_COMPONENT_RTP) == nullptr);
- cricket::VoiceChannel* voice_channel =
- cm_->CreateVoiceChannel(&fake_mc_, transport_controller_,
- cricket::CN_AUDIO, false, AudioOptions());
+ cricket::VoiceChannel* voice_channel = cm_->CreateVoiceChannel(
+ &fake_mc_, session_, cricket::CN_AUDIO, false, AudioOptions());
EXPECT_TRUE(voice_channel == nullptr);
- cricket::VideoChannel* video_channel =
- cm_->CreateVideoChannel(&fake_mc_, transport_controller_,
- cricket::CN_VIDEO, false, VideoOptions());
+ cricket::VideoChannel* video_channel = cm_->CreateVideoChannel(
+ &fake_mc_, session_, cricket::CN_VIDEO, false, VideoOptions());
EXPECT_TRUE(video_channel == nullptr);
- cricket::DataChannel* data_channel = cm_->CreateDataChannel(
- transport_controller_, cricket::CN_DATA, false, cricket::DCT_RTP);
+ cricket::DataChannel* data_channel =
+ cm_->CreateDataChannel(session_, cricket::CN_DATA,
+ false, cricket::DCT_RTP);
EXPECT_TRUE(data_channel == nullptr);
cm_->Terminate();
}
diff --git a/webrtc/base/fakenetwork.h b/webrtc/base/fakenetwork.h
index 065d08d..4b6bb68 100644
--- a/webrtc/base/fakenetwork.h
+++ b/webrtc/base/fakenetwork.h
@@ -29,7 +29,12 @@
class FakeNetworkManager : public NetworkManagerBase,
public MessageHandler {
public:
- FakeNetworkManager() : thread_(Thread::Current()) {}
+ FakeNetworkManager()
+ : thread_(Thread::Current()),
+ next_index_(0),
+ started_(false),
+ sent_first_update_(false) {
+ }
typedef std::vector<SocketAddress> IfaceList;
@@ -53,18 +58,20 @@
}
virtual void StartUpdating() {
- ++start_count_;
- if (start_count_ == 1) {
- sent_first_update_ = false;
- thread_->Post(this);
- } else {
- if (sent_first_update_) {
+ if (started_) {
+ if (sent_first_update_)
SignalNetworksChanged();
- }
+ return;
}
+
+ started_ = true;
+ sent_first_update_ = false;
+ thread_->Post(this);
}
- virtual void StopUpdating() { --start_count_; }
+ virtual void StopUpdating() {
+ started_ = false;
+ }
// MessageHandler interface.
virtual void OnMessage(Message* msg) {
@@ -75,7 +82,7 @@
private:
void DoUpdateNetworks() {
- if (start_count_ == 0)
+ if (!started_)
return;
std::vector<Network*> networks;
for (IfaceList::iterator it = ifaces_.begin();
@@ -104,9 +111,9 @@
Thread* thread_;
IfaceList ifaces_;
- int next_index_ = 0;
- int start_count_ = 0;
- bool sent_first_update_ = false;
+ int next_index_;
+ bool started_;
+ bool sent_first_update_;
};
} // namespace rtc
diff --git a/webrtc/p2p/base/dtlstransport.h b/webrtc/p2p/base/dtlstransport.h
index c448eb1..9559c1e 100644
--- a/webrtc/p2p/base/dtlstransport.h
+++ b/webrtc/p2p/base/dtlstransport.h
@@ -11,6 +11,7 @@
#ifndef WEBRTC_P2P_BASE_DTLSTRANSPORT_H_
#define WEBRTC_P2P_BASE_DTLSTRANSPORT_H_
+#include "webrtc/base/checks.h"
#include "webrtc/p2p/base/dtlstransportchannel.h"
#include "webrtc/p2p/base/transport.h"
@@ -22,31 +23,33 @@
class PortAllocator;
-// Base should be a descendant of cricket::Transport and have a constructor
-// that takes a transport name and PortAllocator.
-//
-// Everything in this class should be called on the worker thread.
+// Base should be a descendant of cricket::Transport
+// TODO(hbos): Add appropriate RTC_DCHECK thread checks to all methods.
template<class Base>
class DtlsTransport : public Base {
public:
- DtlsTransport(const std::string& name,
+ DtlsTransport(rtc::Thread* signaling_thread,
+ rtc::Thread* worker_thread,
+ const std::string& content_name,
PortAllocator* allocator,
const rtc::scoped_refptr<rtc::RTCCertificate>& certificate)
- : Base(name, allocator),
+ : Base(signaling_thread, worker_thread, content_name, allocator),
certificate_(certificate),
secure_role_(rtc::SSL_CLIENT),
- ssl_max_version_(rtc::SSL_PROTOCOL_DTLS_10) {}
+ ssl_max_version_(rtc::SSL_PROTOCOL_DTLS_10) {
+ }
~DtlsTransport() {
Base::DestroyAllChannels();
}
-
- void SetLocalCertificate(
+ void SetCertificate_w(
const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) override {
+ RTC_DCHECK(Base::worker_thread()->IsCurrent());
certificate_ = certificate;
}
- bool GetLocalCertificate(
+ bool GetCertificate_w(
rtc::scoped_refptr<rtc::RTCCertificate>* certificate) override {
+ RTC_DCHECK(Base::worker_thread()->IsCurrent());
if (!certificate_)
return false;
@@ -54,13 +57,15 @@
return true;
}
- bool SetSslMaxProtocolVersion(rtc::SSLProtocolVersion version) override {
+ bool SetSslMaxProtocolVersion_w(rtc::SSLProtocolVersion version) override {
+ RTC_DCHECK(Base::worker_thread()->IsCurrent());
ssl_max_version_ = version;
return true;
}
- bool ApplyLocalTransportDescription(TransportChannelImpl* channel,
- std::string* error_desc) override {
+ bool ApplyLocalTransportDescription_w(TransportChannelImpl* channel,
+ std::string* error_desc) override {
+ RTC_DCHECK(Base::worker_thread()->IsCurrent());
rtc::SSLFingerprint* local_fp =
Base::local_description()->identity_fingerprint.get();
@@ -93,11 +98,12 @@
}
// Apply the description in the base class.
- return Base::ApplyLocalTransportDescription(channel, error_desc);
+ return Base::ApplyLocalTransportDescription_w(channel, error_desc);
}
- bool NegotiateTransportDescription(ContentAction local_role,
- std::string* error_desc) override {
+ bool NegotiateTransportDescription_w(ContentAction local_role,
+ std::string* error_desc) override {
+ RTC_DCHECK(Base::worker_thread()->IsCurrent());
if (!Base::local_description() || !Base::remote_description()) {
const std::string msg = "Local and Remote description must be set before "
"transport descriptions are negotiated";
@@ -194,7 +200,7 @@
}
// Now run the negotiation for the base class.
- return Base::NegotiateTransportDescription(local_role, error_desc);
+ return Base::NegotiateTransportDescription_w(local_role, error_desc);
}
DtlsTransportChannelWrapper* CreateTransportChannel(int component) override {
@@ -213,15 +219,18 @@
Base::DestroyTransportChannel(base_channel);
}
- bool GetSslRole(rtc::SSLRole* ssl_role) const override {
+ bool GetSslRole_w(rtc::SSLRole* ssl_role) const override {
+ RTC_DCHECK(Base::worker_thread()->IsCurrent());
ASSERT(ssl_role != NULL);
*ssl_role = secure_role_;
return true;
}
private:
- bool ApplyNegotiatedTransportDescription(TransportChannelImpl* channel,
- std::string* error_desc) override {
+ bool ApplyNegotiatedTransportDescription_w(
+ TransportChannelImpl* channel,
+ std::string* error_desc) override {
+ RTC_DCHECK(Base::worker_thread()->IsCurrent());
// Set ssl role. Role must be set before fingerprint is applied, which
// initiates DTLS setup.
if (!channel->SetSslRole(secure_role_)) {
@@ -236,7 +245,7 @@
return BadTransportDescription("Failed to apply remote fingerprint.",
error_desc);
}
- return Base::ApplyNegotiatedTransportDescription(channel, error_desc);
+ return Base::ApplyNegotiatedTransportDescription_w(channel, error_desc);
}
rtc::scoped_refptr<rtc::RTCCertificate> certificate_;
diff --git a/webrtc/p2p/base/dtlstransportchannel.cc b/webrtc/p2p/base/dtlstransportchannel.cc
index d3651e0..3474237 100644
--- a/webrtc/p2p/base/dtlstransportchannel.cc
+++ b/webrtc/p2p/base/dtlstransportchannel.cc
@@ -87,9 +87,9 @@
}
DtlsTransportChannelWrapper::DtlsTransportChannelWrapper(
- Transport* transport,
- TransportChannelImpl* channel)
- : TransportChannelImpl(channel->transport_name(), channel->component()),
+ Transport* transport,
+ TransportChannelImpl* channel)
+ : TransportChannelImpl(channel->content_name(), channel->component()),
transport_(transport),
worker_thread_(rtc::Thread::Current()),
channel_(channel),
@@ -105,10 +105,12 @@
&DtlsTransportChannelWrapper::OnReadPacket);
channel_->SignalReadyToSend.connect(this,
&DtlsTransportChannelWrapper::OnReadyToSend);
- channel_->SignalGatheringState.connect(
- this, &DtlsTransportChannelWrapper::OnGatheringState);
- channel_->SignalCandidateGathered.connect(
- this, &DtlsTransportChannelWrapper::OnCandidateGathered);
+ channel_->SignalRequestSignaling.connect(this,
+ &DtlsTransportChannelWrapper::OnRequestSignaling);
+ channel_->SignalCandidateReady.connect(this,
+ &DtlsTransportChannelWrapper::OnCandidateReady);
+ channel_->SignalCandidatesAllocationDone.connect(this,
+ &DtlsTransportChannelWrapper::OnCandidatesAllocationDone);
channel_->SignalRoleConflict.connect(this,
&DtlsTransportChannelWrapper::OnRoleConflict);
channel_->SignalRouteChange.connect(this,
@@ -211,7 +213,7 @@
return true;
}
- // Allow SetRemoteFingerprint with a NULL digest even if SetLocalCertificate
+ // Allow SetRemoteFingerprint with a NULL digest even if SetLocalIdentity
// hasn't been called.
if (dtls_state_ > STATE_OFFERED ||
(dtls_state_ == STATE_NONE && !digest_alg.empty())) {
@@ -608,17 +610,22 @@
return downward_->OnPacketReceived(data, size);
}
-void DtlsTransportChannelWrapper::OnGatheringState(
+void DtlsTransportChannelWrapper::OnRequestSignaling(
TransportChannelImpl* channel) {
ASSERT(channel == channel_);
- SignalGatheringState(this);
+ SignalRequestSignaling(this);
}
-void DtlsTransportChannelWrapper::OnCandidateGathered(
- TransportChannelImpl* channel,
- const Candidate& c) {
+void DtlsTransportChannelWrapper::OnCandidateReady(
+ TransportChannelImpl* channel, const Candidate& c) {
ASSERT(channel == channel_);
- SignalCandidateGathered(this, c);
+ SignalCandidateReady(this, c);
+}
+
+void DtlsTransportChannelWrapper::OnCandidatesAllocationDone(
+ TransportChannelImpl* channel) {
+ ASSERT(channel == channel_);
+ SignalCandidatesAllocationDone(this);
}
void DtlsTransportChannelWrapper::OnRoleConflict(
diff --git a/webrtc/p2p/base/dtlstransportchannel.h b/webrtc/p2p/base/dtlstransportchannel.h
index 273291d..ddedcbc 100644
--- a/webrtc/p2p/base/dtlstransportchannel.h
+++ b/webrtc/p2p/base/dtlstransportchannel.h
@@ -27,7 +27,7 @@
// the bottom and a StreamInterface on the top.
class StreamInterfaceChannel : public rtc::StreamInterface {
public:
- explicit StreamInterfaceChannel(TransportChannel* channel);
+ StreamInterfaceChannel(TransportChannel* channel);
// Push in a packet; this gets pulled out from Read().
bool OnPacketReceived(const char* data, size_t size);
@@ -35,14 +35,10 @@
// Implementations of StreamInterface
rtc::StreamState GetState() const override { return state_; }
void Close() override { state_ = rtc::SS_CLOSED; }
- rtc::StreamResult Read(void* buffer,
- size_t buffer_len,
- size_t* read,
- int* error) override;
- rtc::StreamResult Write(const void* data,
- size_t data_len,
- size_t* written,
- int* error) override;
+ rtc::StreamResult Read(void* buffer, size_t buffer_len,
+ size_t* read, int* error) override;
+ rtc::StreamResult Write(const void* data, size_t data_len,
+ size_t* written, int* error) override;
private:
TransportChannel* channel_; // owned by DtlsTransportChannelWrapper
@@ -97,8 +93,12 @@
TransportChannelImpl* channel);
~DtlsTransportChannelWrapper() override;
- void SetIceRole(IceRole role) override { channel_->SetIceRole(role); }
- IceRole GetIceRole() const override { return channel_->GetIceRole(); }
+ void SetIceRole(IceRole role) override {
+ channel_->SetIceRole(role);
+ }
+ IceRole GetIceRole() const override {
+ return channel_->GetIceRole();
+ }
bool SetLocalCertificate(
const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) override;
rtc::scoped_refptr<rtc::RTCCertificate> GetLocalCertificate() const override;
@@ -109,8 +109,7 @@
bool IsDtlsActive() const override { return dtls_state_ != STATE_NONE; }
// Called to send a packet (via DTLS, if turned on).
- int SendPacket(const char* data,
- size_t size,
+ int SendPacket(const char* data, size_t size,
const rtc::PacketOptions& options,
int flags) override;
@@ -121,11 +120,15 @@
bool GetOption(rtc::Socket::Option opt, int* value) override {
return channel_->GetOption(opt, value);
}
- int GetError() override { return channel_->GetError(); }
+ int GetError() override {
+ return channel_->GetError();
+ }
bool GetStats(ConnectionInfos* infos) override {
return channel_->GetStats(infos);
}
- const std::string SessionId() const override { return channel_->SessionId(); }
+ const std::string SessionId() const override {
+ return channel_->SessionId();
+ }
virtual bool SetSslMaxProtocolVersion(rtc::SSLProtocolVersion version);
@@ -165,7 +168,9 @@
}
// TransportChannelImpl calls.
- Transport* GetTransport() override { return transport_; }
+ Transport* GetTransport() override {
+ return transport_;
+ }
TransportChannelState GetState() const override {
return channel_->GetState();
@@ -187,12 +192,11 @@
void Connect() override;
- IceGatheringState gathering_state() const override {
- return channel_->gathering_state();
+ void OnSignalingReady() override {
+ channel_->OnSignalingReady();
}
-
- void AddRemoteCandidate(const Candidate& candidate) override {
- channel_->AddRemoteCandidate(candidate);
+ void OnCandidate(const Candidate& candidate) override {
+ channel_->OnCandidate(candidate);
}
void SetReceivingTimeout(int receiving_timeout_ms) override {
@@ -213,8 +217,9 @@
bool SetupDtls();
bool MaybeStartDtls();
bool HandleDtlsPacket(const char* data, size_t size);
- void OnGatheringState(TransportChannelImpl* channel);
- void OnCandidateGathered(TransportChannelImpl* channel, const Candidate& c);
+ void OnRequestSignaling(TransportChannelImpl* channel);
+ void OnCandidateReady(TransportChannelImpl* channel, const Candidate& c);
+ void OnCandidatesAllocationDone(TransportChannelImpl* channel);
void OnRoleConflict(TransportChannelImpl* channel);
void OnRouteChange(TransportChannel* channel, const Candidate& candidate);
void OnConnectionRemoved(TransportChannelImpl* channel);
diff --git a/webrtc/p2p/base/dtlstransportchannel_unittest.cc b/webrtc/p2p/base/dtlstransportchannel_unittest.cc
index 95696e2..10640f9 100644
--- a/webrtc/p2p/base/dtlstransportchannel_unittest.cc
+++ b/webrtc/p2p/base/dtlstransportchannel_unittest.cc
@@ -11,7 +11,7 @@
#include <set>
#include "webrtc/p2p/base/dtlstransport.h"
-#include "webrtc/p2p/base/faketransportcontroller.h"
+#include "webrtc/p2p/base/fakesession.h"
#include "webrtc/base/common.h"
#include "webrtc/base/dscp.h"
#include "webrtc/base/gunit.h"
@@ -21,6 +21,7 @@
#include "webrtc/base/sslidentity.h"
#include "webrtc/base/sslstreamadapter.h"
#include "webrtc/base/stringutils.h"
+#include "webrtc/base/thread.h"
#define MAYBE_SKIP_TEST(feature) \
if (!(rtc::SSLStreamAdapter::feature())) { \
@@ -44,14 +45,19 @@
class DtlsTestClient : public sigslot::has_slots<> {
public:
- DtlsTestClient(const std::string& name)
- : name_(name),
- packet_size_(0),
- use_dtls_srtp_(false),
- ssl_max_version_(rtc::SSL_PROTOCOL_DTLS_10),
- negotiated_dtls_(false),
- received_dtls_client_hello_(false),
- received_dtls_server_hello_(false) {}
+ DtlsTestClient(const std::string& name,
+ rtc::Thread* signaling_thread,
+ rtc::Thread* worker_thread) :
+ name_(name),
+ signaling_thread_(signaling_thread),
+ worker_thread_(worker_thread),
+ packet_size_(0),
+ use_dtls_srtp_(false),
+ ssl_max_version_(rtc::SSL_PROTOCOL_DTLS_10),
+ negotiated_dtls_(false),
+ received_dtls_client_hello_(false),
+ received_dtls_server_hello_(false) {
+ }
void CreateCertificate(rtc::KeyType key_type) {
certificate_ = rtc::RTCCertificate::Create(
rtc::scoped_ptr<rtc::SSLIdentity>(
@@ -65,12 +71,13 @@
use_dtls_srtp_ = true;
}
void SetupMaxProtocolVersion(rtc::SSLProtocolVersion version) {
- ASSERT(!transport_);
+ ASSERT(transport_.get() == NULL);
ssl_max_version_ = version;
}
void SetupChannels(int count, cricket::IceRole role) {
transport_.reset(new cricket::DtlsTransport<cricket::FakeTransport>(
- "dtls content name", nullptr, certificate_));
+ signaling_thread_, worker_thread_, "dtls content name", nullptr,
+ certificate_));
transport_->SetAsync(true);
transport_->SetIceRole(role);
transport_->SetIceTiebreaker(
@@ -111,8 +118,8 @@
void Negotiate(DtlsTestClient* peer, cricket::ContentAction action,
ConnectionRole local_role, ConnectionRole remote_role,
int flags) {
- Negotiate(certificate_, certificate_ ? peer->certificate_ : nullptr, action,
- local_role, remote_role, flags);
+ Negotiate(certificate_, certificate_ ? peer->certificate_ : nullptr,
+ action, local_role, remote_role, flags);
}
// Allow any DTLS configuration to be specified (including invalid ones).
@@ -156,18 +163,18 @@
}
cricket::TransportDescription local_desc(
- std::vector<std::string>(), kIceUfrag1, kIcePwd1, cricket::ICEMODE_FULL,
- local_role,
- // If remote if the offerer and has no DTLS support, answer will be
+ std::vector<std::string>(), kIceUfrag1, kIcePwd1,
+ cricket::ICEMODE_FULL, local_role,
+ // If remote if the offerer and has no DTLS support, answer will be
// without any fingerprint.
- (action == cricket::CA_ANSWER && !remote_cert)
- ? nullptr
- : local_fingerprint.get(),
+ (action == cricket::CA_ANSWER && !remote_cert) ?
+ NULL : local_fingerprint.get(),
cricket::Candidates());
cricket::TransportDescription remote_desc(
- std::vector<std::string>(), kIceUfrag1, kIcePwd1, cricket::ICEMODE_FULL,
- remote_role, remote_fingerprint.get(), cricket::Candidates());
+ std::vector<std::string>(), kIceUfrag1, kIcePwd1,
+ cricket::ICEMODE_FULL, remote_role, remote_fingerprint.get(),
+ cricket::Candidates());
bool expect_success = (flags & NF_EXPECT_FAILURE) ? false : true;
// If |expect_success| is false, expect SRTD or SLTD to fail when
@@ -192,9 +199,7 @@
return true;
}
- bool all_channels_writable() const {
- return transport_->all_channels_writable();
- }
+ bool writable() const { return transport_->writable(); }
void CheckRole(rtc::SSLRole role) {
if (role == rtc::SSL_CLIENT) {
@@ -332,8 +337,8 @@
ASSERT_TRUE(VerifyPacket(data, size, &packet_num));
received_.insert(packet_num);
// Only DTLS-SRTP packets should have the bypass flag set.
- int expected_flags =
- (certificate_ && IsRtpLeadByte(data[0])) ? cricket::PF_SRTP_BYPASS : 0;
+ int expected_flags = (certificate_ && IsRtpLeadByte(data[0])) ?
+ cricket::PF_SRTP_BYPASS : 0;
ASSERT_EQ(expected_flags, flags);
}
@@ -367,6 +372,8 @@
private:
std::string name_;
+ rtc::Thread* signaling_thread_;
+ rtc::Thread* worker_thread_;
rtc::scoped_refptr<rtc::RTCCertificate> certificate_;
rtc::scoped_ptr<cricket::FakeTransport> transport_;
std::vector<cricket::DtlsTransportChannelWrapper*> channels_;
@@ -382,13 +389,16 @@
class DtlsTransportChannelTest : public testing::Test {
public:
- DtlsTransportChannelTest()
- : client1_("P1"),
- client2_("P2"),
- channel_ct_(1),
- use_dtls_(false),
- use_dtls_srtp_(false),
- ssl_expected_version_(rtc::SSL_PROTOCOL_DTLS_10) {}
+ DtlsTransportChannelTest() :
+ client1_("P1", rtc::Thread::Current(),
+ rtc::Thread::Current()),
+ client2_("P2", rtc::Thread::Current(),
+ rtc::Thread::Current()),
+ channel_ct_(1),
+ use_dtls_(false),
+ use_dtls_srtp_(false),
+ ssl_expected_version_(rtc::SSL_PROTOCOL_DTLS_10) {
+ }
void SetChannelCount(size_t channel_ct) {
channel_ct_ = static_cast<int>(channel_ct);
@@ -430,10 +440,8 @@
if (!rv)
return false;
- EXPECT_TRUE_WAIT(
- client1_.all_channels_writable() && client2_.all_channels_writable(),
- 10000);
- if (!client1_.all_channels_writable() || !client2_.all_channels_writable())
+ EXPECT_TRUE_WAIT(client1_.writable() && client2_.writable(), 10000);
+ if (!client1_.writable() || !client2_.writable())
return false;
// Check that we used the right roles.
@@ -810,9 +818,7 @@
cricket::CONNECTIONROLE_ACTIVE, NF_REOFFER);
bool rv = client1_.Connect(&client2_);
EXPECT_TRUE(rv);
- EXPECT_TRUE_WAIT(
- client1_.all_channels_writable() && client2_.all_channels_writable(),
- 10000);
+ EXPECT_TRUE_WAIT(client1_.writable() && client2_.writable(), 10000);
TestTransfer(0, 1000, 100, true);
TestTransfer(1, 1000, 100, true);
@@ -831,8 +837,8 @@
// After negotiation, each side has a distinct local certificate, but still no
// remote certificate, because connection has not yet occurred.
- ASSERT_TRUE(client1_.transport()->GetLocalCertificate(&certificate1));
- ASSERT_TRUE(client2_.transport()->GetLocalCertificate(&certificate2));
+ ASSERT_TRUE(client1_.transport()->GetCertificate(&certificate1));
+ ASSERT_TRUE(client2_.transport()->GetCertificate(&certificate2));
ASSERT_NE(certificate1->ssl_certificate().ToPEMString(),
certificate2->ssl_certificate().ToPEMString());
ASSERT_FALSE(
@@ -855,8 +861,8 @@
rtc::scoped_ptr<rtc::SSLCertificate> remote_cert2;
// After connection, each side has a distinct local certificate.
- ASSERT_TRUE(client1_.transport()->GetLocalCertificate(&certificate1));
- ASSERT_TRUE(client2_.transport()->GetLocalCertificate(&certificate2));
+ ASSERT_TRUE(client1_.transport()->GetCertificate(&certificate1));
+ ASSERT_TRUE(client2_.transport()->GetCertificate(&certificate2));
ASSERT_NE(certificate1->ssl_certificate().ToPEMString(),
certificate2->ssl_certificate().ToPEMString());
diff --git a/webrtc/p2p/base/fakesession.h b/webrtc/p2p/base/fakesession.h
new file mode 100644
index 0000000..bd3c089
--- /dev/null
+++ b/webrtc/p2p/base/fakesession.h
@@ -0,0 +1,506 @@
+/*
+ * Copyright 2009 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_P2P_BASE_FAKESESSION_H_
+#define WEBRTC_P2P_BASE_FAKESESSION_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "webrtc/p2p/base/session.h"
+#include "webrtc/p2p/base/transport.h"
+#include "webrtc/p2p/base/transportchannel.h"
+#include "webrtc/p2p/base/transportchannelimpl.h"
+#include "webrtc/base/buffer.h"
+#include "webrtc/base/fakesslidentity.h"
+#include "webrtc/base/messagequeue.h"
+#include "webrtc/base/sigslot.h"
+#include "webrtc/base/sslfingerprint.h"
+
+namespace cricket {
+
+class FakeTransport;
+
+struct PacketMessageData : public rtc::MessageData {
+ PacketMessageData(const char* data, size_t len) : packet(data, len) {
+ }
+ rtc::Buffer packet;
+};
+
+// Fake transport channel class, which can be passed to anything that needs a
+// transport channel. Can be informed of another FakeTransportChannel via
+// SetDestination.
+// TODO(hbos): Move implementation to .cc file, this and other classes in file.
+class FakeTransportChannel : public TransportChannelImpl,
+ public rtc::MessageHandler {
+ public:
+ explicit FakeTransportChannel(Transport* transport,
+ const std::string& content_name,
+ int component)
+ : TransportChannelImpl(content_name, component),
+ transport_(transport),
+ dest_(nullptr),
+ state_(STATE_INIT),
+ async_(false),
+ do_dtls_(false),
+ role_(ICEROLE_UNKNOWN),
+ tiebreaker_(0),
+ remote_ice_mode_(ICEMODE_FULL),
+ dtls_fingerprint_("", nullptr, 0),
+ ssl_role_(rtc::SSL_CLIENT),
+ connection_count_(0) {
+ }
+ ~FakeTransportChannel() {
+ Reset();
+ }
+
+ uint64 IceTiebreaker() const { return tiebreaker_; }
+ IceMode remote_ice_mode() const { return remote_ice_mode_; }
+ const std::string& ice_ufrag() const { return ice_ufrag_; }
+ const std::string& ice_pwd() const { return ice_pwd_; }
+ const std::string& remote_ice_ufrag() const { return remote_ice_ufrag_; }
+ const std::string& remote_ice_pwd() const { return remote_ice_pwd_; }
+ const rtc::SSLFingerprint& dtls_fingerprint() const {
+ return dtls_fingerprint_;
+ }
+
+ void SetAsync(bool async) {
+ async_ = async;
+ }
+
+ Transport* GetTransport() override {
+ return transport_;
+ }
+
+ TransportChannelState GetState() const override {
+ if (connection_count_ == 0) {
+ return TransportChannelState::STATE_FAILED;
+ }
+
+ if (connection_count_ == 1) {
+ return TransportChannelState::STATE_COMPLETED;
+ }
+
+ return TransportChannelState::STATE_FAILED;
+ }
+
+ void SetIceRole(IceRole role) override { role_ = role; }
+ IceRole GetIceRole() const override { return role_; }
+ void SetIceTiebreaker(uint64 tiebreaker) override {
+ tiebreaker_ = tiebreaker;
+ }
+ void SetIceCredentials(const std::string& ice_ufrag,
+ const std::string& ice_pwd) override {
+ ice_ufrag_ = ice_ufrag;
+ ice_pwd_ = ice_pwd;
+ }
+ void SetRemoteIceCredentials(const std::string& ice_ufrag,
+ const std::string& ice_pwd) override {
+ remote_ice_ufrag_ = ice_ufrag;
+ remote_ice_pwd_ = ice_pwd;
+ }
+
+ void SetRemoteIceMode(IceMode mode) override { remote_ice_mode_ = mode; }
+ bool SetRemoteFingerprint(const std::string& alg, const uint8* digest,
+ size_t digest_len) override {
+ dtls_fingerprint_ = rtc::SSLFingerprint(alg, digest, digest_len);
+ return true;
+ }
+ bool SetSslRole(rtc::SSLRole role) override {
+ ssl_role_ = role;
+ return true;
+ }
+ bool GetSslRole(rtc::SSLRole* role) const override {
+ *role = ssl_role_;
+ return true;
+ }
+
+ void Connect() override {
+ if (state_ == STATE_INIT) {
+ state_ = STATE_CONNECTING;
+ }
+ }
+ virtual void Reset() {
+ if (state_ != STATE_INIT) {
+ state_ = STATE_INIT;
+ if (dest_) {
+ dest_->state_ = STATE_INIT;
+ dest_->dest_ = NULL;
+ dest_ = NULL;
+ }
+ }
+ }
+
+ void SetWritable(bool writable) {
+ set_writable(writable);
+ }
+
+ void SetDestination(FakeTransportChannel* dest) {
+ if (state_ == STATE_CONNECTING && dest) {
+ // This simulates the delivery of candidates.
+ dest_ = dest;
+ dest_->dest_ = this;
+ if (certificate_ && dest_->certificate_) {
+ do_dtls_ = true;
+ dest_->do_dtls_ = true;
+ NegotiateSrtpCiphers();
+ }
+ state_ = STATE_CONNECTED;
+ dest_->state_ = STATE_CONNECTED;
+ set_writable(true);
+ dest_->set_writable(true);
+ } else if (state_ == STATE_CONNECTED && !dest) {
+ // Simulates loss of connectivity, by asymmetrically forgetting dest_.
+ dest_ = NULL;
+ state_ = STATE_CONNECTING;
+ set_writable(false);
+ }
+ }
+
+ void SetConnectionCount(size_t connection_count) {
+ size_t old_connection_count = connection_count_;
+ connection_count_ = connection_count;
+ if (connection_count_ < old_connection_count)
+ SignalConnectionRemoved(this);
+ }
+
+ void SetReceiving(bool receiving) {
+ set_receiving(receiving);
+ }
+
+ void SetReceivingTimeout(int timeout) override {}
+
+ int SendPacket(const char* data, size_t len,
+ const rtc::PacketOptions& options, int flags) override {
+ if (state_ != STATE_CONNECTED) {
+ return -1;
+ }
+
+ if (flags != PF_SRTP_BYPASS && flags != 0) {
+ return -1;
+ }
+
+ PacketMessageData* packet = new PacketMessageData(data, len);
+ if (async_) {
+ rtc::Thread::Current()->Post(this, 0, packet);
+ } else {
+ rtc::Thread::Current()->Send(this, 0, packet);
+ }
+ return static_cast<int>(len);
+ }
+ int SetOption(rtc::Socket::Option opt, int value) override {
+ return true;
+ }
+ bool GetOption(rtc::Socket::Option opt, int* value) override {
+ return true;
+ }
+ int GetError() override {
+ return 0;
+ }
+
+ void OnSignalingReady() override {
+ }
+ void OnCandidate(const Candidate& candidate) override {
+ }
+
+ void OnMessage(rtc::Message* msg) override {
+ PacketMessageData* data = static_cast<PacketMessageData*>(
+ msg->pdata);
+ dest_->SignalReadPacket(dest_, data->packet.data<char>(),
+ data->packet.size(), rtc::CreatePacketTime(0), 0);
+ delete data;
+ }
+
+ bool SetLocalCertificate(
+ const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) override {
+ certificate_ = certificate;
+ return true;
+ }
+
+ void SetRemoteSSLCertificate(rtc::FakeSSLCertificate* cert) {
+ remote_cert_ = cert;
+ }
+
+ bool IsDtlsActive() const override {
+ return do_dtls_;
+ }
+
+ bool SetSrtpCiphers(const std::vector<std::string>& ciphers) override {
+ srtp_ciphers_ = ciphers;
+ return true;
+ }
+
+ bool GetSrtpCipher(std::string* cipher) override {
+ if (!chosen_srtp_cipher_.empty()) {
+ *cipher = chosen_srtp_cipher_;
+ return true;
+ }
+ return false;
+ }
+
+ bool GetSslCipher(std::string* cipher) override {
+ return false;
+ }
+
+ rtc::scoped_refptr<rtc::RTCCertificate>
+ GetLocalCertificate() const override {
+ return certificate_;
+ }
+
+ bool GetRemoteSSLCertificate(rtc::SSLCertificate** cert) const override {
+ if (!remote_cert_)
+ return false;
+
+ *cert = remote_cert_->GetReference();
+ return true;
+ }
+
+ bool ExportKeyingMaterial(const std::string& label,
+ const uint8* context,
+ size_t context_len,
+ bool use_context,
+ uint8* result,
+ size_t result_len) override {
+ if (!chosen_srtp_cipher_.empty()) {
+ memset(result, 0xff, result_len);
+ return true;
+ }
+
+ return false;
+ }
+
+ virtual void NegotiateSrtpCiphers() {
+ for (std::vector<std::string>::const_iterator it1 = srtp_ciphers_.begin();
+ it1 != srtp_ciphers_.end(); ++it1) {
+ for (std::vector<std::string>::const_iterator it2 =
+ dest_->srtp_ciphers_.begin();
+ it2 != dest_->srtp_ciphers_.end(); ++it2) {
+ if (*it1 == *it2) {
+ chosen_srtp_cipher_ = *it1;
+ dest_->chosen_srtp_cipher_ = *it2;
+ return;
+ }
+ }
+ }
+ }
+
+ bool GetStats(ConnectionInfos* infos) override {
+ ConnectionInfo info;
+ infos->clear();
+ infos->push_back(info);
+ return true;
+ }
+
+ private:
+ enum State { STATE_INIT, STATE_CONNECTING, STATE_CONNECTED };
+ Transport* transport_;
+ FakeTransportChannel* dest_;
+ State state_;
+ bool async_;
+ rtc::scoped_refptr<rtc::RTCCertificate> certificate_;
+ rtc::FakeSSLCertificate* remote_cert_;
+ bool do_dtls_;
+ std::vector<std::string> srtp_ciphers_;
+ std::string chosen_srtp_cipher_;
+ IceRole role_;
+ uint64 tiebreaker_;
+ std::string ice_ufrag_;
+ std::string ice_pwd_;
+ std::string remote_ice_ufrag_;
+ std::string remote_ice_pwd_;
+ IceMode remote_ice_mode_;
+ rtc::SSLFingerprint dtls_fingerprint_;
+ rtc::SSLRole ssl_role_;
+ size_t connection_count_;
+};
+
+// Fake transport class, which can be passed to anything that needs a Transport.
+// Can be informed of another FakeTransport via SetDestination (low-tech way
+// of doing candidates)
+class FakeTransport : public Transport {
+ public:
+ typedef std::map<int, FakeTransportChannel*> ChannelMap;
+ FakeTransport(rtc::Thread* signaling_thread,
+ rtc::Thread* worker_thread,
+ const std::string& content_name,
+ PortAllocator* alllocator = nullptr)
+ : Transport(signaling_thread, worker_thread,
+ content_name, nullptr),
+ dest_(nullptr),
+ async_(false) {
+ }
+ ~FakeTransport() {
+ DestroyAllChannels();
+ }
+
+ const ChannelMap& channels() const { return channels_; }
+
+ void SetAsync(bool async) { async_ = async; }
+ void SetDestination(FakeTransport* dest) {
+ dest_ = dest;
+ for (ChannelMap::iterator it = channels_.begin(); it != channels_.end();
+ ++it) {
+ it->second->SetLocalCertificate(certificate_);
+ SetChannelDestination(it->first, it->second);
+ }
+ }
+
+ void SetWritable(bool writable) {
+ for (ChannelMap::iterator it = channels_.begin(); it != channels_.end();
+ ++it) {
+ it->second->SetWritable(writable);
+ }
+ }
+
+ void set_certificate(
+ const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) {
+ certificate_ = certificate;
+ }
+
+ using Transport::local_description;
+ using Transport::remote_description;
+
+ protected:
+ TransportChannelImpl* CreateTransportChannel(int component) override {
+ if (channels_.find(component) != channels_.end()) {
+ return NULL;
+ }
+ FakeTransportChannel* channel =
+ new FakeTransportChannel(this, content_name(), component);
+ channel->SetAsync(async_);
+ SetChannelDestination(component, channel);
+ channels_[component] = channel;
+ return channel;
+ }
+ void DestroyTransportChannel(TransportChannelImpl* channel) override {
+ channels_.erase(channel->component());
+ delete channel;
+ }
+ void SetCertificate_w(
+ const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) override {
+ certificate_ = certificate;
+ }
+ bool GetCertificate_w(
+ rtc::scoped_refptr<rtc::RTCCertificate>* certificate) override {
+ if (!certificate_)
+ return false;
+
+ *certificate = certificate_;
+ return true;
+ }
+
+ private:
+ FakeTransportChannel* GetFakeChannel(int component) {
+ ChannelMap::iterator it = channels_.find(component);
+ return (it != channels_.end()) ? it->second : NULL;
+ }
+ void SetChannelDestination(int component,
+ FakeTransportChannel* channel) {
+ FakeTransportChannel* dest_channel = NULL;
+ if (dest_) {
+ dest_channel = dest_->GetFakeChannel(component);
+ if (dest_channel)
+ dest_channel->SetLocalCertificate(dest_->certificate_);
+ }
+ channel->SetDestination(dest_channel);
+ }
+
+ // Note, this is distinct from the Channel map owned by Transport.
+ // This map just tracks the FakeTransportChannels created by this class.
+ ChannelMap channels_;
+ FakeTransport* dest_;
+ bool async_;
+ rtc::scoped_refptr<rtc::RTCCertificate> certificate_;
+};
+
+// Fake session class, which can be passed into a BaseChannel object for
+// test purposes. Can be connected to other FakeSessions via Connect().
+class FakeSession : public BaseSession {
+ public:
+ explicit FakeSession()
+ : BaseSession(rtc::Thread::Current(),
+ rtc::Thread::Current(),
+ NULL, "", "", true),
+ fail_create_channel_(false) {
+ }
+ explicit FakeSession(bool initiator)
+ : BaseSession(rtc::Thread::Current(),
+ rtc::Thread::Current(),
+ NULL, "", "", initiator),
+ fail_create_channel_(false) {
+ }
+ FakeSession(rtc::Thread* worker_thread, bool initiator)
+ : BaseSession(rtc::Thread::Current(),
+ worker_thread,
+ NULL, "", "", initiator),
+ fail_create_channel_(false) {
+ }
+
+ FakeTransport* GetTransport(const std::string& content_name) {
+ return static_cast<FakeTransport*>(
+ BaseSession::GetTransport(content_name));
+ }
+
+ void Connect(FakeSession* dest) {
+ // Simulate the exchange of candidates.
+ CompleteNegotiation();
+ dest->CompleteNegotiation();
+ for (TransportMap::const_iterator it = transport_proxies().begin();
+ it != transport_proxies().end(); ++it) {
+ static_cast<FakeTransport*>(it->second->impl())->SetDestination(
+ dest->GetTransport(it->first));
+ }
+ }
+
+ TransportChannel* CreateChannel(const std::string& content_name,
+ int component) override {
+ if (fail_create_channel_) {
+ return NULL;
+ }
+ return BaseSession::CreateChannel(content_name, component);
+ }
+
+ void set_fail_channel_creation(bool fail_channel_creation) {
+ fail_create_channel_ = fail_channel_creation;
+ }
+
+ // TODO: Hoist this into Session when we re-work the Session code.
+ void set_ssl_rtccertificate(
+ const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) {
+ for (TransportMap::const_iterator it = transport_proxies().begin();
+ it != transport_proxies().end(); ++it) {
+ // We know that we have a FakeTransport*
+
+ static_cast<FakeTransport*>(it->second->impl())->set_certificate
+ (certificate);
+ }
+ }
+
+ protected:
+ Transport* CreateTransport(const std::string& content_name) override {
+ return new FakeTransport(signaling_thread(), worker_thread(), content_name);
+ }
+
+ void CompleteNegotiation() {
+ for (TransportMap::const_iterator it = transport_proxies().begin();
+ it != transport_proxies().end(); ++it) {
+ it->second->CompleteNegotiation();
+ it->second->ConnectChannels();
+ }
+ }
+
+ private:
+ bool fail_create_channel_;
+};
+
+} // namespace cricket
+
+#endif // WEBRTC_P2P_BASE_FAKESESSION_H_
diff --git a/webrtc/p2p/base/faketransportcontroller.h b/webrtc/p2p/base/faketransportcontroller.h
deleted file mode 100644
index 4fbee23..0000000
--- a/webrtc/p2p/base/faketransportcontroller.h
+++ /dev/null
@@ -1,534 +0,0 @@
-/*
- * Copyright 2009 The WebRTC Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef WEBRTC_P2P_BASE_FAKETRANSPORTCONTROLLER_H_
-#define WEBRTC_P2P_BASE_FAKETRANSPORTCONTROLLER_H_
-
-#include <map>
-#include <string>
-#include <vector>
-
-#include "webrtc/p2p/base/transport.h"
-#include "webrtc/p2p/base/transportchannel.h"
-#include "webrtc/p2p/base/transportcontroller.h"
-#include "webrtc/p2p/base/transportchannelimpl.h"
-#include "webrtc/base/bind.h"
-#include "webrtc/base/buffer.h"
-#include "webrtc/base/fakesslidentity.h"
-#include "webrtc/base/messagequeue.h"
-#include "webrtc/base/sigslot.h"
-#include "webrtc/base/sslfingerprint.h"
-#include "webrtc/base/thread.h"
-
-namespace cricket {
-
-class FakeTransport;
-
-struct PacketMessageData : public rtc::MessageData {
- PacketMessageData(const char* data, size_t len) : packet(data, len) {}
- rtc::Buffer packet;
-};
-
-// Fake transport channel class, which can be passed to anything that needs a
-// transport channel. Can be informed of another FakeTransportChannel via
-// SetDestination.
-// TODO(hbos): Move implementation to .cc file, this and other classes in file.
-class FakeTransportChannel : public TransportChannelImpl,
- public rtc::MessageHandler {
- public:
- explicit FakeTransportChannel(Transport* transport,
- const std::string& name,
- int component)
- : TransportChannelImpl(name, component),
- transport_(transport),
- dtls_fingerprint_("", nullptr, 0) {}
- ~FakeTransportChannel() { Reset(); }
-
- uint64 IceTiebreaker() const { return tiebreaker_; }
- IceMode remote_ice_mode() const { return remote_ice_mode_; }
- const std::string& ice_ufrag() const { return ice_ufrag_; }
- const std::string& ice_pwd() const { return ice_pwd_; }
- const std::string& remote_ice_ufrag() const { return remote_ice_ufrag_; }
- const std::string& remote_ice_pwd() const { return remote_ice_pwd_; }
- const rtc::SSLFingerprint& dtls_fingerprint() const {
- return dtls_fingerprint_;
- }
-
- // If async, will send packets by "Post"-ing to message queue instead of
- // synchronously "Send"-ing.
- void SetAsync(bool async) { async_ = async; }
-
- Transport* GetTransport() override { return transport_; }
-
- TransportChannelState GetState() const override {
- if (connection_count_ == 0) {
- return had_connection_ ? TransportChannelState::STATE_FAILED
- : TransportChannelState::STATE_INIT;
- }
-
- if (connection_count_ == 1) {
- return TransportChannelState::STATE_COMPLETED;
- }
-
- return TransportChannelState::STATE_CONNECTING;
- }
-
- void SetIceRole(IceRole role) override { role_ = role; }
- IceRole GetIceRole() const override { return role_; }
- void SetIceTiebreaker(uint64 tiebreaker) override {
- tiebreaker_ = tiebreaker;
- }
- void SetIceCredentials(const std::string& ice_ufrag,
- const std::string& ice_pwd) override {
- ice_ufrag_ = ice_ufrag;
- ice_pwd_ = ice_pwd;
- }
- void SetRemoteIceCredentials(const std::string& ice_ufrag,
- const std::string& ice_pwd) override {
- remote_ice_ufrag_ = ice_ufrag;
- remote_ice_pwd_ = ice_pwd;
- }
-
- void SetRemoteIceMode(IceMode mode) override { remote_ice_mode_ = mode; }
- bool SetRemoteFingerprint(const std::string& alg,
- const uint8* digest,
- size_t digest_len) override {
- dtls_fingerprint_ = rtc::SSLFingerprint(alg, digest, digest_len);
- return true;
- }
- bool SetSslRole(rtc::SSLRole role) override {
- ssl_role_ = role;
- return true;
- }
- bool GetSslRole(rtc::SSLRole* role) const override {
- *role = ssl_role_;
- return true;
- }
-
- void Connect() override {
- if (state_ == STATE_INIT) {
- state_ = STATE_CONNECTING;
- // Connect is expected to start candidate gathering
- if (gathering_state_ != kIceGatheringGathering) {
- gathering_state_ = kIceGatheringGathering;
- SignalGatheringState(this);
- }
- }
- }
-
- IceGatheringState gathering_state() const override {
- return gathering_state_;
- }
-
- void Reset() {
- if (state_ != STATE_INIT) {
- state_ = STATE_INIT;
- if (dest_) {
- dest_->state_ = STATE_INIT;
- dest_->dest_ = nullptr;
- dest_ = nullptr;
- }
- }
- }
-
- void SetWritable(bool writable) { set_writable(writable); }
-
- void SetDestination(FakeTransportChannel* dest) {
- if (state_ == STATE_CONNECTING && dest) {
- // This simulates the delivery of candidates.
- dest_ = dest;
- dest_->dest_ = this;
- if (local_cert_ && dest_->local_cert_) {
- do_dtls_ = true;
- dest_->do_dtls_ = true;
- NegotiateSrtpCiphers();
- }
- state_ = STATE_CONNECTED;
- dest_->state_ = STATE_CONNECTED;
- set_writable(true);
- dest_->set_writable(true);
- } else if (state_ == STATE_CONNECTED && !dest) {
- // Simulates loss of connectivity, by asymmetrically forgetting dest_.
- dest_ = nullptr;
- state_ = STATE_CONNECTING;
- set_writable(false);
- }
- }
-
- void SetConnectionCount(size_t connection_count) {
- size_t old_connection_count = connection_count_;
- connection_count_ = connection_count;
- if (connection_count)
- had_connection_ = true;
- if (connection_count_ < old_connection_count)
- SignalConnectionRemoved(this);
- }
-
- void SetCandidatesGatheringComplete() {
- if (gathering_state_ != kIceGatheringComplete) {
- gathering_state_ = kIceGatheringComplete;
- SignalGatheringState(this);
- }
- }
-
- void SetReceiving(bool receiving) { set_receiving(receiving); }
-
- void SetReceivingTimeout(int timeout) override {
- receiving_timeout_ = timeout;
- }
-
- int receiving_timeout() const { return receiving_timeout_; }
-
- int SendPacket(const char* data,
- size_t len,
- const rtc::PacketOptions& options,
- int flags) override {
- if (state_ != STATE_CONNECTED) {
- return -1;
- }
-
- if (flags != PF_SRTP_BYPASS && flags != 0) {
- return -1;
- }
-
- PacketMessageData* packet = new PacketMessageData(data, len);
- if (async_) {
- rtc::Thread::Current()->Post(this, 0, packet);
- } else {
- rtc::Thread::Current()->Send(this, 0, packet);
- }
- return static_cast<int>(len);
- }
- int SetOption(rtc::Socket::Option opt, int value) override { return true; }
- bool GetOption(rtc::Socket::Option opt, int* value) override { return true; }
- int GetError() override { return 0; }
-
- void AddRemoteCandidate(const Candidate& candidate) override {
- remote_candidates_.push_back(candidate);
- }
- const Candidates& remote_candidates() const { return remote_candidates_; }
-
- void OnMessage(rtc::Message* msg) override {
- PacketMessageData* data = static_cast<PacketMessageData*>(msg->pdata);
- dest_->SignalReadPacket(dest_, data->packet.data<char>(),
- data->packet.size(), rtc::CreatePacketTime(0), 0);
- delete data;
- }
-
- bool SetLocalCertificate(
- const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) {
- local_cert_ = certificate;
- return true;
- }
-
- void SetRemoteSSLCertificate(rtc::FakeSSLCertificate* cert) {
- remote_cert_ = cert;
- }
-
- bool IsDtlsActive() const override { return do_dtls_; }
-
- bool SetSrtpCiphers(const std::vector<std::string>& ciphers) override {
- srtp_ciphers_ = ciphers;
- return true;
- }
-
- bool GetSrtpCipher(std::string* cipher) override {
- if (!chosen_srtp_cipher_.empty()) {
- *cipher = chosen_srtp_cipher_;
- return true;
- }
- return false;
- }
-
- bool GetSslCipher(std::string* cipher) override { return false; }
-
- rtc::scoped_refptr<rtc::RTCCertificate> GetLocalCertificate() const {
- return local_cert_;
- }
-
- bool GetRemoteSSLCertificate(rtc::SSLCertificate** cert) const override {
- if (!remote_cert_)
- return false;
-
- *cert = remote_cert_->GetReference();
- return true;
- }
-
- bool ExportKeyingMaterial(const std::string& label,
- const uint8* context,
- size_t context_len,
- bool use_context,
- uint8* result,
- size_t result_len) override {
- if (!chosen_srtp_cipher_.empty()) {
- memset(result, 0xff, result_len);
- return true;
- }
-
- return false;
- }
-
- void NegotiateSrtpCiphers() {
- for (std::vector<std::string>::const_iterator it1 = srtp_ciphers_.begin();
- it1 != srtp_ciphers_.end(); ++it1) {
- for (std::vector<std::string>::const_iterator it2 =
- dest_->srtp_ciphers_.begin();
- it2 != dest_->srtp_ciphers_.end(); ++it2) {
- if (*it1 == *it2) {
- chosen_srtp_cipher_ = *it1;
- dest_->chosen_srtp_cipher_ = *it2;
- return;
- }
- }
- }
- }
-
- bool GetStats(ConnectionInfos* infos) override {
- ConnectionInfo info;
- infos->clear();
- infos->push_back(info);
- return true;
- }
-
- void set_ssl_max_protocol_version(rtc::SSLProtocolVersion version) {
- ssl_max_version_ = version;
- }
- rtc::SSLProtocolVersion ssl_max_protocol_version() const {
- return ssl_max_version_;
- }
-
- private:
- enum State { STATE_INIT, STATE_CONNECTING, STATE_CONNECTED };
- Transport* transport_;
- FakeTransportChannel* dest_ = nullptr;
- State state_ = STATE_INIT;
- bool async_ = false;
- Candidates remote_candidates_;
- rtc::scoped_refptr<rtc::RTCCertificate> local_cert_;
- rtc::FakeSSLCertificate* remote_cert_ = nullptr;
- bool do_dtls_ = false;
- std::vector<std::string> srtp_ciphers_;
- std::string chosen_srtp_cipher_;
- int receiving_timeout_ = -1;
- IceRole role_ = ICEROLE_UNKNOWN;
- uint64 tiebreaker_ = 0;
- std::string ice_ufrag_;
- std::string ice_pwd_;
- std::string remote_ice_ufrag_;
- std::string remote_ice_pwd_;
- IceMode remote_ice_mode_ = ICEMODE_FULL;
- rtc::SSLProtocolVersion ssl_max_version_ = rtc::SSL_PROTOCOL_DTLS_10;
- rtc::SSLFingerprint dtls_fingerprint_;
- rtc::SSLRole ssl_role_ = rtc::SSL_CLIENT;
- size_t connection_count_ = 0;
- IceGatheringState gathering_state_ = kIceGatheringNew;
- bool had_connection_ = false;
-};
-
-// Fake transport class, which can be passed to anything that needs a Transport.
-// Can be informed of another FakeTransport via SetDestination (low-tech way
-// of doing candidates)
-class FakeTransport : public Transport {
- public:
- typedef std::map<int, FakeTransportChannel*> ChannelMap;
-
- explicit FakeTransport(const std::string& name) : Transport(name, nullptr) {}
-
- // Note that we only have a constructor with the allocator parameter so it can
- // be wrapped by a DtlsTransport.
- FakeTransport(const std::string& name, PortAllocator* allocator)
- : Transport(name, nullptr) {}
-
- ~FakeTransport() { DestroyAllChannels(); }
-
- const ChannelMap& channels() const { return channels_; }
-
- // If async, will send packets by "Post"-ing to message queue instead of
- // synchronously "Send"-ing.
- void SetAsync(bool async) { async_ = async; }
- void SetDestination(FakeTransport* dest) {
- dest_ = dest;
- for (const auto& kv : channels_) {
- kv.second->SetLocalCertificate(certificate_);
- SetChannelDestination(kv.first, kv.second);
- }
- }
-
- void SetWritable(bool writable) {
- for (const auto& kv : channels_) {
- kv.second->SetWritable(writable);
- }
- }
-
- void SetLocalCertificate(
- const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) override {
- certificate_ = certificate;
- }
- bool GetLocalCertificate(
- rtc::scoped_refptr<rtc::RTCCertificate>* certificate) override {
- if (!certificate_)
- return false;
-
- *certificate = certificate_;
- return true;
- }
-
- bool GetSslRole(rtc::SSLRole* role) const override {
- if (channels_.empty()) {
- return false;
- }
- return channels_.begin()->second->GetSslRole(role);
- }
-
- bool SetSslMaxProtocolVersion(rtc::SSLProtocolVersion version) override {
- ssl_max_version_ = version;
- for (const auto& kv : channels_) {
- kv.second->set_ssl_max_protocol_version(ssl_max_version_);
- }
- return true;
- }
- rtc::SSLProtocolVersion ssl_max_protocol_version() const {
- return ssl_max_version_;
- }
-
- using Transport::local_description;
- using Transport::remote_description;
-
- protected:
- TransportChannelImpl* CreateTransportChannel(int component) override {
- if (channels_.find(component) != channels_.end()) {
- return nullptr;
- }
- FakeTransportChannel* channel =
- new FakeTransportChannel(this, name(), component);
- channel->set_ssl_max_protocol_version(ssl_max_version_);
- channel->SetAsync(async_);
- SetChannelDestination(component, channel);
- channels_[component] = channel;
- return channel;
- }
-
- void DestroyTransportChannel(TransportChannelImpl* channel) override {
- channels_.erase(channel->component());
- delete channel;
- }
-
- private:
- FakeTransportChannel* GetFakeChannel(int component) {
- auto it = channels_.find(component);
- return (it != channels_.end()) ? it->second : nullptr;
- }
-
- void SetChannelDestination(int component, FakeTransportChannel* channel) {
- FakeTransportChannel* dest_channel = nullptr;
- if (dest_) {
- dest_channel = dest_->GetFakeChannel(component);
- if (dest_channel) {
- dest_channel->SetLocalCertificate(dest_->certificate_);
- }
- }
- channel->SetDestination(dest_channel);
- }
-
- // Note, this is distinct from the Channel map owned by Transport.
- // This map just tracks the FakeTransportChannels created by this class.
- // It's mainly needed so that we can access a FakeTransportChannel directly,
- // even if wrapped by a DtlsTransportChannelWrapper.
- ChannelMap channels_;
- FakeTransport* dest_ = nullptr;
- bool async_ = false;
- rtc::scoped_refptr<rtc::RTCCertificate> certificate_;
- rtc::SSLProtocolVersion ssl_max_version_ = rtc::SSL_PROTOCOL_DTLS_10;
-};
-
-// Fake TransportController class, which can be passed into a BaseChannel object
-// for test purposes. Can be connected to other FakeTransportControllers via
-// Connect().
-//
-// This fake is unusual in that for the most part, it's implemented with the
-// real TransportController code, but with fake TransportChannels underneath.
-class FakeTransportController : public TransportController {
- public:
- FakeTransportController()
- : TransportController(rtc::Thread::Current(),
- rtc::Thread::Current(),
- nullptr),
- fail_create_channel_(false) {}
-
- explicit FakeTransportController(IceRole role)
- : TransportController(rtc::Thread::Current(),
- rtc::Thread::Current(),
- nullptr),
- fail_create_channel_(false) {
- SetIceRole(role);
- }
-
- explicit FakeTransportController(rtc::Thread* worker_thread)
- : TransportController(rtc::Thread::Current(), worker_thread, nullptr),
- fail_create_channel_(false) {}
-
- FakeTransportController(rtc::Thread* worker_thread, IceRole role)
- : TransportController(rtc::Thread::Current(), worker_thread, nullptr),
- fail_create_channel_(false) {
- SetIceRole(role);
- }
-
- FakeTransport* GetTransport_w(const std::string& transport_name) {
- return static_cast<FakeTransport*>(
- TransportController::GetTransport_w(transport_name));
- }
-
- void Connect(FakeTransportController* dest) {
- worker_thread()->Invoke<void>(
- rtc::Bind(&FakeTransportController::Connect_w, this, dest));
- }
-
- TransportChannel* CreateTransportChannel_w(const std::string& transport_name,
- int component) override {
- if (fail_create_channel_) {
- return nullptr;
- }
- return TransportController::CreateTransportChannel_w(transport_name,
- component);
- }
-
- void set_fail_channel_creation(bool fail_channel_creation) {
- fail_create_channel_ = fail_channel_creation;
- }
-
- protected:
- Transport* CreateTransport_w(const std::string& transport_name) override {
- return new FakeTransport(transport_name);
- }
-
- void Connect_w(FakeTransportController* dest) {
- // Simulate the exchange of candidates.
- ConnectChannels_w();
- dest->ConnectChannels_w();
- for (auto& kv : transports()) {
- FakeTransport* transport = static_cast<FakeTransport*>(kv.second);
- transport->SetDestination(dest->GetTransport_w(kv.first));
- }
- }
-
- void ConnectChannels_w() {
- for (auto& kv : transports()) {
- FakeTransport* transport = static_cast<FakeTransport*>(kv.second);
- transport->ConnectChannels();
- }
- }
-
- private:
- bool fail_create_channel_;
-};
-
-} // namespace cricket
-
-#endif // WEBRTC_P2P_BASE_FAKETRANSPORTCONTROLLER_H_
diff --git a/webrtc/p2p/base/p2ptransport.cc b/webrtc/p2p/base/p2ptransport.cc
index 6c8d657..b919fde 100644
--- a/webrtc/p2p/base/p2ptransport.cc
+++ b/webrtc/p2p/base/p2ptransport.cc
@@ -20,8 +20,12 @@
namespace cricket {
-P2PTransport::P2PTransport(const std::string& name, PortAllocator* allocator)
- : Transport(name, allocator) {
+P2PTransport::P2PTransport(rtc::Thread* signaling_thread,
+ rtc::Thread* worker_thread,
+ const std::string& content_name,
+ PortAllocator* allocator)
+ : Transport(signaling_thread, worker_thread,
+ content_name, allocator) {
}
P2PTransport::~P2PTransport() {
@@ -29,7 +33,8 @@
}
TransportChannelImpl* P2PTransport::CreateTransportChannel(int component) {
- return new P2PTransportChannel(name(), component, this, port_allocator());
+ return new P2PTransportChannel(content_name(), component, this,
+ port_allocator());
}
void P2PTransport::DestroyTransportChannel(TransportChannelImpl* channel) {
diff --git a/webrtc/p2p/base/p2ptransport.h b/webrtc/p2p/base/p2ptransport.h
index 0f965b4..2e27bd8 100644
--- a/webrtc/p2p/base/p2ptransport.h
+++ b/webrtc/p2p/base/p2ptransport.h
@@ -16,10 +16,12 @@
namespace cricket {
-// Everything in this class should be called on the worker thread.
class P2PTransport : public Transport {
public:
- P2PTransport(const std::string& name, PortAllocator* allocator);
+ P2PTransport(rtc::Thread* signaling_thread,
+ rtc::Thread* worker_thread,
+ const std::string& content_name,
+ PortAllocator* allocator);
virtual ~P2PTransport();
protected:
diff --git a/webrtc/p2p/base/p2ptransportchannel.cc b/webrtc/p2p/base/p2ptransportchannel.cc
index bcd9933..094a8dc 100644
--- a/webrtc/p2p/base/p2ptransportchannel.cc
+++ b/webrtc/p2p/base/p2ptransportchannel.cc
@@ -11,7 +11,6 @@
#include "webrtc/p2p/base/p2ptransportchannel.h"
#include <set>
-#include <algorithm>
#include "webrtc/p2p/base/common.h"
#include "webrtc/p2p/base/relayport.h" // For RELAY_PORT_TYPE.
#include "webrtc/p2p/base/stunport.h" // For STUN_PORT_TYPE.
@@ -170,27 +169,27 @@
namespace cricket {
-P2PTransportChannel::P2PTransportChannel(const std::string& transport_name,
+P2PTransportChannel::P2PTransportChannel(const std::string& content_name,
int component,
P2PTransport* transport,
- PortAllocator* allocator)
- : TransportChannelImpl(transport_name, component),
- transport_(transport),
- allocator_(allocator),
- worker_thread_(rtc::Thread::Current()),
- incoming_only_(false),
- error_(0),
- best_connection_(NULL),
- pending_best_connection_(NULL),
- sort_dirty_(false),
- was_writable_(false),
- remote_ice_mode_(ICEMODE_FULL),
- ice_role_(ICEROLE_UNKNOWN),
- tiebreaker_(0),
- remote_candidate_generation_(0),
- gathering_state_(kIceGatheringNew),
- check_receiving_delay_(MIN_CHECK_RECEIVING_DELAY * 5),
- receiving_timeout_(MIN_CHECK_RECEIVING_DELAY * 50) {
+ PortAllocator *allocator) :
+ TransportChannelImpl(content_name, component),
+ transport_(transport),
+ allocator_(allocator),
+ worker_thread_(rtc::Thread::Current()),
+ incoming_only_(false),
+ waiting_for_signaling_(false),
+ error_(0),
+ best_connection_(NULL),
+ pending_best_connection_(NULL),
+ sort_dirty_(false),
+ was_writable_(false),
+ remote_ice_mode_(ICEMODE_FULL),
+ ice_role_(ICEROLE_UNKNOWN),
+ tiebreaker_(0),
+ remote_candidate_generation_(0),
+ check_receiving_delay_(MIN_CHECK_RECEIVING_DELAY * 5),
+ receiving_timeout_(MIN_CHECK_RECEIVING_DELAY * 50) {
}
P2PTransportChannel::~P2PTransportChannel() {
@@ -231,7 +230,6 @@
connection->SignalDestroyed.connect(
this, &P2PTransportChannel::OnConnectionDestroyed);
connection->SignalNominated.connect(this, &P2PTransportChannel::OnNominated);
- had_connection_ = true;
}
void P2PTransportChannel::SetIceRole(IceRole ice_role) {
@@ -266,9 +264,8 @@
TransportChannelState P2PTransportChannel::GetState() const {
std::set<rtc::Network*> networks;
- if (connections_.empty()) {
- return had_connection_ ? TransportChannelState::STATE_FAILED
- : TransportChannelState::STATE_INIT;
+ if (connections_.size() == 0) {
+ return TransportChannelState::STATE_FAILED;
}
for (uint32 i = 0; i < connections_.size(); ++i) {
@@ -303,7 +300,7 @@
if (ice_restart) {
// Restart candidate gathering.
- StartGatheringCandidates();
+ Allocate();
}
}
@@ -358,7 +355,7 @@
}
// Kick off an allocator session
- StartGatheringCandidates();
+ Allocate();
// Start pinging as the ports come in.
thread()->Post(this, MSG_PING);
@@ -411,21 +408,17 @@
// A new candidate is available, let listeners know
void P2PTransportChannel::OnCandidatesReady(
- PortAllocatorSession* session,
- const std::vector<Candidate>& candidates) {
+ PortAllocatorSession *session, const std::vector<Candidate>& candidates) {
ASSERT(worker_thread_ == rtc::Thread::Current());
for (size_t i = 0; i < candidates.size(); ++i) {
- SignalCandidateGathered(this, candidates[i]);
+ SignalCandidateReady(this, candidates[i]);
}
}
void P2PTransportChannel::OnCandidatesAllocationDone(
PortAllocatorSession* session) {
ASSERT(worker_thread_ == rtc::Thread::Current());
- gathering_state_ = kIceGatheringComplete;
- LOG(LS_INFO) << "P2PTransportChannel: " << transport_name() << ", component "
- << component() << " gathering complete";
- SignalGatheringState(this);
+ SignalCandidatesAllocationDone(this);
}
// Handle stun packets
@@ -496,7 +489,8 @@
LOG(LS_WARNING) << "P2PTransportChannel::OnUnknownAddress - "
<< "No STUN_ATTR_PRIORITY found in the "
<< "stun request message";
- port->SendBindingErrorResponse(stun_msg, address, STUN_ERROR_BAD_REQUEST,
+ port->SendBindingErrorResponse(stun_msg, address,
+ STUN_ERROR_BAD_REQUEST,
STUN_ERROR_REASON_BAD_REQUEST);
return;
}
@@ -546,7 +540,8 @@
remote_candidate, cricket::PortInterface::ORIGIN_THIS_PORT);
if (!connection) {
ASSERT(false);
- port->SendBindingErrorResponse(stun_msg, address, STUN_ERROR_SERVER_ERROR,
+ port->SendBindingErrorResponse(stun_msg, address,
+ STUN_ERROR_SERVER_ERROR,
STUN_ERROR_REASON_SERVER_ERROR);
return;
}
@@ -575,6 +570,16 @@
// from Transport.
}
+// When the signalling channel is ready, we can really kick off the allocator
+void P2PTransportChannel::OnSignalingReady() {
+ ASSERT(worker_thread_ == rtc::Thread::Current());
+ if (waiting_for_signaling_) {
+ waiting_for_signaling_ = false;
+ AddAllocatorSession(allocator_->CreateSession(
+ SessionId(), content_name(), component(), ice_ufrag_, ice_pwd_));
+ }
+}
+
void P2PTransportChannel::OnNominated(Connection* conn) {
ASSERT(worker_thread_ == rtc::Thread::Current());
ASSERT(ice_role_ == ICEROLE_CONTROLLED);
@@ -596,7 +601,7 @@
}
}
-void P2PTransportChannel::AddRemoteCandidate(const Candidate& candidate) {
+void P2PTransportChannel::OnCandidate(const Candidate& candidate) {
ASSERT(worker_thread_ == rtc::Thread::Current());
uint32 generation = candidate.generation();
@@ -845,7 +850,7 @@
std::vector<Connection *>::const_iterator it;
for (it = connections_.begin(); it != connections_.end(); ++it) {
- Connection* connection = *it;
+ Connection *connection = *it;
ConnectionInfo info;
info.best_connection = (best_connection_ == connection);
info.readable =
@@ -880,14 +885,12 @@
return static_cast<rtc::DiffServCodePoint> (it->second);
}
-void P2PTransportChannel::StartGatheringCandidates() {
- // Time for a new allocator
- if (gathering_state_ != kIceGatheringGathering) {
- gathering_state_ = kIceGatheringGathering;
- SignalGatheringState(this);
- }
- AddAllocatorSession(allocator_->CreateSession(
- SessionId(), transport_name(), component(), ice_ufrag_, ice_pwd_));
+// Begin allocate (or immediately re-allocate, if MSG_ALLOCATE pending)
+void P2PTransportChannel::Allocate() {
+ // Time for a new allocator, lets make sure we have a signalling channel
+ // to communicate candidates through first.
+ waiting_for_signaling_ = true;
+ SignalRequestSignaling(this);
}
// Monitor connection states.
@@ -1249,7 +1252,8 @@
void P2PTransportChannel::PingConnection(Connection* conn) {
bool use_candidate = false;
if (remote_ice_mode_ == ICEMODE_FULL && ice_role_ == ICEROLE_CONTROLLING) {
- use_candidate = (conn == best_connection_) || (best_connection_ == NULL) ||
+ use_candidate = (conn == best_connection_) ||
+ (best_connection_ == NULL) ||
(!best_connection_->writable()) ||
(conn->priority() > best_connection_->priority());
} else if (remote_ice_mode_ == ICEMODE_LITE && conn == best_connection_) {
@@ -1331,10 +1335,9 @@
}
// We data is available, let listeners know
-void P2PTransportChannel::OnReadPacket(Connection* connection,
- const char* data,
- size_t len,
- const rtc::PacketTime& packet_time) {
+void P2PTransportChannel::OnReadPacket(
+ Connection *connection, const char *data, size_t len,
+ const rtc::PacketTime& packet_time) {
ASSERT(worker_thread_ == rtc::Thread::Current());
// Do not deliver, if packet doesn't belong to the correct transport channel.
diff --git a/webrtc/p2p/base/p2ptransportchannel.h b/webrtc/p2p/base/p2ptransportchannel.h
index f07a81c..a00c17e 100644
--- a/webrtc/p2p/base/p2ptransportchannel.h
+++ b/webrtc/p2p/base/p2ptransportchannel.h
@@ -51,11 +51,11 @@
class P2PTransportChannel : public TransportChannelImpl,
public rtc::MessageHandler {
public:
- P2PTransportChannel(const std::string& transport_name,
+ P2PTransportChannel(const std::string& content_name,
int component,
P2PTransport* transport,
- PortAllocator* allocator);
- virtual ~P2PTransportChannel();
+ PortAllocator *allocator);
+ ~P2PTransportChannel() override;
// From TransportChannelImpl:
Transport* GetTransport() override { return transport_; }
@@ -69,19 +69,15 @@
const std::string& ice_pwd) override;
void SetRemoteIceMode(IceMode mode) override;
void Connect() override;
- IceGatheringState gathering_state() const override {
- return gathering_state_;
- }
- void AddRemoteCandidate(const Candidate& candidate) override;
+ void OnSignalingReady() override;
+ void OnCandidate(const Candidate& candidate) override;
// Sets the receiving timeout in milliseconds.
// This also sets the check_receiving_delay proportionally.
void SetReceivingTimeout(int receiving_timeout_ms) override;
// From TransportChannel:
- int SendPacket(const char* data,
- size_t len,
- const rtc::PacketOptions& options,
- int flags) override;
+ int SendPacket(const char *data, size_t len,
+ const rtc::PacketOptions& options, int flags) override;
int SetOption(rtc::Socket::Option opt, int value) override;
bool GetOption(rtc::Socket::Option opt, int* value) override;
int GetError() override { return error_; }
@@ -100,9 +96,13 @@
bool IsDtlsActive() const override { return false; }
// Default implementation.
- bool GetSslRole(rtc::SSLRole* role) const override { return false; }
+ bool GetSslRole(rtc::SSLRole* role) const override {
+ return false;
+ }
- bool SetSslRole(rtc::SSLRole role) override { return false; }
+ bool SetSslRole(rtc::SSLRole role) override {
+ return false;
+ }
// Set up the ciphers to use for DTLS-SRTP.
bool SetSrtpCiphers(const std::vector<std::string>& ciphers) override {
@@ -110,10 +110,14 @@
}
// Find out which DTLS-SRTP cipher was negotiated.
- bool GetSrtpCipher(std::string* cipher) override { return false; }
+ bool GetSrtpCipher(std::string* cipher) override {
+ return false;
+ }
// Find out which DTLS cipher was negotiated.
- bool GetSslCipher(std::string* cipher) override { return false; }
+ bool GetSslCipher(std::string* cipher) override {
+ return false;
+ }
// Returns null because the channel is not encrypted by default.
rtc::scoped_refptr<rtc::RTCCertificate> GetLocalCertificate() const override {
@@ -161,7 +165,7 @@
return allocator_sessions_.back();
}
- void StartGatheringCandidates();
+ void Allocate();
void UpdateConnectionStates();
void RequestSort();
void SortConnections();
@@ -208,7 +212,7 @@
void OnNominated(Connection* conn);
- void OnMessage(rtc::Message* pmsg) override;
+ void OnMessage(rtc::Message *pmsg) override;
void OnSort();
void OnPing();
@@ -218,9 +222,10 @@
Connection* best_nominated_connection() const;
P2PTransport* transport_;
- PortAllocator* allocator_;
- rtc::Thread* worker_thread_;
+ PortAllocator *allocator_;
+ rtc::Thread *worker_thread_;
bool incoming_only_;
+ bool waiting_for_signaling_;
int error_;
std::vector<PortAllocatorSession*> allocator_sessions_;
std::vector<PortInterface *> ports_;
@@ -232,7 +237,6 @@
std::vector<RemoteCandidate> remote_candidates_;
bool sort_dirty_; // indicates whether another sort is needed right now
bool was_writable_;
- bool had_connection_ = false; // if connections_ has ever been nonempty
typedef std::map<rtc::Socket::Option, int> OptionMap;
OptionMap options_;
std::string ice_ufrag_;
@@ -243,7 +247,6 @@
IceRole ice_role_;
uint64 tiebreaker_;
uint32 remote_candidate_generation_;
- IceGatheringState gathering_state_;
int check_receiving_delay_;
int receiving_timeout_;
diff --git a/webrtc/p2p/base/p2ptransportchannel_unittest.cc b/webrtc/p2p/base/p2ptransportchannel_unittest.cc
index 25a5d9a..3bb3be5 100644
--- a/webrtc/p2p/base/p2ptransportchannel_unittest.cc
+++ b/webrtc/p2p/base/p2ptransportchannel_unittest.cc
@@ -297,8 +297,10 @@
const std::string& remote_ice_pwd) {
cricket::P2PTransportChannel* channel = new cricket::P2PTransportChannel(
"test content name", component, NULL, GetAllocator(endpoint));
- channel->SignalCandidateGathered.connect(
- this, &P2PTransportChannelTestBase::OnCandidate);
+ channel->SignalRequestSignaling.connect(
+ this, &P2PTransportChannelTestBase::OnChannelRequestSignaling);
+ channel->SignalCandidateReady.connect(this,
+ &P2PTransportChannelTestBase::OnCandidate);
channel->SignalReadPacket.connect(
this, &P2PTransportChannelTestBase::OnReadPacket);
channel->SignalRoleConflict.connect(
@@ -387,9 +389,10 @@
}
bool IsLocalToPrflxOrTheReverse(const Result& expected) {
- return (
- (expected.local_type == "local" && expected.remote_type == "prflx") ||
- (expected.local_type == "prflx" && expected.remote_type == "local"));
+ return ((expected.local_type == "local" &&
+ expected.remote_type == "prflx") ||
+ (expected.local_type == "prflx" &&
+ expected.remote_type == "local"));
}
// Return true if the approprite parts of the expected Result, based
@@ -509,8 +512,8 @@
ep2_ch1()->best_connection()) {
int32 converge_start = rtc::Time(), converge_time;
int converge_wait = 2000;
- EXPECT_TRUE_WAIT_MARGIN(CheckCandidate1(expected), converge_wait,
- converge_wait);
+ EXPECT_TRUE_WAIT_MARGIN(CheckCandidate1(expected),
+ converge_wait, converge_wait);
// Also do EXPECT_EQ on each part so that failures are more verbose.
ExpectCandidate1(expected);
@@ -623,6 +626,9 @@
TestSendRecv(1);
}
+ void OnChannelRequestSignaling(cricket::TransportChannelImpl* channel) {
+ channel->OnSignalingReady();
+ }
// We pass the candidates directly to the other side.
void OnCandidate(cricket::TransportChannelImpl* ch,
const cricket::Candidate& c) {
@@ -663,7 +669,7 @@
}
LOG(LS_INFO) << "Candidate(" << data->channel->component() << "->"
<< rch->component() << "): " << c.ToString();
- rch->AddRemoteCandidate(c);
+ rch->OnCandidate(c);
break;
}
}
@@ -798,10 +804,8 @@
static const Result* kMatrixSharedUfrag[NUM_CONFIGS][NUM_CONFIGS];
static const Result* kMatrixSharedSocketAsGice[NUM_CONFIGS][NUM_CONFIGS];
static const Result* kMatrixSharedSocketAsIce[NUM_CONFIGS][NUM_CONFIGS];
- void ConfigureEndpoints(Config config1,
- Config config2,
- int allocator_flags1,
- int allocator_flags2) {
+ void ConfigureEndpoints(Config config1, Config config2,
+ int allocator_flags1, int allocator_flags2) {
ServerAddresses stun_servers;
stun_servers.insert(kStunAddr);
GetEndpoint(0)->allocator_.reset(
@@ -817,8 +821,8 @@
cricket::RelayServerConfig relay_server(cricket::RELAY_TURN);
relay_server.credentials = kRelayCredentials;
- relay_server.ports.push_back(
- cricket::ProtocolAddress(kTurnUdpIntAddr, cricket::PROTO_UDP, false));
+ relay_server.ports.push_back(cricket::ProtocolAddress(
+ kTurnUdpIntAddr, cricket::PROTO_UDP, false));
GetEndpoint(0)->allocator_->AddRelay(relay_server);
GetEndpoint(1)->allocator_->AddRelay(relay_server);
@@ -1022,14 +1026,15 @@
// The actual tests that exercise all the various configurations.
// Test names are of the form P2PTransportChannelTest_TestOPENToNAT_FULL_CONE
-#define P2P_TEST_DECLARATION(x, y, z) \
- TEST_F(P2PTransportChannelTest, z##Test##x##To##y) { \
- ConfigureEndpoints(x, y, PORTALLOCATOR_ENABLE_SHARED_SOCKET, \
- PORTALLOCATOR_ENABLE_SHARED_SOCKET); \
- if (kMatrixSharedSocketAsIce[x][y] != NULL) \
- Test(*kMatrixSharedSocketAsIce[x][y]); \
- else \
- LOG(LS_WARNING) << "Not yet implemented"; \
+#define P2P_TEST_DECLARATION(x, y, z) \
+ TEST_F(P2PTransportChannelTest, z##Test##x##To##y) { \
+ ConfigureEndpoints(x, y, \
+ PORTALLOCATOR_ENABLE_SHARED_SOCKET, \
+ PORTALLOCATOR_ENABLE_SHARED_SOCKET); \
+ if (kMatrixSharedSocketAsIce[x][y] != NULL) \
+ Test(*kMatrixSharedSocketAsIce[x][y]); \
+ else \
+ LOG(LS_WARNING) << "Not yet implemented"; \
}
#define P2P_TEST(x, y) \
@@ -1084,7 +1089,8 @@
// Test that we restart candidate allocation when local ufrag&pwd changed.
// Standard Ice protocol is used.
TEST_F(P2PTransportChannelTest, HandleUfragPwdChange) {
- ConfigureEndpoints(OPEN, OPEN, kDefaultPortAllocatorFlags,
+ ConfigureEndpoints(OPEN, OPEN,
+ kDefaultPortAllocatorFlags,
kDefaultPortAllocatorFlags);
CreateChannels(1);
TestHandleIceUfragPasswordChanged();
@@ -1093,7 +1099,8 @@
// Test the operation of GetStats.
TEST_F(P2PTransportChannelTest, GetStats) {
- ConfigureEndpoints(OPEN, OPEN, kDefaultPortAllocatorFlags,
+ ConfigureEndpoints(OPEN, OPEN,
+ kDefaultPortAllocatorFlags,
kDefaultPortAllocatorFlags);
CreateChannels(1);
EXPECT_TRUE_WAIT_MARGIN(ep1_ch1()->readable() && ep1_ch1()->writable() &&
@@ -1119,7 +1126,8 @@
// Test that we properly create a connection on a STUN ping from unknown address
// when the signaling is slow.
TEST_F(P2PTransportChannelTest, PeerReflexiveCandidateBeforeSignaling) {
- ConfigureEndpoints(OPEN, OPEN, kDefaultPortAllocatorFlags,
+ ConfigureEndpoints(OPEN, OPEN,
+ kDefaultPortAllocatorFlags,
kDefaultPortAllocatorFlags);
// Emulate no remote credentials coming in.
set_clear_remote_candidates_ufrag_pwd(false);
@@ -1163,7 +1171,8 @@
// Test that we properly create a connection on a STUN ping from unknown address
// when the signaling is slow and the end points are behind NAT.
TEST_F(P2PTransportChannelTest, PeerReflexiveCandidateBeforeSignalingWithNAT) {
- ConfigureEndpoints(OPEN, NAT_SYMMETRIC, kDefaultPortAllocatorFlags,
+ ConfigureEndpoints(OPEN, NAT_SYMMETRIC,
+ kDefaultPortAllocatorFlags,
kDefaultPortAllocatorFlags);
// Emulate no remote credentials coming in.
set_clear_remote_candidates_ufrag_pwd(false);
@@ -1205,7 +1214,8 @@
// Test that if remote candidates don't have ufrag and pwd, we still work.
TEST_F(P2PTransportChannelTest, RemoteCandidatesWithoutUfragPwd) {
set_clear_remote_candidates_ufrag_pwd(true);
- ConfigureEndpoints(OPEN, OPEN, kDefaultPortAllocatorFlags,
+ ConfigureEndpoints(OPEN, OPEN,
+ kDefaultPortAllocatorFlags,
kDefaultPortAllocatorFlags);
CreateChannels(1);
const cricket::Connection* best_connection = NULL;
@@ -1220,7 +1230,8 @@
// Test that a host behind NAT cannot be reached when incoming_only
// is set to true.
TEST_F(P2PTransportChannelTest, IncomingOnlyBlocked) {
- ConfigureEndpoints(NAT_FULL_CONE, OPEN, kDefaultPortAllocatorFlags,
+ ConfigureEndpoints(NAT_FULL_CONE, OPEN,
+ kDefaultPortAllocatorFlags,
kDefaultPortAllocatorFlags);
SetAllocatorFlags(0, kOnlyLocalPorts);
@@ -1241,7 +1252,8 @@
// Test that a peer behind NAT can connect to a peer that has
// incoming_only flag set.
TEST_F(P2PTransportChannelTest, IncomingOnlyOpen) {
- ConfigureEndpoints(OPEN, NAT_FULL_CONE, kDefaultPortAllocatorFlags,
+ ConfigureEndpoints(OPEN, NAT_FULL_CONE,
+ kDefaultPortAllocatorFlags,
kDefaultPortAllocatorFlags);
SetAllocatorFlags(0, kOnlyLocalPorts);
@@ -1402,10 +1414,11 @@
// Testing forceful TURN connections.
TEST_F(P2PTransportChannelTest, TestForceTurn) {
- ConfigureEndpoints(
- NAT_PORT_RESTRICTED, NAT_SYMMETRIC,
- kDefaultPortAllocatorFlags | cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET,
- kDefaultPortAllocatorFlags | cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET);
+ ConfigureEndpoints(NAT_PORT_RESTRICTED, NAT_SYMMETRIC,
+ kDefaultPortAllocatorFlags |
+ cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET,
+ kDefaultPortAllocatorFlags |
+ cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET);
set_force_relay(true);
SetAllocationStepDelay(0, kMinimumStepDelay);
@@ -1413,8 +1426,10 @@
CreateChannels(1);
- EXPECT_TRUE_WAIT(ep1_ch1()->readable() && ep1_ch1()->writable() &&
- ep2_ch1()->readable() && ep2_ch1()->writable(),
+ EXPECT_TRUE_WAIT(ep1_ch1()->readable() &&
+ ep1_ch1()->writable() &&
+ ep2_ch1()->readable() &&
+ ep2_ch1()->writable(),
2000);
EXPECT_TRUE(ep1_ch1()->best_connection() &&
@@ -1460,7 +1475,8 @@
TEST_F(P2PTransportChannelSameNatTest, TestConesBehindSameCone) {
ConfigureEndpoints(NAT_FULL_CONE, NAT_FULL_CONE, NAT_FULL_CONE);
Test(P2PTransportChannelTestBase::Result(
- "prflx", "udp", "stun", "udp", "stun", "udp", "prflx", "udp", 1000));
+ "prflx", "udp", "stun", "udp",
+ "stun", "udp", "prflx", "udp", 1000));
}
// Test what happens when we have multiple available pathways.
@@ -1577,11 +1593,17 @@
protected:
void PrepareChannel(cricket::P2PTransportChannel* ch) {
+ ch->SignalRequestSignaling.connect(
+ this, &P2PTransportChannelPingTest::OnChannelRequestSignaling);
ch->SetIceRole(cricket::ICEROLE_CONTROLLING);
ch->SetIceCredentials(kIceUfrag[0], kIcePwd[0]);
ch->SetRemoteIceCredentials(kIceUfrag[1], kIcePwd[1]);
}
+ void OnChannelRequestSignaling(cricket::TransportChannelImpl* channel) {
+ channel->OnSignalingReady();
+ }
+
cricket::Candidate CreateCandidate(const std::string& ip,
int port,
int priority) {
@@ -1628,8 +1650,8 @@
cricket::P2PTransportChannel ch("trigger checks", 1, nullptr, &pa);
PrepareChannel(&ch);
ch.Connect();
- ch.AddRemoteCandidate(CreateCandidate("1.1.1.1", 1, 1));
- ch.AddRemoteCandidate(CreateCandidate("2.2.2.2", 2, 2));
+ ch.OnCandidate(CreateCandidate("1.1.1.1", 1, 1));
+ ch.OnCandidate(CreateCandidate("2.2.2.2", 2, 2));
cricket::Connection* conn1 = WaitForConnectionTo(&ch, "1.1.1.1", 1);
cricket::Connection* conn2 = WaitForConnectionTo(&ch, "2.2.2.2", 2);
@@ -1652,8 +1674,8 @@
cricket::P2PTransportChannel ch("trigger checks", 1, nullptr, &pa);
PrepareChannel(&ch);
ch.Connect();
- ch.AddRemoteCandidate(CreateCandidate("1.1.1.1", 1, 1));
- ch.AddRemoteCandidate(CreateCandidate("2.2.2.2", 2, 2));
+ ch.OnCandidate(CreateCandidate("1.1.1.1", 1, 1));
+ ch.OnCandidate(CreateCandidate("2.2.2.2", 2, 2));
cricket::Connection* conn1 = WaitForConnectionTo(&ch, "1.1.1.1", 1);
cricket::Connection* conn2 = WaitForConnectionTo(&ch, "2.2.2.2", 2);
@@ -1678,14 +1700,14 @@
ch.Connect();
// Create conn1 and keep track of original candidate priority.
- ch.AddRemoteCandidate(CreateCandidate("1.1.1.1", 1, 1));
+ ch.OnCandidate(CreateCandidate("1.1.1.1", 1, 1));
cricket::Connection* conn1 = WaitForConnectionTo(&ch, "1.1.1.1", 1);
ASSERT_TRUE(conn1 != nullptr);
uint32 remote_priority = conn1->remote_candidate().priority();
// Create a higher priority candidate and make the connection
// readable/writable. This will prune conn1.
- ch.AddRemoteCandidate(CreateCandidate("2.2.2.2", 2, 2));
+ ch.OnCandidate(CreateCandidate("2.2.2.2", 2, 2));
cricket::Connection* conn2 = WaitForConnectionTo(&ch, "2.2.2.2", 2);
ASSERT_TRUE(conn2 != nullptr);
conn2->ReceivedPing();
@@ -1732,7 +1754,7 @@
EXPECT_EQ(500, ch.receiving_timeout());
EXPECT_EQ(50, ch.check_receiving_delay());
ch.Connect();
- ch.AddRemoteCandidate(CreateCandidate("1.1.1.1", 1, 1));
+ ch.OnCandidate(CreateCandidate("1.1.1.1", 1, 1));
cricket::Connection* conn1 = WaitForConnectionTo(&ch, "1.1.1.1", 1);
ASSERT_TRUE(conn1 != nullptr);
@@ -1753,14 +1775,14 @@
PrepareChannel(&ch);
ch.SetIceRole(cricket::ICEROLE_CONTROLLED);
ch.Connect();
- ch.AddRemoteCandidate(CreateCandidate("1.1.1.1", 1, 1));
+ ch.OnCandidate(CreateCandidate("1.1.1.1", 1, 1));
cricket::Connection* conn1 = WaitForConnectionTo(&ch, "1.1.1.1", 1);
ASSERT_TRUE(conn1 != nullptr);
EXPECT_EQ(conn1, ch.best_connection());
// When a higher priority candidate comes in, the new connection is chosen
// as the best connection.
- ch.AddRemoteCandidate(CreateCandidate("2.2.2.2", 2, 10));
+ ch.OnCandidate(CreateCandidate("2.2.2.2", 2, 10));
cricket::Connection* conn2 = WaitForConnectionTo(&ch, "2.2.2.2", 2);
ASSERT_TRUE(conn1 != nullptr);
EXPECT_EQ(conn2, ch.best_connection());
@@ -1768,7 +1790,7 @@
// If a stun request with use-candidate attribute arrives, the receiving
// connection will be set as the best connection, even though
// its priority is lower.
- ch.AddRemoteCandidate(CreateCandidate("3.3.3.3", 3, 1));
+ ch.OnCandidate(CreateCandidate("3.3.3.3", 3, 1));
cricket::Connection* conn3 = WaitForConnectionTo(&ch, "3.3.3.3", 3);
ASSERT_TRUE(conn3 != nullptr);
// Because it has a lower priority, the best connection is still conn2.
@@ -1783,7 +1805,7 @@
// Even if another higher priority candidate arrives,
// it will not be set as the best connection because the best connection
// is nominated by the controlling side.
- ch.AddRemoteCandidate(CreateCandidate("4.4.4.4", 4, 100));
+ ch.OnCandidate(CreateCandidate("4.4.4.4", 4, 100));
cricket::Connection* conn4 = WaitForConnectionTo(&ch, "4.4.4.4", 4);
ASSERT_TRUE(conn4 != nullptr);
EXPECT_EQ(conn3, ch.best_connection());
@@ -1826,7 +1848,7 @@
EXPECT_EQ(conn1, ch.best_connection());
// Another connection is nominated via use_candidate.
- ch.AddRemoteCandidate(CreateCandidate("2.2.2.2", 2, 1));
+ ch.OnCandidate(CreateCandidate("2.2.2.2", 2, 1));
cricket::Connection* conn2 = WaitForConnectionTo(&ch, "2.2.2.2", 2);
ASSERT_TRUE(conn2 != nullptr);
// Because it has a lower priority, the best connection is still conn1.
@@ -1872,7 +1894,7 @@
PrepareChannel(&ch);
ch.SetIceRole(cricket::ICEROLE_CONTROLLED);
ch.Connect();
- ch.AddRemoteCandidate(CreateCandidate("1.1.1.1", 1, 10));
+ ch.OnCandidate(CreateCandidate("1.1.1.1", 1, 10));
cricket::Connection* conn1 = WaitForConnectionTo(&ch, "1.1.1.1", 1);
ASSERT_TRUE(conn1 != nullptr);
EXPECT_EQ(conn1, ch.best_connection());
@@ -1880,7 +1902,7 @@
// If a data packet is received on conn2, the best connection should
// switch to conn2 because the controlled side must mirror the media path
// chosen by the controlling side.
- ch.AddRemoteCandidate(CreateCandidate("2.2.2.2", 2, 1));
+ ch.OnCandidate(CreateCandidate("2.2.2.2", 2, 1));
cricket::Connection* conn2 = WaitForConnectionTo(&ch, "2.2.2.2", 2);
ASSERT_TRUE(conn2 != nullptr);
conn2->ReceivedPing(); // Become readable.
diff --git a/webrtc/p2p/base/session.cc b/webrtc/p2p/base/session.cc
index b80a233..23680b9 100644
--- a/webrtc/p2p/base/session.cc
+++ b/webrtc/p2p/base/session.cc
@@ -10,6 +10,11 @@
#include "webrtc/p2p/base/session.h"
+#include "webrtc/p2p/base/dtlstransport.h"
+#include "webrtc/p2p/base/p2ptransport.h"
+#include "webrtc/p2p/base/transport.h"
+#include "webrtc/p2p/base/transportchannelproxy.h"
+#include "webrtc/p2p/base/transportinfo.h"
#include "webrtc/base/bind.h"
#include "webrtc/base/common.h"
#include "webrtc/base/helpers.h"
@@ -17,15 +22,266 @@
#include "webrtc/base/scoped_ptr.h"
#include "webrtc/base/stringencode.h"
#include "webrtc/base/sslstreamadapter.h"
-#include "webrtc/p2p/base/transport.h"
-#include "webrtc/p2p/base/transportinfo.h"
-#include "webrtc/p2p/base/transportcontroller.h"
+
#include "webrtc/p2p/base/constants.h"
namespace cricket {
using rtc::Bind;
+TransportProxy::~TransportProxy() {
+ for (ChannelMap::iterator iter = channels_.begin();
+ iter != channels_.end(); ++iter) {
+ iter->second->SignalDestroyed(iter->second);
+ delete iter->second;
+ }
+}
+
+TransportChannel* TransportProxy::GetChannel(int component) {
+ ASSERT(rtc::Thread::Current() == worker_thread_);
+ return GetChannelProxy(component);
+}
+
+TransportChannel* TransportProxy::CreateChannel(int component) {
+ ASSERT(rtc::Thread::Current() == worker_thread_);
+ ASSERT(GetChannel(component) == NULL);
+ ASSERT(!transport_->get()->HasChannel(component));
+
+ // We always create a proxy in case we need to change out the transport later.
+ TransportChannelProxy* channel_proxy =
+ new TransportChannelProxy(content_name(), component);
+ channels_[component] = channel_proxy;
+
+ // If we're already negotiated, create an impl and hook it up to the proxy
+ // channel. If we're connecting, create an impl but don't hook it up yet.
+ if (negotiated_) {
+ CreateChannelImpl_w(component);
+ SetChannelImplFromTransport_w(channel_proxy, component);
+ } else if (connecting_) {
+ CreateChannelImpl_w(component);
+ }
+ return channel_proxy;
+}
+
+bool TransportProxy::HasChannel(int component) {
+ return transport_->get()->HasChannel(component);
+}
+
+void TransportProxy::DestroyChannel(int component) {
+ ASSERT(rtc::Thread::Current() == worker_thread_);
+ TransportChannelProxy* channel_proxy = GetChannelProxy(component);
+ if (channel_proxy) {
+ // If the state of TransportProxy is not NEGOTIATED then
+ // TransportChannelProxy and its impl are not connected. Both must
+ // be connected before deletion.
+ //
+ // However, if we haven't entered the connecting state then there
+ // is no implementation to hook up.
+ if (connecting_ && !negotiated_) {
+ SetChannelImplFromTransport_w(channel_proxy, component);
+ }
+
+ channels_.erase(component);
+ channel_proxy->SignalDestroyed(channel_proxy);
+ delete channel_proxy;
+ }
+}
+
+void TransportProxy::ConnectChannels() {
+ if (!connecting_) {
+ if (!negotiated_) {
+ for (auto& iter : channels_) {
+ CreateChannelImpl(iter.first);
+ }
+ }
+ connecting_ = true;
+ }
+ // TODO(juberti): Right now Transport::ConnectChannels doesn't work if we
+ // don't have any channels yet, so we need to allow this method to be called
+ // multiple times. Once we fix Transport, we can move this call inside the
+ // if (!connecting_) block.
+ transport_->get()->ConnectChannels();
+}
+
+void TransportProxy::CompleteNegotiation() {
+ if (!negotiated_) {
+ // Negotiating assumes connecting_ has happened and
+ // implementations exist. If not we need to create the
+ // implementations.
+ for (auto& iter : channels_) {
+ if (!connecting_) {
+ CreateChannelImpl(iter.first);
+ }
+ SetChannelImplFromTransport(iter.second, iter.first);
+ }
+ negotiated_ = true;
+ }
+}
+
+void TransportProxy::AddSentCandidates(const Candidates& candidates) {
+ for (Candidates::const_iterator cand = candidates.begin();
+ cand != candidates.end(); ++cand) {
+ sent_candidates_.push_back(*cand);
+ }
+}
+
+void TransportProxy::AddUnsentCandidates(const Candidates& candidates) {
+ for (Candidates::const_iterator cand = candidates.begin();
+ cand != candidates.end(); ++cand) {
+ unsent_candidates_.push_back(*cand);
+ }
+}
+
+TransportChannelProxy* TransportProxy::GetChannelProxy(int component) const {
+ ChannelMap::const_iterator iter = channels_.find(component);
+ return (iter != channels_.end()) ? iter->second : NULL;
+}
+
+void TransportProxy::CreateChannelImpl(int component) {
+ worker_thread_->Invoke<void>(Bind(
+ &TransportProxy::CreateChannelImpl_w, this, component));
+}
+
+void TransportProxy::CreateChannelImpl_w(int component) {
+ ASSERT(rtc::Thread::Current() == worker_thread_);
+ transport_->get()->CreateChannel(component);
+}
+
+void TransportProxy::SetChannelImplFromTransport(TransportChannelProxy* proxy,
+ int component) {
+ worker_thread_->Invoke<void>(Bind(
+ &TransportProxy::SetChannelImplFromTransport_w, this, proxy, component));
+}
+
+void TransportProxy::SetChannelImplFromTransport_w(TransportChannelProxy* proxy,
+ int component) {
+ ASSERT(rtc::Thread::Current() == worker_thread_);
+ TransportChannelImpl* impl = transport_->get()->GetChannel(component);
+ ASSERT(impl != NULL);
+ ReplaceChannelImpl_w(proxy, impl);
+}
+
+void TransportProxy::ReplaceChannelImpl(TransportChannelProxy* proxy,
+ TransportChannelImpl* impl) {
+ worker_thread_->Invoke<void>(Bind(
+ &TransportProxy::ReplaceChannelImpl_w, this, proxy, impl));
+}
+
+void TransportProxy::ReplaceChannelImpl_w(TransportChannelProxy* proxy,
+ TransportChannelImpl* impl) {
+ ASSERT(rtc::Thread::Current() == worker_thread_);
+ ASSERT(proxy != NULL);
+ proxy->SetImplementation(impl);
+}
+
+// This function muxes |this| onto |target| by repointing |this| at
+// |target|'s transport and setting our TransportChannelProxies
+// to point to |target|'s underlying implementations.
+bool TransportProxy::SetupMux(TransportProxy* target) {
+ // Bail out if there's nothing to do.
+ if (transport_ == target->transport_) {
+ return true;
+ }
+
+ // Run through all channels and remove any non-rtp transport channels before
+ // setting target transport channels.
+ for (ChannelMap::const_iterator iter = channels_.begin();
+ iter != channels_.end(); ++iter) {
+ if (!target->transport_->get()->HasChannel(iter->first)) {
+ // Remove if channel doesn't exist in |transport_|.
+ ReplaceChannelImpl(iter->second, NULL);
+ } else {
+ // Replace the impl for all the TransportProxyChannels with the channels
+ // from |target|'s transport. Fail if there's not an exact match.
+ ReplaceChannelImpl(
+ iter->second, target->transport_->get()->CreateChannel(iter->first));
+ }
+ }
+
+ // Now replace our transport. Must happen afterwards because
+ // it deletes all impls as a side effect.
+ transport_ = target->transport_;
+ transport_->get()->SignalCandidatesReady.connect(
+ this, &TransportProxy::OnTransportCandidatesReady);
+ set_candidates_allocated(target->candidates_allocated());
+ return true;
+}
+
+void TransportProxy::SetIceRole(IceRole role) {
+ transport_->get()->SetIceRole(role);
+}
+
+bool TransportProxy::SetLocalTransportDescription(
+ const TransportDescription& description,
+ ContentAction action,
+ std::string* error_desc) {
+ // If this is an answer, finalize the negotiation.
+ if (action == CA_ANSWER) {
+ CompleteNegotiation();
+ }
+ bool result = transport_->get()->SetLocalTransportDescription(description,
+ action,
+ error_desc);
+ if (result)
+ local_description_set_ = true;
+ return result;
+}
+
+bool TransportProxy::SetRemoteTransportDescription(
+ const TransportDescription& description,
+ ContentAction action,
+ std::string* error_desc) {
+ // If this is an answer, finalize the negotiation.
+ if (action == CA_ANSWER) {
+ CompleteNegotiation();
+ }
+ bool result = transport_->get()->SetRemoteTransportDescription(description,
+ action,
+ error_desc);
+ if (result)
+ remote_description_set_ = true;
+ return result;
+}
+
+void TransportProxy::OnSignalingReady() {
+ // If we're starting a new allocation sequence, reset our state.
+ set_candidates_allocated(false);
+ transport_->get()->OnSignalingReady();
+}
+
+bool TransportProxy::OnRemoteCandidates(const Candidates& candidates,
+ std::string* error) {
+ // Ensure the transport is negotiated before handling candidates.
+ // TODO(juberti): Remove this once everybody calls SetLocalTD.
+ CompleteNegotiation();
+
+ // Ignore candidates for if the proxy content_name doesn't match the content
+ // name of the actual transport. This stops video candidates from being sent
+ // down to the audio transport when BUNDLE is enabled.
+ if (content_name_ != transport_->get()->content_name()) {
+ return true;
+ }
+
+ // Verify each candidate before passing down to transport layer.
+ for (Candidates::const_iterator cand = candidates.begin();
+ cand != candidates.end(); ++cand) {
+ if (!transport_->get()->VerifyCandidate(*cand, error))
+ return false;
+ if (!HasChannel(cand->component())) {
+ *error = "Candidate has unknown component: " + cand->ToString() +
+ " for content: " + content_name_;
+ return false;
+ }
+ }
+ transport_->get()->OnRemoteCandidates(candidates);
+ return true;
+}
+
+void TransportProxy::SetCertificate(
+ const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) {
+ transport_->get()->SetCertificate(certificate);
+}
+
std::string BaseSession::StateToString(State state) {
switch (state) {
case STATE_INIT:
@@ -70,6 +326,7 @@
rtc::Thread* worker_thread,
PortAllocator* port_allocator,
const std::string& sid,
+ const std::string& content_type,
bool initiator)
: state_(STATE_INIT),
error_(ERROR_NONE),
@@ -77,11 +334,13 @@
worker_thread_(worker_thread),
port_allocator_(port_allocator),
sid_(sid),
- transport_controller_(new TransportController(signaling_thread,
- worker_thread,
- port_allocator)) {
+ content_type_(content_type),
+ initiator_(initiator),
+ ssl_max_version_(rtc::SSL_PROTOCOL_DTLS_10),
+ ice_tiebreaker_(rtc::CreateRandomId64()),
+ role_switch_(false),
+ ice_receiving_timeout_(-1) {
ASSERT(signaling_thread->IsCurrent());
- set_initiator(initiator);
}
BaseSession::~BaseSession() {
@@ -91,6 +350,11 @@
LogState(state_, STATE_DEINIT);
state_ = STATE_DEINIT;
SignalState(this, state_);
+
+ for (TransportMap::iterator iter = transports_.begin();
+ iter != transports_.end(); ++iter) {
+ delete iter->second;
+ }
}
const SessionDescription* BaseSession::local_description() const {
@@ -120,23 +384,37 @@
remote_description_.reset(sdesc);
}
-void BaseSession::set_initiator(bool initiator) {
- initiator_ = initiator;
-
- IceRole ice_role = initiator ? ICEROLE_CONTROLLING : ICEROLE_CONTROLLED;
- transport_controller_->SetIceRole(ice_role);
-}
-
const SessionDescription* BaseSession::initiator_description() const {
// TODO(tommi): Assert on thread correctness.
return initiator_ ? local_description_.get() : remote_description_.get();
}
+bool BaseSession::SetCertificate(
+ const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) {
+ if (certificate_)
+ return false;
+ if (!certificate)
+ return false;
+ certificate_ = certificate;
+ for (TransportMap::iterator iter = transports_.begin();
+ iter != transports_.end(); ++iter) {
+ iter->second->SetCertificate(certificate_);
+ }
+ return true;
+}
+
+bool BaseSession::SetSslMaxProtocolVersion(rtc::SSLProtocolVersion version) {
+ if (state_ != STATE_INIT) {
+ return false;
+ }
+
+ ssl_max_version_ = version;
+ return true;
+}
+
bool BaseSession::PushdownTransportDescription(ContentSource source,
ContentAction action,
std::string* error_desc) {
- ASSERT(signaling_thread()->IsCurrent());
-
if (source == CS_LOCAL) {
return PushdownLocalTransportDescription(local_description(),
action,
@@ -150,17 +428,23 @@
bool BaseSession::PushdownLocalTransportDescription(
const SessionDescription* sdesc,
ContentAction action,
- std::string* err) {
- ASSERT(signaling_thread()->IsCurrent());
+ std::string* error_desc) {
+ // Update the Transports with the right information, and trigger them to
+ // start connecting.
+ for (TransportMap::iterator iter = transports_.begin();
+ iter != transports_.end(); ++iter) {
+ // If no transport info was in this session description, ret == false
+ // and we just skip this one.
+ TransportDescription tdesc;
+ bool ret = GetTransportDescription(
+ sdesc, iter->second->content_name(), &tdesc);
+ if (ret) {
+ if (!iter->second->SetLocalTransportDescription(tdesc, action,
+ error_desc)) {
+ return false;
+ }
- if (!sdesc) {
- return false;
- }
-
- for (const TransportInfo& tinfo : sdesc->transport_infos()) {
- if (!transport_controller_->SetLocalTransportDescription(
- tinfo.content_name, tinfo.description, action, err)) {
- return false;
+ iter->second->ConnectChannels();
}
}
@@ -170,23 +454,134 @@
bool BaseSession::PushdownRemoteTransportDescription(
const SessionDescription* sdesc,
ContentAction action,
- std::string* err) {
- ASSERT(signaling_thread()->IsCurrent());
+ std::string* error_desc) {
+ // Update the Transports with the right information.
+ for (TransportMap::iterator iter = transports_.begin();
+ iter != transports_.end(); ++iter) {
+ TransportDescription tdesc;
- if (!sdesc) {
- return false;
- }
-
- for (const TransportInfo& tinfo : sdesc->transport_infos()) {
- if (!transport_controller_->SetRemoteTransportDescription(
- tinfo.content_name, tinfo.description, action, err)) {
- return false;
+ // If no transport info was in this session description, ret == false
+ // and we just skip this one.
+ bool ret = GetTransportDescription(
+ sdesc, iter->second->content_name(), &tdesc);
+ if (ret) {
+ if (!iter->second->SetRemoteTransportDescription(tdesc, action,
+ error_desc)) {
+ return false;
+ }
}
}
return true;
}
+void BaseSession::SetIceConnectionReceivingTimeout(int timeout_ms) {
+ ice_receiving_timeout_ = timeout_ms;
+ for (const auto& kv : transport_proxies()) {
+ Transport* transport = kv.second->impl();
+ if (transport) {
+ transport->SetChannelReceivingTimeout(timeout_ms);
+ }
+ }
+}
+
+TransportChannel* BaseSession::CreateChannel(const std::string& content_name,
+ int component) {
+ // We create the proxy "on demand" here because we need to support
+ // creating channels at any time, even before we send or receive
+ // initiate messages, which is before we create the transports.
+ TransportProxy* transproxy = GetOrCreateTransportProxy(content_name);
+ return transproxy->CreateChannel(component);
+}
+
+TransportChannel* BaseSession::GetChannel(const std::string& content_name,
+ int component) {
+ TransportProxy* transproxy = GetTransportProxy(content_name);
+ if (transproxy == NULL)
+ return NULL;
+
+ return transproxy->GetChannel(component);
+}
+
+void BaseSession::DestroyChannel(const std::string& content_name,
+ int component) {
+ TransportProxy* transproxy = GetTransportProxy(content_name);
+ ASSERT(transproxy != NULL);
+ transproxy->DestroyChannel(component);
+}
+
+TransportProxy* BaseSession::GetOrCreateTransportProxy(
+ const std::string& content_name) {
+ TransportProxy* transproxy = GetTransportProxy(content_name);
+ if (transproxy)
+ return transproxy;
+
+ Transport* transport = CreateTransport(content_name);
+ transport->SetIceRole(initiator_ ? ICEROLE_CONTROLLING : ICEROLE_CONTROLLED);
+ transport->SetIceTiebreaker(ice_tiebreaker_);
+ transport->SetSslMaxProtocolVersion(ssl_max_version_);
+ // TODO: Connect all the Transport signals to TransportProxy
+ // then to the BaseSession.
+ transport->SignalConnecting.connect(
+ this, &BaseSession::OnTransportConnecting);
+ transport->SignalWritableState.connect(
+ this, &BaseSession::OnTransportWritable);
+ transport->SignalReceivingState.connect(
+ this, &BaseSession::OnTransportReceiving);
+ transport->SignalRequestSignaling.connect(
+ this, &BaseSession::OnTransportRequestSignaling);
+ transport->SignalRouteChange.connect(
+ this, &BaseSession::OnTransportRouteChange);
+ transport->SignalCandidatesAllocationDone.connect(
+ this, &BaseSession::OnTransportCandidatesAllocationDone);
+ transport->SignalRoleConflict.connect(
+ this, &BaseSession::OnRoleConflict);
+ transport->SignalCompleted.connect(
+ this, &BaseSession::OnTransportCompleted);
+ transport->SignalFailed.connect(
+ this, &BaseSession::OnTransportFailed);
+
+ transproxy = new TransportProxy(worker_thread_, sid_, content_name,
+ new TransportWrapper(transport));
+ transproxy->SignalCandidatesReady.connect(
+ this, &BaseSession::OnTransportProxyCandidatesReady);
+ if (certificate_)
+ transproxy->SetCertificate(certificate_);
+ transports_[content_name] = transproxy;
+
+ return transproxy;
+}
+
+Transport* BaseSession::GetTransport(const std::string& content_name) {
+ TransportProxy* transproxy = GetTransportProxy(content_name);
+ if (transproxy == NULL)
+ return NULL;
+ return transproxy->impl();
+}
+
+TransportProxy* BaseSession::GetTransportProxy(
+ const std::string& content_name) {
+ TransportMap::iterator iter = transports_.find(content_name);
+ return (iter != transports_.end()) ? iter->second : NULL;
+}
+
+void BaseSession::DestroyTransportProxy(
+ const std::string& content_name) {
+ TransportMap::iterator iter = transports_.find(content_name);
+ if (iter != transports_.end()) {
+ delete iter->second;
+ transports_.erase(content_name);
+ }
+}
+
+Transport* BaseSession::CreateTransport(const std::string& content_name) {
+ Transport* transport = new DtlsTransport<P2PTransport>(
+ signaling_thread(), worker_thread(), content_name, port_allocator(),
+ certificate_);
+ transport->SetChannelReceivingTimeout(ice_receiving_timeout_);
+ return transport;
+}
+
void BaseSession::SetState(State state) {
ASSERT(signaling_thread_->IsCurrent());
if (state != state_) {
@@ -206,14 +601,180 @@
}
}
-void BaseSession::SetIceConnectionReceivingTimeout(int timeout_ms) {
- transport_controller_->SetIceConnectionReceivingTimeout(timeout_ms);
+void BaseSession::OnSignalingReady() {
+ ASSERT(signaling_thread()->IsCurrent());
+ for (TransportMap::iterator iter = transports_.begin();
+ iter != transports_.end(); ++iter) {
+ iter->second->OnSignalingReady();
+ }
+}
+
+// TODO(juberti): Since PushdownLocalTD now triggers the connection process to
+// start, remove this method once everyone calls PushdownLocalTD.
+void BaseSession::SpeculativelyConnectAllTransportChannels() {
+ // Put all transports into the connecting state.
+ for (TransportMap::iterator iter = transports_.begin();
+ iter != transports_.end(); ++iter) {
+ iter->second->ConnectChannels();
+ }
+}
+
+bool BaseSession::OnRemoteCandidates(const std::string& content_name,
+ const Candidates& candidates,
+ std::string* error) {
+ // Give candidates to the appropriate transport, and tell that transport
+ // to start connecting, if it's not already doing so.
+ TransportProxy* transproxy = GetTransportProxy(content_name);
+ if (!transproxy) {
+ *error = "Unknown content name " + content_name;
+ return false;
+ }
+ if (!transproxy->OnRemoteCandidates(candidates, error)) {
+ return false;
+ }
+ // TODO(juberti): Remove this call once we can be sure that we always have
+ // a local transport description (which will trigger the connection).
+ transproxy->ConnectChannels();
+ return true;
+}
+
+bool BaseSession::MaybeEnableMuxingSupport() {
+ // We need both a local and remote description to decide if we should mux.
+ if ((state_ == STATE_SENTINITIATE ||
+ state_ == STATE_RECEIVEDINITIATE) &&
+ ((local_description_ == NULL) ||
+ (remote_description_ == NULL))) {
+ return false;
+ }
+
+ // In order to perform the multiplexing, we need all proxies to be in the
+ // negotiated state, i.e. to have implementations underneath.
+ // Ensure that this is the case, regardless of whether we are going to mux.
+ for (TransportMap::iterator iter = transports_.begin();
+ iter != transports_.end(); ++iter) {
+ ASSERT(iter->second->negotiated());
+ if (!iter->second->negotiated()) {
+ return false;
+ }
+ }
+
+ // If both sides agree to BUNDLE, mux all the specified contents onto the
+ // transport belonging to the first content name in the BUNDLE group.
+ // If the contents are already muxed, this will be a no-op.
+ // TODO(juberti): Should this check that local and remote have configured
+ // BUNDLE the same way?
+ bool candidates_allocated = IsCandidateAllocationDone();
+ const ContentGroup* local_bundle_group =
+ local_description_->GetGroupByName(GROUP_TYPE_BUNDLE);
+ const ContentGroup* remote_bundle_group =
+ remote_description_->GetGroupByName(GROUP_TYPE_BUNDLE);
+ if (local_bundle_group && remote_bundle_group) {
+ if (!BundleContentGroup(local_bundle_group)) {
+ LOG(LS_WARNING) << "Failed to set up BUNDLE";
+ return false;
+ }
+
+ // If we weren't done gathering before, we might be done now, as a result
+ // of enabling mux.
+ if (!candidates_allocated) {
+ MaybeCandidateAllocationDone();
+ }
+ } else {
+ LOG(LS_INFO) << "BUNDLE group missing from remote or local description.";
+ }
+ return true;
+}
+
+bool BaseSession::BundleContentGroup(const ContentGroup* bundle_group) {
+ const std::string* content_name = bundle_group->FirstContentName();
+ if (!content_name) {
+ LOG(LS_INFO) << "No content names specified in BUNDLE group.";
+ return true;
+ }
+
+ TransportProxy* selected_proxy = GetTransportProxy(*content_name);
+ if (!selected_proxy) {
+ LOG(LS_WARNING) << "No transport found for content \""
+ << *content_name << "\".";
+ return false;
+ }
+
+ for (TransportMap::iterator iter = transports_.begin();
+ iter != transports_.end(); ++iter) {
+ // If content is part of the mux group, then repoint its proxy at the
+ // transport object that we have chosen to mux onto. If the proxy
+ // is already pointing at the right object, it will be a no-op.
+ if (bundle_group->HasContentName(iter->first) &&
+ !iter->second->SetupMux(selected_proxy)) {
+ LOG(LS_WARNING) << "Failed to bundle " << iter->first << " to "
+ << *content_name;
+ return false;
+ }
+ LOG(LS_INFO) << "Bundling " << iter->first << " to " << *content_name;
+ }
+
+ return true;
+}
+
+void BaseSession::OnTransportCandidatesAllocationDone(Transport* transport) {
+ // TODO(juberti): This is a clunky way of processing the done signal. Instead,
+ // TransportProxy should receive the done signal directly, set its allocated
+ // flag internally, and then reissue the done signal to Session.
+ // Overall we should make TransportProxy receive *all* the signals from
+ // Transport, since this removes the need to manually iterate over all
+ // the transports, as is needed to make sure signals are handled properly
+ // when BUNDLEing.
+ // TODO(juberti): Per b/7998978, devs and QA are hitting this assert in ways
+ // that make it prohibitively difficult to run dbg builds. Disabled for now.
+ //ASSERT(!IsCandidateAllocationDone());
+ for (TransportMap::iterator iter = transports_.begin();
+ iter != transports_.end(); ++iter) {
+ if (iter->second->impl() == transport) {
+ iter->second->set_candidates_allocated(true);
+ }
+ }
+ MaybeCandidateAllocationDone();
+}
+
+bool BaseSession::IsCandidateAllocationDone() const {
+ for (TransportMap::const_iterator iter = transports_.begin();
+ iter != transports_.end(); ++iter) {
+ if (!iter->second->candidates_allocated()) {
+ LOG(LS_INFO) << "Candidate allocation not done for "
+ << iter->second->content_name();
+ return false;
+ }
+ }
+ return true;
+}
+
+void BaseSession::MaybeCandidateAllocationDone() {
+ if (IsCandidateAllocationDone()) {
+ LOG(LS_INFO) << "Candidate gathering is complete.";
+ OnCandidatesAllocationDone();
+ }
+}
+
+void BaseSession::OnRoleConflict() {
+ if (role_switch_) {
+ LOG(LS_WARNING) << "Repeat of role conflict signal from Transport.";
+ return;
+ }
+
+ role_switch_ = true;
+ for (TransportMap::iterator iter = transports_.begin();
+ iter != transports_.end(); ++iter) {
+ // Role will be reverse of initial role setting.
+ IceRole role = initiator_ ? ICEROLE_CONTROLLED : ICEROLE_CONTROLLING;
+ iter->second->SetIceRole(role);
+ }
}
void BaseSession::LogState(State old_state, State new_state) {
LOG(LS_INFO) << "Session:" << id()
<< " Old state:" << StateToString(old_state)
- << " New state:" << StateToString(new_state);
+ << " New state:" << StateToString(new_state)
+ << " Type:" << content_type();
}
// static
diff --git a/webrtc/p2p/base/session.h b/webrtc/p2p/base/session.h
index 7fcf29b..8d7aa21 100644
--- a/webrtc/p2p/base/session.h
+++ b/webrtc/p2p/base/session.h
@@ -16,14 +16,14 @@
#include <string>
#include <vector>
+#include "webrtc/p2p/base/candidate.h"
+#include "webrtc/p2p/base/port.h"
+#include "webrtc/p2p/base/transport.h"
#include "webrtc/base/refcount.h"
#include "webrtc/base/rtccertificate.h"
#include "webrtc/base/scoped_ptr.h"
#include "webrtc/base/scoped_ref_ptr.h"
#include "webrtc/base/socketaddress.h"
-#include "webrtc/p2p/base/candidate.h"
-#include "webrtc/p2p/base/port.h"
-#include "webrtc/p2p/base/transport.h"
namespace cricket {
@@ -31,8 +31,136 @@
class P2PTransportChannel;
class Transport;
class TransportChannel;
+class TransportChannelProxy;
class TransportChannelImpl;
-class TransportController;
+
+typedef rtc::RefCountedObject<rtc::scoped_ptr<Transport> >
+TransportWrapper;
+
+// Bundles a Transport and ChannelMap together. ChannelMap is used to
+// create transport channels before receiving or sending a session
+// initiate, and for speculatively connecting channels. Previously, a
+// session had one ChannelMap and transport. Now, with multiple
+// transports per session, we need multiple ChannelMaps as well.
+
+typedef std::map<int, TransportChannelProxy*> ChannelMap;
+
+class TransportProxy : public sigslot::has_slots<> {
+ public:
+ TransportProxy(
+ rtc::Thread* worker_thread,
+ const std::string& sid,
+ const std::string& content_name,
+ TransportWrapper* transport)
+ : worker_thread_(worker_thread),
+ sid_(sid),
+ content_name_(content_name),
+ transport_(transport),
+ connecting_(false),
+ negotiated_(false),
+ sent_candidates_(false),
+ candidates_allocated_(false),
+ local_description_set_(false),
+ remote_description_set_(false) {
+ transport_->get()->SignalCandidatesReady.connect(
+ this, &TransportProxy::OnTransportCandidatesReady);
+ }
+ ~TransportProxy();
+
+ const std::string& content_name() const { return content_name_; }
+ // TODO(juberti): It's not good form to expose the object you're wrapping,
+ // since callers can mutate it. Can we make this return a const Transport*?
+ Transport* impl() const { return transport_->get(); }
+
+ const std::string& type() const;
+ bool negotiated() const { return negotiated_; }
+ const Candidates& sent_candidates() const { return sent_candidates_; }
+ const Candidates& unsent_candidates() const { return unsent_candidates_; }
+ bool candidates_allocated() const { return candidates_allocated_; }
+ void set_candidates_allocated(bool allocated) {
+ candidates_allocated_ = allocated;
+ }
+
+ TransportChannel* GetChannel(int component);
+ TransportChannel* CreateChannel(int component);
+ bool HasChannel(int component);
+ void DestroyChannel(int component);
+
+ void AddSentCandidates(const Candidates& candidates);
+ void AddUnsentCandidates(const Candidates& candidates);
+ void ClearSentCandidates() { sent_candidates_.clear(); }
+ void ClearUnsentCandidates() { unsent_candidates_.clear(); }
+
+ // Start the connection process for any channels, creating impls if needed.
+ void ConnectChannels();
+ // Hook up impls to the proxy channels. Doesn't change connect state.
+ void CompleteNegotiation();
+
+ // Mux this proxy onto the specified proxy's transport.
+ bool SetupMux(TransportProxy* proxy);
+
+ // Simple functions that thunk down to the same functions on Transport.
+ void SetIceRole(IceRole role);
+ void SetCertificate(
+ const rtc::scoped_refptr<rtc::RTCCertificate>& certificate);
+ bool SetLocalTransportDescription(const TransportDescription& description,
+ ContentAction action,
+ std::string* error_desc);
+ bool SetRemoteTransportDescription(const TransportDescription& description,
+ ContentAction action,
+ std::string* error_desc);
+ void OnSignalingReady();
+ bool OnRemoteCandidates(const Candidates& candidates, std::string* error);
+
+ // Called when a transport signals that it has new candidates.
+ void OnTransportCandidatesReady(cricket::Transport* transport,
+ const Candidates& candidates) {
+ SignalCandidatesReady(this, candidates);
+ }
+
+ bool local_description_set() const {
+ return local_description_set_;
+ }
+ bool remote_description_set() const {
+ return remote_description_set_;
+ }
+
+ // Handles sending of ready candidates and receiving of remote candidates.
+ sigslot::signal2<TransportProxy*,
+ const std::vector<Candidate>&> SignalCandidatesReady;
+
+ private:
+ TransportChannelProxy* GetChannelProxy(int component) const;
+
+ // Creates a new channel on the Transport which causes the reference
+ // count to increment.
+ void CreateChannelImpl(int component);
+ void CreateChannelImpl_w(int component);
+
+ // Manipulators of transportchannelimpl in channel proxy.
+ void SetChannelImplFromTransport(TransportChannelProxy* proxy, int component);
+ void SetChannelImplFromTransport_w(TransportChannelProxy* proxy,
+ int component);
+ void ReplaceChannelImpl(TransportChannelProxy* proxy,
+ TransportChannelImpl* impl);
+ void ReplaceChannelImpl_w(TransportChannelProxy* proxy,
+ TransportChannelImpl* impl);
+
+ rtc::Thread* const worker_thread_;
+ const std::string sid_;
+ const std::string content_name_;
+ rtc::scoped_refptr<TransportWrapper> transport_;
+ bool connecting_;
+ bool negotiated_;
+ ChannelMap channels_;
+ Candidates sent_candidates_;
+ Candidates unsent_candidates_;
+ bool candidates_allocated_;
+ bool local_description_set_;
+ bool remote_description_set_;
+};
+
+typedef std::map<std::string, TransportProxy*> TransportMap;
// Statistics for all the transports of this session.
typedef std::map<std::string, TransportStats> TransportStatsMap;
@@ -96,6 +224,7 @@
rtc::Thread* worker_thread,
PortAllocator* port_allocator,
const std::string& sid,
+ const std::string& content_type,
bool initiator);
virtual ~BaseSession();
@@ -107,6 +236,14 @@
// The ID of this session.
const std::string& id() const { return sid_; }
+ // TODO(juberti): This data is largely redundant, as it can now be obtained
+ // from local/remote_description(). Remove these functions and members.
+ // Returns the XML namespace identifying the type of this session.
+ const std::string& content_type() const { return content_type_; }
+
+ // Indicates whether we initiated this session.
+ bool initiator() const { return initiator_; }
+
// Returns the application-level description given by our client.
// If we are the recipient, this will be NULL until we send an accept.
const SessionDescription* local_description() const;
@@ -123,9 +260,6 @@
// Takes ownership of SessionDescription*
void set_remote_description(SessionDescription* sdesc);
- void set_initiator(bool initiator);
- bool initiator() const { return initiator_; }
-
const SessionDescription* initiator_description() const;
// Returns the current state of the session. See the enum above for details.
@@ -146,25 +280,151 @@
// TODO(ronghuawu): remove the SetError method that doesn't take |error_desc|.
virtual void SetError(Error error, const std::string& error_desc);
+ // Fired when the remote description is updated, with the updated
+ // contents.
+ sigslot::signal2<BaseSession* , const ContentInfos&>
+ SignalRemoteDescriptionUpdate;
+
+ // Fired when SetState is called (regardless if there's a state change), which
+ // indicates the session description might have be updated.
+ sigslot::signal2<BaseSession*, ContentAction> SignalNewLocalDescription;
+
+ // Fired when SetState is called (regardless if there's a state change), which
+ // indicates the session description might have be updated.
+ sigslot::signal2<BaseSession*, ContentAction> SignalNewRemoteDescription;
+
+ // Returns the transport that has been negotiated or NULL if
+ // negotiation is still in progress.
+ virtual Transport* GetTransport(const std::string& content_name);
+
+ // Creates a new channel with the given names. This method may be called
+ // immediately after creating the session. However, the actual
+ // implementation may not be fixed until transport negotiation completes.
+ // This will usually be called from the worker thread, but that
+ // shouldn't be an issue since the main thread will be blocked in
+ // Send when doing so.
+ virtual TransportChannel* CreateChannel(const std::string& content_name,
+ int component);
+
+ // Returns the channel with the given names.
+ virtual TransportChannel* GetChannel(const std::string& content_name,
+ int component);
+
+ // Destroys the channel with the given names.
+ // This will usually be called from the worker thread, but that
+ // shouldn't be an issue since the main thread will be blocked in
+ // Send when doing so.
+ virtual void DestroyChannel(const std::string& content_name,
+ int component);
+
+ // Set the ice connection receiving timeout.
void SetIceConnectionReceivingTimeout(int timeout_ms);
+ // For testing.
+ const rtc::scoped_refptr<rtc::RTCCertificate>&
+ certificate_for_testing() const {
+ return certificate_;
+ }
+
protected:
+ // Specifies the identity to use in this session.
+ bool SetCertificate(
+ const rtc::scoped_refptr<rtc::RTCCertificate>& certificate);
+
+ bool SetSslMaxProtocolVersion(rtc::SSLProtocolVersion version);
+
bool PushdownTransportDescription(ContentSource source,
ContentAction action,
std::string* error_desc);
+ void set_initiator(bool initiator) { initiator_ = initiator; }
+
+ const TransportMap& transport_proxies() const { return transports_; }
+ // Get a TransportProxy by content_name or transport. NULL if not found.
+ TransportProxy* GetTransportProxy(const std::string& content_name);
+ void DestroyTransportProxy(const std::string& content_name);
+ // TransportProxy is owned by session. Return proxy just for convenience.
+ TransportProxy* GetOrCreateTransportProxy(const std::string& content_name);
+ // Creates the actual transport object. Overridable for testing.
+ virtual Transport* CreateTransport(const std::string& content_name);
+
+ void OnSignalingReady();
+ void SpeculativelyConnectAllTransportChannels();
+ // Helper method to provide remote candidates to the transport.
+ bool OnRemoteCandidates(const std::string& content_name,
+ const Candidates& candidates,
+ std::string* error);
+
+ // This method will mux transport channels by content_name.
+ // First content is used for muxing.
+ bool MaybeEnableMuxingSupport();
+
+ // Called when a transport requests signaling.
+ virtual void OnTransportRequestSignaling(Transport* transport) {
+ }
+
+ // Called when the first channel of a transport begins connecting. We use
+ // this to start a timer, to make sure that the connection completes in a
+ // reasonable amount of time.
+ virtual void OnTransportConnecting(Transport* transport) {
+ }
+
+ // Called when a transport changes its writable state. We track this to make
+ // sure that the transport becomes writable within a reasonable amount of
+ // time. If this does not occur, we signal an error.
+ virtual void OnTransportWritable(Transport* transport) {
+ }
+ virtual void OnTransportReadable(Transport* transport) {
+ }
+
+ virtual void OnTransportReceiving(Transport* transport) {
+ }
+
+ // Called when a transport has found its steady-state connections.
+ virtual void OnTransportCompleted(Transport* transport) {
+ }
+
+ // Called when a transport has failed permanently.
+ virtual void OnTransportFailed(Transport* transport) {
+ }
+
+ // Called when a transport signals that it has new candidates.
+ virtual void OnTransportProxyCandidatesReady(TransportProxy* proxy,
+ const Candidates& candidates) {
+ }
+
+ virtual void OnTransportRouteChange(
+ Transport* transport,
+ int component,
+ const cricket::Candidate& remote_candidate) {
+ }
+
+ virtual void OnTransportCandidatesAllocationDone(Transport* transport);
+
+ // Called when all transport channels allocated required candidates.
+ // This method should be used as an indication of candidates gathering process
+ // is completed and application can now send local candidates list to remote.
+ virtual void OnCandidatesAllocationDone() {
+ }
+
+ // Handles the ice role change callback from Transport. This must be
+ // propagated to all the transports.
+ virtual void OnRoleConflict();
// Handles messages posted to us.
virtual void OnMessage(rtc::Message *pmsg);
- TransportController* transport_controller() {
- return transport_controller_.get();
- }
-
protected:
+ bool IsCandidateAllocationDone() const;
+
State state_;
Error error_;
std::string error_desc_;
+ // This method will delete the Transport and TransportChannelImpls
+ // and replace those with the Transport object of the first
+ // MediaContent in bundle_group.
+ bool BundleContentGroup(const ContentGroup* bundle_group);
+
private:
// Helper methods to push local and remote transport descriptions.
bool PushdownLocalTransportDescription(
@@ -174,6 +434,8 @@
const SessionDescription* sdesc, ContentAction action,
std::string* error_desc);
+ void MaybeCandidateAllocationDone();
+
// Log session state.
void LogState(State old_state, State new_state);
@@ -187,10 +449,21 @@
rtc::Thread* const worker_thread_;
PortAllocator* const port_allocator_;
const std::string sid_;
+ const std::string content_type_;
bool initiator_;
- rtc::scoped_ptr<TransportController> transport_controller_;
+ rtc::scoped_refptr<rtc::RTCCertificate> certificate_;
+ rtc::SSLProtocolVersion ssl_max_version_;
rtc::scoped_ptr<const SessionDescription> local_description_;
rtc::scoped_ptr<SessionDescription> remote_description_;
+ uint64 ice_tiebreaker_;
+ // This flag will be set to true after the first role switch. This flag
+ // will enable us to stop any role switch during the call.
+ bool role_switch_;
+ TransportMap transports_;
+
+ // Timeout value in milliseconds for which no ICE connection receives
+ // any packets.
+ int ice_receiving_timeout_;
};
} // namespace cricket
diff --git a/webrtc/p2p/base/session_unittest.cc b/webrtc/p2p/base/session_unittest.cc
new file mode 100644
index 0000000..3419cc3
--- /dev/null
+++ b/webrtc/p2p/base/session_unittest.cc
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2015 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/base/gunit.h"
+#include "webrtc/base/helpers.h"
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/base/thread.h"
+#include "webrtc/p2p/base/dtlstransportchannel.h"
+#include "webrtc/p2p/base/p2ptransportchannel.h"
+#include "webrtc/p2p/base/portallocator.h"
+#include "webrtc/p2p/base/session.h"
+#include "webrtc/p2p/base/transportchannelproxy.h"
+#include "webrtc/p2p/client/fakeportallocator.h"
+
+using cricket::BaseSession;
+using cricket::DtlsTransportChannelWrapper;
+using cricket::FakePortAllocator;
+using cricket::P2PTransportChannel;
+using cricket::PortAllocator;
+using cricket::TransportChannelProxy;
+using cricket::TransportProxy;
+
+class BaseSessionForTest : public BaseSession {
+ public:
+ BaseSessionForTest(rtc::Thread* signaling_thread,
+ rtc::Thread* worker_thread,
+ PortAllocator* port_allocator,
+ const std::string& sid,
+ const std::string& content_type,
+ bool initiator)
+ : BaseSession(signaling_thread,
+ worker_thread,
+ port_allocator,
+ sid,
+ content_type,
+ initiator) {}
+ using BaseSession::GetOrCreateTransportProxy;
+};
+
+class BaseSessionTest : public testing::Test {
+ public:
+ BaseSessionTest()
+ : port_allocator_(new FakePortAllocator(rtc::Thread::Current(), nullptr)),
+ session_(new BaseSessionForTest(rtc::Thread::Current(),
+ rtc::Thread::Current(),
+ port_allocator_.get(),
+ "123",
+ cricket::NS_JINGLE_RTP,
+ false)) {}
+ P2PTransportChannel* CreateChannel(const std::string& content,
+ int component) {
+ TransportProxy* transport_proxy =
+ session_->GetOrCreateTransportProxy(content);
+ // This hacking is needed in order that the p2p transport channel
+ // will be created in the following.
+ transport_proxy->CompleteNegotiation();
+
+ TransportChannelProxy* channel_proxy = static_cast<TransportChannelProxy*>(
+ session_->CreateChannel(content, component));
+ DtlsTransportChannelWrapper* dtls_channel =
+ static_cast<DtlsTransportChannelWrapper*>(channel_proxy->impl());
+ return static_cast<P2PTransportChannel*>(dtls_channel->channel());
+ }
+
+ rtc::scoped_ptr<PortAllocator> port_allocator_;
+ rtc::scoped_ptr<BaseSessionForTest> session_;
+};
+
+TEST_F(BaseSessionTest, TestSetIceReceivingTimeout) {
+ P2PTransportChannel* channel1 = CreateChannel("audio", 1);
+ ASSERT_NE(channel1, nullptr);
+ // These are the default values.
+ EXPECT_EQ(2500, channel1->receiving_timeout());
+ EXPECT_EQ(250, channel1->check_receiving_delay());
+ // Set the timeout to a different value.
+ session_->SetIceConnectionReceivingTimeout(1000);
+ EXPECT_EQ(1000, channel1->receiving_timeout());
+ EXPECT_EQ(100, channel1->check_receiving_delay());
+
+ // Even if a channel is created after setting the receiving timeout,
+ // the set timeout value is applied to the new channel.
+ P2PTransportChannel* channel2 = CreateChannel("video", 2);
+ ASSERT_NE(channel2, nullptr);
+ EXPECT_EQ(1000, channel2->receiving_timeout());
+ EXPECT_EQ(100, channel2->check_receiving_delay());
+
+ // Test minimum checking delay.
+ session_->SetIceConnectionReceivingTimeout(200);
+ EXPECT_EQ(200, channel1->receiving_timeout());
+ EXPECT_EQ(50, channel1->check_receiving_delay());
+ EXPECT_EQ(200, channel2->receiving_timeout());
+ EXPECT_EQ(50, channel2->check_receiving_delay());
+}
diff --git a/webrtc/p2p/base/transport.cc b/webrtc/p2p/base/transport.cc
index e3e6ca0..3322e38 100644
--- a/webrtc/p2p/base/transport.cc
+++ b/webrtc/p2p/base/transport.cc
@@ -8,8 +8,6 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include <utility> // for std::pair
-
#include "webrtc/p2p/base/transport.h"
#include "webrtc/p2p/base/candidate.h"
@@ -24,6 +22,40 @@
using rtc::Bind;
+enum {
+ MSG_ONSIGNALINGREADY = 1,
+ MSG_ONREMOTECANDIDATE,
+ MSG_READSTATE,
+ MSG_WRITESTATE,
+ MSG_REQUESTSIGNALING,
+ MSG_CANDIDATEREADY,
+ MSG_ROUTECHANGE,
+ MSG_CONNECTING,
+ MSG_CANDIDATEALLOCATIONCOMPLETE,
+ MSG_ROLECONFLICT,
+ MSG_COMPLETED,
+ MSG_FAILED,
+ MSG_RECEIVINGSTATE,
+};
+
+struct ChannelParams : public rtc::MessageData {
+ ChannelParams() : channel(NULL), candidate(NULL) {}
+ explicit ChannelParams(int component)
+ : component(component), channel(NULL), candidate(NULL) {}
+ explicit ChannelParams(Candidate* candidate)
+ : channel(NULL), candidate(candidate) {
+ }
+
+ ~ChannelParams() {
+ delete candidate;
+ }
+
+ std::string name;
+ int component;
+ TransportChannelImpl* channel;
+ Candidate* candidate;
+};
+
static bool VerifyIceParams(const TransportDescription& desc) {
// For legacy protocols.
if (desc.ice_ufrag.empty() && desc.ice_pwd.empty())
@@ -65,59 +97,58 @@
new_desc.ice_ufrag, new_desc.ice_pwd);
}
-Transport::Transport(const std::string& name, PortAllocator* allocator)
- : name_(name), allocator_(allocator) {}
+Transport::Transport(rtc::Thread* signaling_thread,
+ rtc::Thread* worker_thread,
+ const std::string& content_name,
+ PortAllocator* allocator)
+ : signaling_thread_(signaling_thread),
+ worker_thread_(worker_thread),
+ content_name_(content_name),
+ allocator_(allocator),
+ destroyed_(false),
+ readable_(TRANSPORT_STATE_NONE),
+ writable_(TRANSPORT_STATE_NONE),
+ receiving_(TRANSPORT_STATE_NONE),
+ was_writable_(false),
+ connect_requested_(false),
+ ice_role_(ICEROLE_UNKNOWN),
+ tiebreaker_(0),
+ remote_ice_mode_(ICEMODE_FULL),
+ channel_receiving_timeout_(-1) {
+}
Transport::~Transport() {
- ASSERT(channels_destroyed_);
-}
-
-bool Transport::AllChannelsCompleted() const {
- // We aren't completed until at least one channel is complete, so if there
- // are no channels, we aren't complete yet.
- if (channels_.empty()) {
- LOG(LS_INFO) << name() << " transport is not complete"
- << " because it has no TransportChannels";
- return false;
- }
-
- // A Transport's ICE process is completed if all of its channels are writable,
- // have finished allocating candidates, and have pruned all but one of their
- // connections.
- for (const auto& iter : channels_) {
- const TransportChannelImpl* channel = iter.second.get();
- bool complete =
- channel->writable() &&
- channel->GetState() == TransportChannelState::STATE_COMPLETED &&
- channel->GetIceRole() == ICEROLE_CONTROLLING &&
- channel->gathering_state() == kIceGatheringComplete;
- if (!complete) {
- LOG(LS_INFO) << name() << " transport is not complete"
- << " because a channel is still incomplete.";
- return false;
- }
- }
-
- return true;
-}
-
-bool Transport::AnyChannelFailed() const {
- for (const auto& iter : channels_) {
- if (iter.second->GetState() == TransportChannelState::STATE_FAILED) {
- return true;
- }
- }
- return false;
+ ASSERT(signaling_thread_->IsCurrent());
+ ASSERT(destroyed_);
}
void Transport::SetIceRole(IceRole role) {
- ice_role_ = role;
- for (auto& iter : channels_) {
- iter.second->SetIceRole(ice_role_);
- }
+ worker_thread_->Invoke<void>(Bind(&Transport::SetIceRole_w, this, role));
+}
+
+void Transport::SetCertificate(
+ const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) {
+ worker_thread_->Invoke<void>(Bind(&Transport::SetCertificate_w, this,
+ certificate));
+}
+
+bool Transport::GetCertificate(
+ rtc::scoped_refptr<rtc::RTCCertificate>* certificate) {
+ // The identity is set on the worker thread, so for safety it must also be
+ // acquired on the worker thread.
+ return worker_thread_->Invoke<bool>(
+ Bind(&Transport::GetCertificate_w, this, certificate));
}
bool Transport::GetRemoteSSLCertificate(rtc::SSLCertificate** cert) {
+ // Channels can be deleted on the worker thread, so for safety the remote
+ // certificate is acquired on the worker thread.
+ return worker_thread_->Invoke<bool>(
+ Bind(&Transport::GetRemoteSSLCertificate_w, this, cert));
+}
+
+bool Transport::GetRemoteSSLCertificate_w(rtc::SSLCertificate** cert) {
+ ASSERT(worker_thread()->IsCurrent());
if (channels_.empty())
return false;
@@ -126,6 +157,12 @@
}
void Transport::SetChannelReceivingTimeout(int timeout_ms) {
+ worker_thread_->Invoke<void>(
+ Bind(&Transport::SetChannelReceivingTimeout_w, this, timeout_ms));
+}
+
+void Transport::SetChannelReceivingTimeout_w(int timeout_ms) {
+ ASSERT(worker_thread()->IsCurrent());
channel_receiving_timeout_ = timeout_ms;
for (const auto& kv : channels_) {
kv.second->SetReceivingTimeout(timeout_ms);
@@ -136,74 +173,35 @@
const TransportDescription& description,
ContentAction action,
std::string* error_desc) {
- bool ret = true;
-
- if (!VerifyIceParams(description)) {
- return BadTransportDescription("Invalid ice-ufrag or ice-pwd length",
- error_desc);
- }
-
- if (local_description_ &&
- IceCredentialsChanged(*local_description_, description)) {
- IceRole new_ice_role =
- (action == CA_OFFER) ? ICEROLE_CONTROLLING : ICEROLE_CONTROLLED;
-
- // It must be called before ApplyLocalTransportDescription, which may
- // trigger an ICE restart and depends on the new ICE role.
- SetIceRole(new_ice_role);
- }
-
- local_description_.reset(new TransportDescription(description));
-
- for (auto& iter : channels_) {
- ret &= ApplyLocalTransportDescription(iter.second.get(), error_desc);
- }
- if (!ret) {
- return false;
- }
-
- // If PRANSWER/ANSWER is set, we should decide transport protocol type.
- if (action == CA_PRANSWER || action == CA_ANSWER) {
- ret &= NegotiateTransportDescription(action, error_desc);
- }
- if (ret) {
- local_description_set_ = true;
- // This kicks off candidate gathering.
- ConnectChannels();
- }
-
- return ret;
+ return worker_thread_->Invoke<bool>(Bind(
+ &Transport::SetLocalTransportDescription_w, this,
+ description, action, error_desc));
}
bool Transport::SetRemoteTransportDescription(
const TransportDescription& description,
ContentAction action,
std::string* error_desc) {
- bool ret = true;
-
- if (!VerifyIceParams(description)) {
- return BadTransportDescription("Invalid ice-ufrag or ice-pwd length",
- error_desc);
- }
-
- remote_description_.reset(new TransportDescription(description));
- for (auto& iter : channels_) {
- ret &= ApplyRemoteTransportDescription(iter.second.get(), error_desc);
- }
-
- // If PRANSWER/ANSWER is set, we should decide transport protocol type.
- if (action == CA_PRANSWER || action == CA_ANSWER) {
- ret = NegotiateTransportDescription(CA_OFFER, error_desc);
- }
- if (ret) {
- remote_description_set_ = true;
- }
-
- return ret;
+ return worker_thread_->Invoke<bool>(Bind(
+ &Transport::SetRemoteTransportDescription_w, this,
+ description, action, error_desc));
}
TransportChannelImpl* Transport::CreateChannel(int component) {
+ return worker_thread_->Invoke<TransportChannelImpl*>(Bind(
+ &Transport::CreateChannel_w, this, component));
+}
+
+TransportChannelImpl* Transport::CreateChannel_w(int component) {
+ ASSERT(worker_thread()->IsCurrent());
TransportChannelImpl* impl;
+ // TODO(tommi): We don't really need to grab the lock until the actual call
+ // to insert() below and presumably hold it throughout initialization of
+ // |impl| after the impl_exists check. Maybe we can factor that out to
+ // a separate function and not grab the lock in this function.
+ // Actually, we probably don't need to hold the lock while initializing
+ // |impl| since we can just do the insert when that's done.
+ rtc::CritScope cs(&crit_);
// Create the entry if it does not exist.
bool impl_exists = false;
@@ -219,7 +217,7 @@
// Increase the ref count.
iterator->second.AddRef();
- channels_destroyed_ = false;
+ destroyed_ = false;
if (impl_exists) {
// If this is an existing channel, we should just return it without
@@ -231,22 +229,24 @@
impl->SetIceRole(ice_role_);
impl->SetIceTiebreaker(tiebreaker_);
impl->SetReceivingTimeout(channel_receiving_timeout_);
- // TODO(ronghuawu): Change CreateChannel to be able to return error since
- // below Apply**Description calls can fail.
+ // TODO(ronghuawu): Change CreateChannel_w to be able to return error since
+ // below Apply**Description_w calls can fail.
if (local_description_)
- ApplyLocalTransportDescription(impl, NULL);
+ ApplyLocalTransportDescription_w(impl, NULL);
if (remote_description_)
- ApplyRemoteTransportDescription(impl, NULL);
+ ApplyRemoteTransportDescription_w(impl, NULL);
if (local_description_ && remote_description_)
- ApplyNegotiatedTransportDescription(impl, NULL);
+ ApplyNegotiatedTransportDescription_w(impl, NULL);
impl->SignalReadableState.connect(this, &Transport::OnChannelReadableState);
impl->SignalWritableState.connect(this, &Transport::OnChannelWritableState);
impl->SignalReceivingState.connect(this, &Transport::OnChannelReceivingState);
- impl->SignalGatheringState.connect(this, &Transport::OnChannelGatheringState);
- impl->SignalCandidateGathered.connect(this,
- &Transport::OnChannelCandidateGathered);
+ impl->SignalRequestSignaling.connect(
+ this, &Transport::OnChannelRequestSignaling);
+ impl->SignalCandidateReady.connect(this, &Transport::OnChannelCandidateReady);
impl->SignalRouteChange.connect(this, &Transport::OnChannelRouteChange);
+ impl->SignalCandidatesAllocationDone.connect(
+ this, &Transport::OnChannelCandidatesAllocationDone);
impl->SignalRoleConflict.connect(this, &Transport::OnRoleConflict);
impl->SignalConnectionRemoved.connect(
this, &Transport::OnChannelConnectionRemoved);
@@ -256,22 +256,36 @@
if (channels_.size() == 1) {
// If this is the first channel, then indicate that we have started
// connecting.
- SignalConnecting(this);
+ signaling_thread()->Post(this, MSG_CONNECTING, NULL);
}
}
return impl;
}
TransportChannelImpl* Transport::GetChannel(int component) {
+ // TODO(tommi,pthatcher): Since we're returning a pointer from the channels_
+ // map, shouldn't we assume that we're on the worker thread? (The pointer
+ // will be used outside of the lock).
+ // And if we're on the worker thread, which is the only thread that modifies
+ // channels_, can we skip grabbing the lock?
+ rtc::CritScope cs(&crit_);
ChannelMap::iterator iter = channels_.find(component);
return (iter != channels_.end()) ? iter->second.get() : NULL;
}
bool Transport::HasChannels() {
+ rtc::CritScope cs(&crit_);
return !channels_.empty();
}
void Transport::DestroyChannel(int component) {
+ worker_thread_->Invoke<void>(Bind(
+ &Transport::DestroyChannel_w, this, component));
+}
+
+void Transport::DestroyChannel_w(int component) {
+ ASSERT(worker_thread()->IsCurrent());
+
ChannelMap::iterator iter = channels_.find(component);
if (iter == channels_.end())
return;
@@ -281,36 +295,34 @@
iter->second.DecRef();
if (!iter->second.ref()) {
impl = iter->second.get();
+ rtc::CritScope cs(&crit_);
channels_.erase(iter);
}
if (connect_requested_ && channels_.empty()) {
// We're no longer attempting to connect.
- SignalConnecting(this);
+ signaling_thread()->Post(this, MSG_CONNECTING, NULL);
}
if (impl) {
+ // Check in case the deleted channel was the only non-writable channel.
+ OnChannelWritableState(impl);
DestroyTransportChannel(impl);
- // Need to update aggregate state after destroying a channel,
- // for example if it was the only one that wasn't yet writable.
- UpdateReadableState();
- UpdateWritableState();
- UpdateReceivingState();
- UpdateGatheringState();
- MaybeSignalCompleted();
}
}
void Transport::ConnectChannels() {
+ ASSERT(signaling_thread()->IsCurrent());
+ worker_thread_->Invoke<void>(Bind(&Transport::ConnectChannels_w, this));
+}
+
+void Transport::ConnectChannels_w() {
+ ASSERT(worker_thread()->IsCurrent());
if (connect_requested_ || channels_.empty())
return;
connect_requested_ = true;
-
- if (!ready_candidates_.empty()) {
- SignalCandidatesGathered(this, ready_candidates_);
- ready_candidates_.clear();
- }
+ signaling_thread()->Post(this, MSG_CANDIDATEREADY, NULL);
if (!local_description_) {
// TOOD(mallinath) : TransportDescription(TD) shouldn't be generated here.
@@ -319,22 +331,38 @@
// Session.
// Session must generate local TD before remote candidates pushed when
// initiate request initiated by the remote.
- LOG(LS_INFO) << "Transport::ConnectChannels: No local description has "
+ LOG(LS_INFO) << "Transport::ConnectChannels_w: No local description has "
<< "been set. Will generate one.";
- TransportDescription desc(
- std::vector<std::string>(), rtc::CreateRandomString(ICE_UFRAG_LENGTH),
- rtc::CreateRandomString(ICE_PWD_LENGTH), ICEMODE_FULL,
- CONNECTIONROLE_NONE, NULL, Candidates());
- SetLocalTransportDescription(desc, CA_OFFER, NULL);
+ TransportDescription desc(std::vector<std::string>(),
+ rtc::CreateRandomString(ICE_UFRAG_LENGTH),
+ rtc::CreateRandomString(ICE_PWD_LENGTH),
+ ICEMODE_FULL, CONNECTIONROLE_NONE, NULL,
+ Candidates());
+ SetLocalTransportDescription_w(desc, CA_OFFER, NULL);
}
- CallChannels(&TransportChannelImpl::Connect);
- if (HasChannels()) {
- SignalConnecting(this);
+ CallChannels_w(&TransportChannelImpl::Connect);
+ if (!channels_.empty()) {
+ signaling_thread()->Post(this, MSG_CONNECTING, NULL);
}
}
+void Transport::OnConnecting_s() {
+ ASSERT(signaling_thread()->IsCurrent());
+ SignalConnecting(this);
+}
+
void Transport::DestroyAllChannels() {
+ ASSERT(signaling_thread()->IsCurrent());
+ worker_thread_->Invoke<void>(Bind(&Transport::DestroyAllChannels_w, this));
+ worker_thread()->Clear(this);
+ signaling_thread()->Clear(this);
+ destroyed_ = true;
+}
+
+void Transport::DestroyAllChannels_w() {
+ ASSERT(worker_thread()->IsCurrent());
+
std::vector<TransportChannelImpl*> impls;
for (auto& iter : channels_) {
iter.second.DecRef();
@@ -342,15 +370,27 @@
impls.push_back(iter.second.get());
}
- channels_.clear();
-
- for (TransportChannelImpl* impl : impls) {
- DestroyTransportChannel(impl);
+ {
+ rtc::CritScope cs(&crit_);
+ channels_.clear();
}
- channels_destroyed_ = true;
+
+ for (size_t i = 0; i < impls.size(); ++i)
+ DestroyTransportChannel(impls[i]);
}
-void Transport::CallChannels(TransportChannelFunc func) {
+void Transport::OnSignalingReady() {
+ ASSERT(signaling_thread()->IsCurrent());
+ if (destroyed_) return;
+
+ worker_thread()->Post(this, MSG_ONSIGNALINGREADY, NULL);
+
+ // Notify the subclass.
+ OnTransportSignalingReady();
+}
+
+void Transport::CallChannels_w(TransportChannelFunc func) {
+ ASSERT(worker_thread()->IsCurrent());
for (const auto& iter : channels_) {
((iter.second.get())->*func)();
}
@@ -389,7 +429,14 @@
bool Transport::GetStats(TransportStats* stats) {
- stats->transport_name = name();
+ ASSERT(signaling_thread()->IsCurrent());
+ return worker_thread_->Invoke<bool>(Bind(
+ &Transport::GetStats_w, this, stats));
+}
+
+bool Transport::GetStats_w(TransportStats* stats) {
+ ASSERT(worker_thread()->IsCurrent());
+ stats->content_name = content_name();
stats->channel_stats.clear();
for (auto iter : channels_) {
ChannelMapEntry& entry = iter.second;
@@ -405,49 +452,96 @@
return true;
}
-bool Transport::AddRemoteCandidates(const std::vector<Candidate>& candidates,
- std::string* error) {
- ASSERT(!channels_destroyed_);
- // Verify each candidate before passing down to transport layer.
- for (const Candidate& cand : candidates) {
- if (!VerifyCandidate(cand, error)) {
- return false;
- }
- if (!HasChannel(cand.component())) {
- *error = "Candidate has unknown component: " + cand.ToString() +
- " for content: " + name();
- return false;
- }
- }
+bool Transport::GetSslRole(rtc::SSLRole* ssl_role) const {
+ return worker_thread_->Invoke<bool>(Bind(
+ &Transport::GetSslRole_w, this, ssl_role));
+}
+bool Transport::SetSslMaxProtocolVersion(rtc::SSLProtocolVersion version) {
+ return worker_thread_->Invoke<bool>(Bind(
+ &Transport::SetSslMaxProtocolVersion_w, this, version));
+}
+
+void Transport::OnRemoteCandidates(const std::vector<Candidate>& candidates) {
for (std::vector<Candidate>::const_iterator iter = candidates.begin();
iter != candidates.end();
++iter) {
- TransportChannelImpl* channel = GetChannel(iter->component());
- if (channel != NULL) {
- channel->AddRemoteCandidate(*iter);
- }
+ OnRemoteCandidate(*iter);
}
- return true;
+}
+
+void Transport::OnRemoteCandidate(const Candidate& candidate) {
+ ASSERT(signaling_thread()->IsCurrent());
+ if (destroyed_) return;
+
+ if (!HasChannel(candidate.component())) {
+ LOG(LS_WARNING) << "Ignoring candidate for unknown component "
+ << candidate.component();
+ return;
+ }
+
+ ChannelParams* params = new ChannelParams(new Candidate(candidate));
+ worker_thread()->Post(this, MSG_ONREMOTECANDIDATE, params);
+}
+
+void Transport::OnRemoteCandidate_w(const Candidate& candidate) {
+ ASSERT(worker_thread()->IsCurrent());
+ ChannelMap::iterator iter = channels_.find(candidate.component());
+ // It's ok for a channel to go away while this message is in transit.
+ if (iter != channels_.end()) {
+ iter->second->OnCandidate(candidate);
+ }
}
void Transport::OnChannelReadableState(TransportChannel* channel) {
- UpdateReadableState();
+ ASSERT(worker_thread()->IsCurrent());
+ signaling_thread()->Post(this, MSG_READSTATE, NULL);
+}
+
+void Transport::OnChannelReadableState_s() {
+ ASSERT(signaling_thread()->IsCurrent());
+ TransportState readable = GetTransportState_s(TRANSPORT_READABLE_STATE);
+ if (readable_ != readable) {
+ readable_ = readable;
+ SignalReadableState(this);
+ }
}
void Transport::OnChannelWritableState(TransportChannel* channel) {
- LOG(LS_INFO) << name() << " TransportChannel " << channel->component()
- << " writability changed to " << channel->writable()
- << ". Check if transport is complete.";
- UpdateWritableState();
- MaybeSignalCompleted();
+ ASSERT(worker_thread()->IsCurrent());
+ signaling_thread()->Post(this, MSG_WRITESTATE, NULL);
+
+ MaybeCompleted_w();
+}
+
+void Transport::OnChannelWritableState_s() {
+ ASSERT(signaling_thread()->IsCurrent());
+ TransportState writable = GetTransportState_s(TRANSPORT_WRITABLE_STATE);
+ if (writable_ != writable) {
+ was_writable_ = (writable_ == TRANSPORT_STATE_ALL);
+ writable_ = writable;
+ SignalWritableState(this);
+ }
}
void Transport::OnChannelReceivingState(TransportChannel* channel) {
- UpdateReceivingState();
+ ASSERT(worker_thread()->IsCurrent());
+ signaling_thread()->Post(this, MSG_RECEIVINGSTATE);
}
-TransportState Transport::GetTransportState(TransportStateType state_type) {
+void Transport::OnChannelReceivingState_s() {
+ ASSERT(signaling_thread()->IsCurrent());
+ TransportState receiving = GetTransportState_s(TRANSPORT_RECEIVING_STATE);
+ if (receiving_ != receiving) {
+ receiving_ = receiving;
+ SignalReceivingState(this);
+ }
+}
+
+TransportState Transport::GetTransportState_s(TransportStateType state_type) {
+ ASSERT(signaling_thread()->IsCurrent());
+
+ rtc::CritScope cs(&crit_);
bool any = false;
bool all = !channels_.empty();
for (const auto iter : channels_) {
@@ -478,48 +572,106 @@
return TRANSPORT_STATE_NONE;
}
-void Transport::OnChannelGatheringState(TransportChannelImpl* channel) {
- ASSERT(channels_.find(channel->component()) != channels_.end());
- UpdateGatheringState();
- if (gathering_state_ == kIceGatheringComplete) {
- // If UpdateGatheringState brought us to kIceGatheringComplete, check if
- // our connection state is also "Completed". Otherwise, there's no point in
- // checking (since it would only produce log messages).
- MaybeSignalCompleted();
- }
+void Transport::OnChannelRequestSignaling(TransportChannelImpl* channel) {
+ ASSERT(worker_thread()->IsCurrent());
+ // Resetting ICE state for the channel.
+ ChannelMap::iterator iter = channels_.find(channel->component());
+ if (iter != channels_.end())
+ iter->second.set_candidates_allocated(false);
+ signaling_thread()->Post(this, MSG_REQUESTSIGNALING, nullptr);
}
-void Transport::OnChannelCandidateGathered(TransportChannelImpl* channel,
- const Candidate& candidate) {
+void Transport::OnChannelRequestSignaling_s() {
+ ASSERT(signaling_thread()->IsCurrent());
+ LOG(LS_INFO) << "Transport: " << content_name_ << ", allocating candidates";
+ SignalRequestSignaling(this);
+}
+
+void Transport::OnChannelCandidateReady(TransportChannelImpl* channel,
+ const Candidate& candidate) {
// We should never signal peer-reflexive candidates.
if (candidate.type() == PRFLX_PORT_TYPE) {
ASSERT(false);
return;
}
+ ASSERT(worker_thread()->IsCurrent());
+ rtc::CritScope cs(&crit_);
+ ready_candidates_.push_back(candidate);
+
+ // We hold any messages until the client lets us connect.
if (connect_requested_) {
- std::vector<Candidate> candidates;
- candidates.push_back(candidate);
- SignalCandidatesGathered(this, candidates);
- } else {
- // We hold any candidates until the client lets us connect.
- ready_candidates_.push_back(candidate);
+ signaling_thread()->Post(
+ this, MSG_CANDIDATEREADY, NULL);
+ }
+}
+
+void Transport::OnChannelCandidateReady_s() {
+ ASSERT(signaling_thread()->IsCurrent());
+ ASSERT(connect_requested_);
+
+ std::vector<Candidate> candidates;
+ {
+ rtc::CritScope cs(&crit_);
+ candidates.swap(ready_candidates_);
+ }
+
+ // we do the deleting of Candidate* here to keep the new above and
+ // delete below close to each other
+ if (!candidates.empty()) {
+ SignalCandidatesReady(this, candidates);
}
}
void Transport::OnChannelRouteChange(TransportChannel* channel,
const Candidate& remote_candidate) {
+ ASSERT(worker_thread()->IsCurrent());
+ ChannelParams* params = new ChannelParams(new Candidate(remote_candidate));
+ params->channel = static_cast<cricket::TransportChannelImpl*>(channel);
+ signaling_thread()->Post(this, MSG_ROUTECHANGE, params);
+}
+
+void Transport::OnChannelRouteChange_s(const TransportChannel* channel,
+ const Candidate& remote_candidate) {
+ ASSERT(signaling_thread()->IsCurrent());
SignalRouteChange(this, remote_candidate.component(), remote_candidate);
}
+void Transport::OnChannelCandidatesAllocationDone(
+ TransportChannelImpl* channel) {
+ ASSERT(worker_thread()->IsCurrent());
+ ChannelMap::iterator iter = channels_.find(channel->component());
+ ASSERT(iter != channels_.end());
+ LOG(LS_INFO) << "Transport: " << content_name_ << ", component "
+ << channel->component() << " allocation complete";
+
+ iter->second.set_candidates_allocated(true);
+
+ // If all channels belonging to this Transport got signal, then
+ // forward this signal to upper layer.
+ // Can this signal arrive before all transport channels are created?
+ for (auto& iter : channels_) {
+ if (!iter.second.candidates_allocated())
+ return;
+ }
+ signaling_thread_->Post(this, MSG_CANDIDATEALLOCATIONCOMPLETE);
+
+ MaybeCompleted_w();
+}
+
+void Transport::OnChannelCandidatesAllocationDone_s() {
+ ASSERT(signaling_thread()->IsCurrent());
+ LOG(LS_INFO) << "Transport: " << content_name_ << " allocation complete";
+ SignalCandidatesAllocationDone(this);
+}
+
void Transport::OnRoleConflict(TransportChannelImpl* channel) {
- SignalRoleConflict();
+ signaling_thread_->Post(this, MSG_ROLECONFLICT);
}
void Transport::OnChannelConnectionRemoved(TransportChannelImpl* channel) {
- LOG(LS_INFO) << name() << " TransportChannel " << channel->component()
- << " connection removed. Check if transport is complete.";
- MaybeSignalCompleted();
+ ASSERT(worker_thread()->IsCurrent());
+ MaybeCompleted_w();
// Check if the state is now Failed.
// Failed is only available in the Controlling ICE role.
@@ -527,105 +679,158 @@
return;
}
- // Failed can only occur after candidate gathering has stopped.
- if (channel->gathering_state() != kIceGatheringComplete) {
+ ChannelMap::iterator iter = channels_.find(channel->component());
+ ASSERT(iter != channels_.end());
+ // Failed can only occur after candidate allocation has stopped.
+ if (!iter->second.candidates_allocated()) {
return;
}
if (channel->GetState() == TransportChannelState::STATE_FAILED) {
// A Transport has failed if any of its channels have no remaining
// connections.
- SignalFailed(this);
+ signaling_thread_->Post(this, MSG_FAILED);
}
}
-void Transport::MaybeSignalCompleted() {
- if (AllChannelsCompleted()) {
- LOG(LS_INFO) << name() << " transport is complete"
- << " because all the channels are complete.";
- SignalCompleted(this);
- }
- // TODO(deadbeef): Should we do anything if we previously were completed,
- // but now are not (if, for example, a new remote candidate is added)?
-}
+void Transport::MaybeCompleted_w() {
+ ASSERT(worker_thread()->IsCurrent());
-void Transport::UpdateGatheringState() {
- IceGatheringState new_state = kIceGatheringNew;
- bool any_gathering = false;
- bool all_complete = !channels_.empty();
- for (const auto& kv : channels_) {
- any_gathering =
- any_gathering || kv.second->gathering_state() != kIceGatheringNew;
- all_complete =
- all_complete && kv.second->gathering_state() == kIceGatheringComplete;
- }
- if (all_complete) {
- new_state = kIceGatheringComplete;
- } else if (any_gathering) {
- new_state = kIceGatheringGathering;
+ // When there is no channel created yet, calling this function could fire an
+ // IceConnectionCompleted event prematurely.
+ if (channels_.empty()) {
+ return;
}
- if (gathering_state_ != new_state) {
- gathering_state_ = new_state;
- if (gathering_state_ == kIceGatheringGathering) {
- LOG(LS_INFO) << "Transport: " << name_ << ", gathering candidates";
- } else if (gathering_state_ == kIceGatheringComplete) {
- LOG(LS_INFO) << "Transport " << name() << " gathering complete.";
+ // A Transport's ICE process is completed if all of its channels are writable,
+ // have finished allocating candidates, and have pruned all but one of their
+ // connections.
+ for (const auto& iter : channels_) {
+ const TransportChannelImpl* channel = iter.second.get();
+ if (!(channel->writable() &&
+ channel->GetState() == TransportChannelState::STATE_COMPLETED &&
+ channel->GetIceRole() == ICEROLE_CONTROLLING &&
+ iter.second.candidates_allocated())) {
+ return;
}
- SignalGatheringState(this);
+ }
+
+ signaling_thread_->Post(this, MSG_COMPLETED);
+}
+
+void Transport::SetIceRole_w(IceRole role) {
+ ASSERT(worker_thread()->IsCurrent());
+ rtc::CritScope cs(&crit_);
+ ice_role_ = role;
+ for (auto& iter : channels_) {
+ iter.second->SetIceRole(ice_role_);
}
}
-void Transport::UpdateReceivingState() {
- TransportState receiving = GetTransportState(TRANSPORT_RECEIVING_STATE);
- if (receiving_ != receiving) {
- receiving_ = receiving;
- SignalReceivingState(this);
+void Transport::SetRemoteIceMode_w(IceMode mode) {
+ ASSERT(worker_thread()->IsCurrent());
+ remote_ice_mode_ = mode;
+ // Shouldn't channels be created after this method executed?
+ for (auto& iter : channels_) {
+ iter.second->SetRemoteIceMode(remote_ice_mode_);
}
}
-void Transport::UpdateWritableState() {
- TransportState writable = GetTransportState(TRANSPORT_WRITABLE_STATE);
- LOG(LS_INFO) << name() << " transport writable state changed? " << writable_
- << " => " << writable;
- if (writable_ != writable) {
- was_writable_ = (writable_ == TRANSPORT_STATE_ALL);
- writable_ = writable;
- SignalWritableState(this);
+bool Transport::SetLocalTransportDescription_w(
+ const TransportDescription& desc,
+ ContentAction action,
+ std::string* error_desc) {
+ ASSERT(worker_thread()->IsCurrent());
+ bool ret = true;
+
+ if (!VerifyIceParams(desc)) {
+ return BadTransportDescription("Invalid ice-ufrag or ice-pwd length",
+ error_desc);
}
+
+ // TODO(tommi,pthatcher): I'm not sure why we need to grab this lock at this
+ // point. |local_description_| seems to always be modified on the worker
+ // thread, so we should be able to use it here without grabbing the lock.
+ // However, we _might_ need it before the call to reset() below?
+ // Raw access to |local_description_| is granted to derived transports outside
+ // of locking (see local_description() in the header file).
+ // The contract is that the derived implementations must be aware of when the
+ // description might change and do appropriate synchronization.
+ rtc::CritScope cs(&crit_);
+ if (local_description_ && IceCredentialsChanged(*local_description_, desc)) {
+ IceRole new_ice_role = (action == CA_OFFER) ? ICEROLE_CONTROLLING
+ : ICEROLE_CONTROLLED;
+
+ // It must be called before ApplyLocalTransportDescription_w, which may
+ // trigger an ICE restart and depends on the new ICE role.
+ SetIceRole_w(new_ice_role);
+ }
+
+ local_description_.reset(new TransportDescription(desc));
+
+ for (auto& iter : channels_) {
+ ret &= ApplyLocalTransportDescription_w(iter.second.get(), error_desc);
+ }
+ if (!ret)
+ return false;
+
+ // If PRANSWER/ANSWER is set, we should decide transport protocol type.
+ if (action == CA_PRANSWER || action == CA_ANSWER) {
+ ret &= NegotiateTransportDescription_w(action, error_desc);
+ }
+ return ret;
}
-void Transport::UpdateReadableState() {
- TransportState readable = GetTransportState(TRANSPORT_READABLE_STATE);
- if (readable_ != readable) {
- readable_ = readable;
- SignalReadableState(this);
+bool Transport::SetRemoteTransportDescription_w(
+ const TransportDescription& desc,
+ ContentAction action,
+ std::string* error_desc) {
+ bool ret = true;
+
+ if (!VerifyIceParams(desc)) {
+ return BadTransportDescription("Invalid ice-ufrag or ice-pwd length",
+ error_desc);
}
+
+ // TODO(tommi,pthatcher): See todo for local_description_ above.
+ rtc::CritScope cs(&crit_);
+ remote_description_.reset(new TransportDescription(desc));
+ for (auto& iter : channels_) {
+ ret &= ApplyRemoteTransportDescription_w(iter.second.get(), error_desc);
+ }
+
+ // If PRANSWER/ANSWER is set, we should decide transport protocol type.
+ if (action == CA_PRANSWER || action == CA_ANSWER) {
+ ret = NegotiateTransportDescription_w(CA_OFFER, error_desc);
+ }
+ return ret;
}
-bool Transport::ApplyLocalTransportDescription(TransportChannelImpl* ch,
- std::string* error_desc) {
+bool Transport::ApplyLocalTransportDescription_w(TransportChannelImpl* ch,
+ std::string* error_desc) {
+ ASSERT(worker_thread()->IsCurrent());
ch->SetIceCredentials(local_description_->ice_ufrag,
local_description_->ice_pwd);
return true;
}
-bool Transport::ApplyRemoteTransportDescription(TransportChannelImpl* ch,
- std::string* error_desc) {
+bool Transport::ApplyRemoteTransportDescription_w(TransportChannelImpl* ch,
+ std::string* error_desc) {
ch->SetRemoteIceCredentials(remote_description_->ice_ufrag,
remote_description_->ice_pwd);
return true;
}
-bool Transport::ApplyNegotiatedTransportDescription(
- TransportChannelImpl* channel,
- std::string* error_desc) {
+bool Transport::ApplyNegotiatedTransportDescription_w(
+ TransportChannelImpl* channel, std::string* error_desc) {
+ ASSERT(worker_thread()->IsCurrent());
channel->SetRemoteIceMode(remote_ice_mode_);
return true;
}
-bool Transport::NegotiateTransportDescription(ContentAction local_role,
- std::string* error_desc) {
+bool Transport::NegotiateTransportDescription_w(ContentAction local_role,
+ std::string* error_desc) {
+ ASSERT(worker_thread()->IsCurrent());
// TODO(ekr@rtfm.com): This is ICE-specific stuff. Refactor into
// P2PTransport.
@@ -633,7 +838,7 @@
// ice_lite, this local end point should take CONTROLLING role.
if (ice_role_ == ICEROLE_CONTROLLED &&
remote_description_->ice_mode == ICEMODE_LITE) {
- SetIceRole(ICEROLE_CONTROLLING);
+ SetIceRole_w(ICEROLE_CONTROLLING);
}
// Update remote ice_mode to all existing channels.
@@ -645,10 +850,60 @@
// creation, we have the negotiation state saved until a new
// negotiation happens.
for (auto& iter : channels_) {
- if (!ApplyNegotiatedTransportDescription(iter.second.get(), error_desc))
+ if (!ApplyNegotiatedTransportDescription_w(iter.second.get(), error_desc))
return false;
}
return true;
}
+void Transport::OnMessage(rtc::Message* msg) {
+ switch (msg->message_id) {
+ case MSG_ONSIGNALINGREADY:
+ CallChannels_w(&TransportChannelImpl::OnSignalingReady);
+ break;
+ case MSG_ONREMOTECANDIDATE: {
+ ChannelParams* params = static_cast<ChannelParams*>(msg->pdata);
+ OnRemoteCandidate_w(*params->candidate);
+ delete params;
+ }
+ break;
+ case MSG_CONNECTING:
+ OnConnecting_s();
+ break;
+ case MSG_READSTATE:
+ OnChannelReadableState_s();
+ break;
+ case MSG_WRITESTATE:
+ OnChannelWritableState_s();
+ break;
+ case MSG_RECEIVINGSTATE:
+ OnChannelReceivingState_s();
+ break;
+ case MSG_REQUESTSIGNALING:
+ OnChannelRequestSignaling_s();
+ break;
+ case MSG_CANDIDATEREADY:
+ OnChannelCandidateReady_s();
+ break;
+ case MSG_ROUTECHANGE: {
+ ChannelParams* params = static_cast<ChannelParams*>(msg->pdata);
+ OnChannelRouteChange_s(params->channel, *params->candidate);
+ delete params;
+ }
+ break;
+ case MSG_CANDIDATEALLOCATIONCOMPLETE:
+ OnChannelCandidatesAllocationDone_s();
+ break;
+ case MSG_ROLECONFLICT:
+ SignalRoleConflict();
+ break;
+ case MSG_COMPLETED:
+ SignalCompleted(this);
+ break;
+ case MSG_FAILED:
+ SignalFailed(this);
+ break;
+ }
+}
+
} // namespace cricket
diff --git a/webrtc/p2p/base/transport.h b/webrtc/p2p/base/transport.h
index b401c26..5539655 100644
--- a/webrtc/p2p/base/transport.h
+++ b/webrtc/p2p/base/transport.h
@@ -15,11 +15,15 @@
// state changes (in order to update the manager's state), and forwards
// requests to begin connecting or to reset to each of the channels.
//
-// On Threading: Transport performs work solely on the worker thread, and so
-// its methods should only be called on the worker thread.
+// On Threading: Transport performs work on both the signaling and worker
+// threads. For subclasses, the rule is that all signaling related calls will
+// be made on the signaling thread and all channel related calls (including
+// signaling for a channel) will be made on the worker thread. When
+// information needs to be sent between the two threads, this class should do
+// the work (e.g., OnRemoteCandidate).
//
-// Note: Subclasses must call DestroyChannels() in their own destructors.
-// It is not possible to do so here because the subclass destructor will
+// Note: Subclasses must call DestroyChannels() in their own constructors.
+// It is not possible to do so here because the subclass constructor will
// already have run.
#ifndef WEBRTC_P2P_BASE_TRANSPORT_H_
@@ -32,11 +36,16 @@
#include "webrtc/p2p/base/constants.h"
#include "webrtc/p2p/base/sessiondescription.h"
#include "webrtc/p2p/base/transportinfo.h"
+#include "webrtc/base/criticalsection.h"
#include "webrtc/base/messagequeue.h"
#include "webrtc/base/rtccertificate.h"
#include "webrtc/base/sigslot.h"
#include "webrtc/base/sslstreamadapter.h"
+namespace rtc {
+class Thread;
+}
+
namespace cricket {
class PortAllocator;
@@ -45,26 +54,6 @@
typedef std::vector<Candidate> Candidates;
-// TODO(deadbeef): Unify with PeerConnectionInterface::IceConnectionState
-// once /talk/ and /webrtc/ are combined, and also switch to ENUM_NAME naming
-// style.
-enum IceConnectionState {
- kIceConnectionConnecting = 0,
- kIceConnectionFailed,
- kIceConnectionConnected, // Writable, but still checking one or more
- // connections
- kIceConnectionCompleted,
-};
-
-// TODO(deadbeef): Unify with PeerConnectionInterface::IceConnectionState
-// once /talk/ and /webrtc/ are combined, and also switch to ENUM_NAME naming
-// style.
-enum IceGatheringState {
- kIceGatheringNew = 0,
- kIceGatheringGathering,
- kIceGatheringComplete,
-};
-
// For "writable", "readable", and "receiving", we need to differentiate between
// none, all, and some.
enum TransportState {
@@ -136,7 +125,7 @@
// Information about the stats of a transport.
struct TransportStats {
- std::string transport_name;
+ std::string content_name;
TransportChannelStatsList channel_stats;
};
@@ -147,13 +136,22 @@
const std::string& new_ufrag,
const std::string& new_pwd);
-class Transport : public sigslot::has_slots<> {
+class Transport : public rtc::MessageHandler,
+ public sigslot::has_slots<> {
public:
- Transport(const std::string& name, PortAllocator* allocator);
+ Transport(rtc::Thread* signaling_thread,
+ rtc::Thread* worker_thread,
+ const std::string& content_name,
+ PortAllocator* allocator);
virtual ~Transport();
- // Returns the name of this transport.
- const std::string& name() const { return name_; }
+ // Returns the signaling thread. The app talks to Transport on this thread.
+ rtc::Thread* signaling_thread() const { return signaling_thread_; }
+ // Returns the worker thread. The actual networking is done on this thread.
+ rtc::Thread* worker_thread() const { return worker_thread_; }
+
+ // Returns the content_name of this transport.
+ const std::string& content_name() const { return content_name_; }
// Returns the port allocator object for this transport.
PortAllocator* port_allocator() { return allocator_; }
@@ -184,14 +182,6 @@
return (receiving_ == TRANSPORT_STATE_SOME ||
receiving_ == TRANSPORT_STATE_ALL);
}
- bool ready_for_remote_candidates() const {
- return local_description_set_ && remote_description_set_;
- }
-
- bool AllChannelsCompleted() const;
- bool AnyChannelFailed() const;
-
- IceGatheringState gathering_state() const { return gathering_state_; }
sigslot::signal1<Transport*> SignalReadableState;
sigslot::signal1<Transport*> SignalWritableState;
@@ -211,23 +201,21 @@
void SetChannelReceivingTimeout(int timeout_ms);
// Must be called before applying local session description.
- virtual void SetLocalCertificate(
- const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) {}
+ void SetCertificate(
+ const rtc::scoped_refptr<rtc::RTCCertificate>& certificate);
- // Get a copy of the local certificate provided by SetLocalCertificate.
- virtual bool GetLocalCertificate(
- rtc::scoped_refptr<rtc::RTCCertificate>* certificate) {
- return false;
- }
+ // Get a copy of the local identity provided by SetIdentity.
+ bool GetCertificate(rtc::scoped_refptr<rtc::RTCCertificate>* certificate);
// Get a copy of the remote certificate in use by the specified channel.
bool GetRemoteSSLCertificate(rtc::SSLCertificate** cert);
// Create, destroy, and lookup the channels of this type by their components.
TransportChannelImpl* CreateChannel(int component);
-
+ // Note: GetChannel may lead to race conditions, since the mutex is not held
+ // after the pointer is returned.
TransportChannelImpl* GetChannel(int component);
-
+ // Note: HasChannel does not lead to race conditions, unlike GetChannel.
bool HasChannel(int component) {
return (NULL != GetChannel(component));
}
@@ -235,7 +223,7 @@
void DestroyChannel(int component);
// Set the local TransportDescription to be used by TransportChannels.
- // This calls ConnectChannels internally, kicking off candidate gathering.
+ // This should be called before ConnectChannels().
bool SetLocalTransportDescription(const TransportDescription& description,
ContentAction action,
std::string* error_desc);
@@ -259,15 +247,20 @@
bool GetStats(TransportStats* stats);
- sigslot::signal1<Transport*> SignalGatheringState;
+ // Before any stanza is sent, the manager will request signaling. Once
+ // signaling is available, the client should call OnSignalingReady. Once
+ // this occurs, the transport (or its channels) can send any waiting stanzas.
+ // OnSignalingReady invokes OnTransportSignalingReady and then forwards this
+ // signal to each channel.
+ sigslot::signal1<Transport*> SignalRequestSignaling;
+ void OnSignalingReady();
// Handles sending of ready candidates and receiving of remote candidates.
- sigslot::signal2<Transport*, const std::vector<Candidate>&>
- SignalCandidatesGathered;
+ sigslot::signal2<Transport*,
+ const std::vector<Candidate>&> SignalCandidatesReady;
- // Called when one or more candidates are ready from the remote peer.
- bool AddRemoteCandidates(const std::vector<Candidate>& candidates,
- std::string* error);
+ sigslot::signal1<Transport*> SignalCandidatesAllocationDone;
+ void OnRemoteCandidates(const std::vector<Candidate>& candidates);
// If candidate is not acceptable, returns false and sets error.
// Call this before calling OnRemoteCandidates.
@@ -282,12 +275,10 @@
// Forwards the signal from TransportChannel to BaseSession.
sigslot::signal0<> SignalRoleConflict;
- virtual bool GetSslRole(rtc::SSLRole* ssl_role) const { return false; }
+ virtual bool GetSslRole(rtc::SSLRole* ssl_role) const;
// Must be called before channel is starting to connect.
- virtual bool SetSslMaxProtocolVersion(rtc::SSLProtocolVersion version) {
- return false;
- }
+ virtual bool SetSslMaxProtocolVersion(rtc::SSLProtocolVersion version);
protected:
// These are called by Create/DestroyChannel above in order to create or
@@ -295,6 +286,9 @@
virtual TransportChannelImpl* CreateTransportChannel(int component) = 0;
virtual void DestroyTransportChannel(TransportChannelImpl* channel) = 0;
+ // Informs the subclass that we received the signaling ready message.
+ virtual void OnTransportSignalingReady() {}
+
// The current local transport description, for use by derived classes
// when performing transport description negotiation.
const TransportDescription* local_description() const {
@@ -307,37 +301,53 @@
return remote_description_.get();
}
+ virtual void SetCertificate_w(
+ const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) {}
+
+ virtual bool GetCertificate_w(
+ rtc::scoped_refptr<rtc::RTCCertificate>* certificate) {
+ return false;
+ }
+
// Pushes down the transport parameters from the local description, such
// as the ICE ufrag and pwd.
// Derived classes can override, but must call the base as well.
- virtual bool ApplyLocalTransportDescription(TransportChannelImpl* channel,
- std::string* error_desc);
+ virtual bool ApplyLocalTransportDescription_w(TransportChannelImpl* channel,
+ std::string* error_desc);
// Pushes down remote ice credentials from the remote description to the
// transport channel.
- virtual bool ApplyRemoteTransportDescription(TransportChannelImpl* ch,
- std::string* error_desc);
+ virtual bool ApplyRemoteTransportDescription_w(TransportChannelImpl* ch,
+ std::string* error_desc);
// Negotiates the transport parameters based on the current local and remote
// transport description, such as the ICE role to use, and whether DTLS
// should be activated.
// Derived classes can negotiate their specific parameters here, but must call
// the base as well.
- virtual bool NegotiateTransportDescription(ContentAction local_role,
- std::string* error_desc);
+ virtual bool NegotiateTransportDescription_w(ContentAction local_role,
+ std::string* error_desc);
// Pushes down the transport parameters obtained via negotiation.
// Derived classes can set their specific parameters here, but must call the
// base as well.
- virtual bool ApplyNegotiatedTransportDescription(
- TransportChannelImpl* channel,
- std::string* error_desc);
+ virtual bool ApplyNegotiatedTransportDescription_w(
+ TransportChannelImpl* channel, std::string* error_desc);
+
+ virtual bool GetSslRole_w(rtc::SSLRole* ssl_role) const {
+ return false;
+ }
+
+ virtual bool SetSslMaxProtocolVersion_w(rtc::SSLProtocolVersion version) {
+ return false;
+ }
private:
struct ChannelMapEntry {
- ChannelMapEntry() : impl_(NULL), ref_(0) {}
+ ChannelMapEntry() : impl_(NULL), candidates_allocated_(false), ref_(0) {}
explicit ChannelMapEntry(TransportChannelImpl *impl)
: impl_(impl),
+ candidates_allocated_(false),
ref_(0) {
}
@@ -350,9 +360,14 @@
TransportChannelImpl* get() const { return impl_; }
TransportChannelImpl* operator->() const { return impl_; }
+ void set_candidates_allocated(bool status) {
+ candidates_allocated_ = status;
+ }
+ bool candidates_allocated() const { return candidates_allocated_; }
- private:
- TransportChannelImpl* impl_;
+ private:
+ TransportChannelImpl *impl_;
+ bool candidates_allocated_;
int ref_;
};
@@ -366,59 +381,93 @@
// Called when the receiving state of a channel changes.
void OnChannelReceivingState(TransportChannel* channel);
- // Called when a channel starts finishes gathering candidates
- void OnChannelGatheringState(TransportChannelImpl* channel);
+ // Called when a channel requests signaling.
+ void OnChannelRequestSignaling(TransportChannelImpl* channel);
+ // Called when a candidate is ready from remote peer.
+ void OnRemoteCandidate(const Candidate& candidate);
// Called when a candidate is ready from channel.
- void OnChannelCandidateGathered(TransportChannelImpl* channel,
- const Candidate& candidate);
+ void OnChannelCandidateReady(TransportChannelImpl* channel,
+ const Candidate& candidate);
void OnChannelRouteChange(TransportChannel* channel,
const Candidate& remote_candidate);
+ void OnChannelCandidatesAllocationDone(TransportChannelImpl* channel);
// Called when there is ICE role change.
void OnRoleConflict(TransportChannelImpl* channel);
// Called when the channel removes a connection.
void OnChannelConnectionRemoved(TransportChannelImpl* channel);
+ // Dispatches messages to the appropriate handler (below).
+ void OnMessage(rtc::Message* msg);
+
+ // These are versions of the above methods that are called only on a
+ // particular thread (s = signaling, w = worker). The above methods post or
+ // send a message to invoke this version.
+ TransportChannelImpl* CreateChannel_w(int component);
+ void DestroyChannel_w(int component);
+ void ConnectChannels_w();
+ void ResetChannels_w();
+ void DestroyAllChannels_w();
+ void OnRemoteCandidate_w(const Candidate& candidate);
+ void OnChannelReadableState_s();
+ void OnChannelWritableState_s();
+ void OnChannelReceivingState_s();
+ void OnChannelRequestSignaling_s();
+ void OnConnecting_s();
+ void OnChannelRouteChange_s(const TransportChannel* channel,
+ const Candidate& remote_candidate);
+ void OnChannelCandidatesAllocationDone_s();
+
// Helper function that invokes the given function on every channel.
typedef void (TransportChannelImpl::* TransportChannelFunc)();
- void CallChannels(TransportChannelFunc func);
+ void CallChannels_w(TransportChannelFunc func);
// Computes the AND and OR of the channel's read/write/receiving state
// (argument picks the operation).
- TransportState GetTransportState(TransportStateType type);
+ TransportState GetTransportState_s(TransportStateType type);
+
+ void OnChannelCandidateReady_s();
+
+ void SetIceRole_w(IceRole role);
+ void SetRemoteIceMode_w(IceMode mode);
+ bool SetLocalTransportDescription_w(const TransportDescription& desc,
+ ContentAction action,
+ std::string* error_desc);
+ bool SetRemoteTransportDescription_w(const TransportDescription& desc,
+ ContentAction action,
+ std::string* error_desc);
+ bool GetStats_w(TransportStats* infos);
+ bool GetRemoteSSLCertificate_w(rtc::SSLCertificate** cert);
+
+ void SetChannelReceivingTimeout_w(int timeout_ms);
// Sends SignalCompleted if we are now in that state.
- void MaybeSignalCompleted();
+ void MaybeCompleted_w();
- // Sends SignalGatheringState if gathering state changed
- void UpdateGatheringState();
-
- void UpdateReadableState();
- void UpdateWritableState();
- void UpdateReceivingState();
-
- const std::string name_;
+ rtc::Thread* const signaling_thread_;
+ rtc::Thread* const worker_thread_;
+ const std::string content_name_;
PortAllocator* const allocator_;
- bool channels_destroyed_ = false;
- TransportState readable_ = TRANSPORT_STATE_NONE;
- TransportState writable_ = TRANSPORT_STATE_NONE;
- TransportState receiving_ = TRANSPORT_STATE_NONE;
- bool was_writable_ = false;
- bool connect_requested_ = false;
- IceRole ice_role_ = ICEROLE_UNKNOWN;
- uint64 tiebreaker_ = 0;
- IceMode remote_ice_mode_ = ICEMODE_FULL;
- int channel_receiving_timeout_ = -1;
+ bool destroyed_;
+ TransportState readable_;
+ TransportState writable_;
+ TransportState receiving_;
+ bool was_writable_;
+ bool connect_requested_;
+ IceRole ice_role_;
+ uint64 tiebreaker_;
+ IceMode remote_ice_mode_;
+ int channel_receiving_timeout_;
rtc::scoped_ptr<TransportDescription> local_description_;
rtc::scoped_ptr<TransportDescription> remote_description_;
- bool local_description_set_ = false;
- bool remote_description_set_ = false;
- IceGatheringState gathering_state_ = kIceGatheringNew;
+ // TODO(tommi): Make sure we only use this on the worker thread.
ChannelMap channels_;
// Buffers the ready_candidates so that SignalCanidatesReady can
// provide them in multiples.
std::vector<Candidate> ready_candidates_;
+ // Protects changes to channels and messages
+ rtc::CriticalSection crit_;
RTC_DISALLOW_COPY_AND_ASSIGN(Transport);
};
diff --git a/webrtc/p2p/base/transport_unittest.cc b/webrtc/p2p/base/transport_unittest.cc
index 9febfe3..43b761a 100644
--- a/webrtc/p2p/base/transport_unittest.cc
+++ b/webrtc/p2p/base/transport_unittest.cc
@@ -11,7 +11,8 @@
#include "webrtc/base/fakesslidentity.h"
#include "webrtc/base/gunit.h"
#include "webrtc/base/network.h"
-#include "webrtc/p2p/base/faketransportcontroller.h"
+#include "webrtc/base/thread.h"
+#include "webrtc/p2p/base/fakesession.h"
#include "webrtc/p2p/base/p2ptransport.h"
using cricket::Candidate;
@@ -34,7 +35,9 @@
public sigslot::has_slots<> {
public:
TransportTest()
- : transport_(new FakeTransport("test content name")),
+ : thread_(rtc::Thread::Current()),
+ transport_(new FakeTransport(
+ thread_, thread_, "test content name", NULL)),
channel_(NULL),
connecting_signalled_(false),
completed_(false),
@@ -70,6 +73,7 @@
failed_ = true;
}
+ rtc::Thread* thread_;
rtc::scoped_ptr<FakeTransport> transport_;
FakeTransportChannel* channel_;
bool connecting_signalled_;
@@ -81,7 +85,20 @@
TEST_F(TransportTest, TestConnectChannelsDoesSignal) {
EXPECT_TRUE(SetupChannel());
transport_->ConnectChannels();
- EXPECT_TRUE(connecting_signalled_);
+ EXPECT_FALSE(connecting_signalled_);
+
+ EXPECT_TRUE_WAIT(connecting_signalled_, 100);
+}
+
+// Test that DestroyAllChannels kills any pending OnConnecting signals.
+TEST_F(TransportTest, TestDestroyAllClearsPosts) {
+ EXPECT_TRUE(transport_->CreateChannel(1) != NULL);
+
+ transport_->ConnectChannels();
+ transport_->DestroyAllChannels();
+
+ thread_->ProcessMessages(0);
+ EXPECT_FALSE(connecting_signalled_);
}
// This test verifies channels are created with proper ICE
@@ -215,7 +232,7 @@
NULL));
channel_->SetConnectionCount(2);
- channel_->SetCandidatesGatheringComplete();
+ channel_->SignalCandidatesAllocationDone(channel_);
channel_->SetWritable(true);
EXPECT_TRUE_WAIT(transport_->all_channels_writable(), 100);
// ICE is not yet completed because there is still more than one connection.
diff --git a/webrtc/p2p/base/transportchannel.cc b/webrtc/p2p/base/transportchannel.cc
index 9ab7641..5fb0eb4 100644
--- a/webrtc/p2p/base/transportchannel.cc
+++ b/webrtc/p2p/base/transportchannel.cc
@@ -18,8 +18,9 @@
const char READABLE_ABBREV[2] = { '_', 'R' };
const char WRITABLE_ABBREV[2] = { '_', 'W' };
std::stringstream ss;
- ss << "Channel[" << transport_name_ << "|" << component_ << "|"
- << READABLE_ABBREV[readable_] << WRITABLE_ABBREV[writable_] << "]";
+ ss << "Channel[" << content_name_
+ << "|" << component_
+ << "|" << READABLE_ABBREV[readable_] << WRITABLE_ABBREV[writable_] << "]";
return ss.str();
}
diff --git a/webrtc/p2p/base/transportchannel.h b/webrtc/p2p/base/transportchannel.h
index 5b13e68..f492e4e 100644
--- a/webrtc/p2p/base/transportchannel.h
+++ b/webrtc/p2p/base/transportchannel.h
@@ -37,23 +37,16 @@
};
// Used to indicate channel's connection state.
-enum TransportChannelState {
- STATE_INIT,
- STATE_CONNECTING, // Will enter this state once a connection is created
- STATE_COMPLETED,
- STATE_FAILED
-};
+enum TransportChannelState { STATE_CONNECTING, STATE_COMPLETED, STATE_FAILED };
// A TransportChannel represents one logical stream of packets that are sent
// between the two sides of a session.
class TransportChannel : public sigslot::has_slots<> {
public:
- explicit TransportChannel(const std::string& transport_name, int component)
- : transport_name_(transport_name),
+ explicit TransportChannel(const std::string& content_name, int component)
+ : content_name_(content_name),
component_(component),
- readable_(false),
- writable_(false),
- receiving_(false) {}
+ readable_(false), writable_(false), receiving_(false) {}
virtual ~TransportChannel() {}
// TODO(guoweis) - Make this pure virtual once all subclasses of
@@ -66,7 +59,7 @@
// Returns the session id of this channel.
virtual const std::string SessionId() const { return std::string(); }
- const std::string& transport_name() const { return transport_name_; }
+ const std::string& content_name() const { return content_name_; }
int component() const { return component_; }
// Returns the readable and states of this channel. Each time one of these
@@ -155,9 +148,10 @@
// Sets the receiving state, signaling if necessary.
void set_receiving(bool receiving);
+
private:
// Used mostly for debugging.
- std::string transport_name_;
+ std::string content_name_;
int component_;
bool readable_;
bool writable_;
diff --git a/webrtc/p2p/base/transportchannelimpl.h b/webrtc/p2p/base/transportchannelimpl.h
index d9c267f..3aca951 100644
--- a/webrtc/p2p/base/transportchannelimpl.h
+++ b/webrtc/p2p/base/transportchannelimpl.h
@@ -32,9 +32,8 @@
// client.
class TransportChannelImpl : public TransportChannel {
public:
- explicit TransportChannelImpl(const std::string& transport_name,
- int component)
- : TransportChannel(transport_name, component) {}
+ explicit TransportChannelImpl(const std::string& content_name, int component)
+ : TransportChannel(content_name, component) {}
// Returns the transport that created this channel.
virtual Transport* GetTransport() = 0;
@@ -62,10 +61,13 @@
virtual void SetReceivingTimeout(int timeout_ms) = 0;
// Begins the process of attempting to make a connection to the other client.
- // This includes starting to gather candidates.
virtual void Connect() = 0;
- sigslot::signal1<TransportChannelImpl*> SignalGatheringState;
+ // Allows an individual channel to request signaling and be notified when it
+ // is ready. This is useful if the individual named channels have need to
+ // send their own transport-info stanzas.
+ sigslot::signal1<TransportChannelImpl*> SignalRequestSignaling;
+ virtual void OnSignalingReady() = 0;
// Handles sending and receiving of candidates. The Transport
// receives the candidates and may forward them to the relevant
@@ -75,11 +77,9 @@
// channel, they cannot return an error if the message is invalid.
// It is assumed that the Transport will have checked validity
// before forwarding.
- sigslot::signal2<TransportChannelImpl*, const Candidate&>
- SignalCandidateGathered;
- virtual void AddRemoteCandidate(const Candidate& candidate) = 0;
-
- virtual IceGatheringState gathering_state() const = 0;
+ sigslot::signal2<TransportChannelImpl*,
+ const Candidate&> SignalCandidateReady;
+ virtual void OnCandidate(const Candidate& candidate) = 0;
// DTLS methods
virtual bool SetLocalCertificate(
@@ -92,6 +92,9 @@
virtual bool SetSslRole(rtc::SSLRole role) = 0;
+ // TransportChannel is forwarding this signal from PortAllocatorSession.
+ sigslot::signal1<TransportChannelImpl*> SignalCandidatesAllocationDone;
+
// Invoked when there is conflict in the ICE role between local and remote
// agents.
sigslot::signal1<TransportChannelImpl*> SignalRoleConflict;
diff --git a/webrtc/p2p/base/transportchannelproxy.cc b/webrtc/p2p/base/transportchannelproxy.cc
new file mode 100644
index 0000000..f7946dd
--- /dev/null
+++ b/webrtc/p2p/base/transportchannelproxy.cc
@@ -0,0 +1,276 @@
+/*
+ * Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/p2p/base/transport.h"
+#include "webrtc/p2p/base/transportchannelimpl.h"
+#include "webrtc/p2p/base/transportchannelproxy.h"
+#include "webrtc/base/common.h"
+#include "webrtc/base/logging.h"
+#include "webrtc/base/thread.h"
+
+namespace cricket {
+
+enum {
+ MSG_UPDATESTATE,
+};
+
+TransportChannelProxy::TransportChannelProxy(const std::string& content_name,
+ int component)
+ : TransportChannel(content_name, component),
+ impl_(NULL) {
+ worker_thread_ = rtc::Thread::Current();
+}
+
+TransportChannelProxy::~TransportChannelProxy() {
+ // Clearing any pending signal.
+ worker_thread_->Clear(this);
+ if (impl_) {
+ impl_->GetTransport()->DestroyChannel(impl_->component());
+ }
+}
+
+void TransportChannelProxy::SetImplementation(TransportChannelImpl* impl) {
+ ASSERT(rtc::Thread::Current() == worker_thread_);
+
+ if (impl == impl_) {
+ // Ignore if the |impl| has already been set.
+ LOG(LS_WARNING) << "Ignored TransportChannelProxy::SetImplementation call "
+ << "with a same impl as the existing one.";
+ return;
+ }
+
+ // Destroy any existing impl_.
+ if (impl_) {
+ impl_->GetTransport()->DestroyChannel(impl_->component());
+ }
+
+ // Adopt the supplied impl, and connect to its signals.
+ impl_ = impl;
+
+ if (impl_) {
+ impl_->SignalReadableState.connect(
+ this, &TransportChannelProxy::OnReadableState);
+ impl_->SignalWritableState.connect(
+ this, &TransportChannelProxy::OnWritableState);
+ impl_->SignalReadPacket.connect(
+ this, &TransportChannelProxy::OnReadPacket);
+ impl_->SignalReadyToSend.connect(
+ this, &TransportChannelProxy::OnReadyToSend);
+ impl_->SignalRouteChange.connect(
+ this, &TransportChannelProxy::OnRouteChange);
+ for (const auto& pair : options_) {
+ impl_->SetOption(pair.first, pair.second);
+ }
+
+ // Push down the SRTP ciphers, if any were set.
+ if (!pending_srtp_ciphers_.empty()) {
+ impl_->SetSrtpCiphers(pending_srtp_ciphers_);
+ }
+ }
+
+ // Post ourselves a message to see if we need to fire state callbacks.
+ worker_thread_->Post(this, MSG_UPDATESTATE);
+}
+
+int TransportChannelProxy::SendPacket(const char* data, size_t len,
+ const rtc::PacketOptions& options,
+ int flags) {
+ ASSERT(rtc::Thread::Current() == worker_thread_);
+ // Fail if we don't have an impl yet.
+ if (!impl_) {
+ return -1;
+ }
+ return impl_->SendPacket(data, len, options, flags);
+}
+
+int TransportChannelProxy::SetOption(rtc::Socket::Option opt, int value) {
+ ASSERT(rtc::Thread::Current() == worker_thread_);
+ options_.push_back(OptionPair(opt, value));
+ if (!impl_) {
+ return 0;
+ }
+ return impl_->SetOption(opt, value);
+}
+
+bool TransportChannelProxy::GetOption(rtc::Socket::Option opt, int* value) {
+ ASSERT(rtc::Thread::Current() == worker_thread_);
+ if (impl_) {
+ return impl_->GetOption(opt, value);
+ }
+
+ for (const auto& pair : options_) {
+ if (pair.first == opt) {
+ *value = pair.second;
+ return true;
+ }
+ }
+ return false;
+}
+
+int TransportChannelProxy::GetError() {
+ ASSERT(rtc::Thread::Current() == worker_thread_);
+ if (!impl_) {
+ return 0;
+ }
+ return impl_->GetError();
+}
+
+TransportChannelState TransportChannelProxy::GetState() const {
+ ASSERT(rtc::Thread::Current() == worker_thread_);
+ if (!impl_) {
+ return TransportChannelState::STATE_CONNECTING;
+ }
+ return impl_->GetState();
+}
+
+bool TransportChannelProxy::GetStats(ConnectionInfos* infos) {
+ ASSERT(rtc::Thread::Current() == worker_thread_);
+ if (!impl_) {
+ return false;
+ }
+ return impl_->GetStats(infos);
+}
+
+bool TransportChannelProxy::IsDtlsActive() const {
+ ASSERT(rtc::Thread::Current() == worker_thread_);
+ if (!impl_) {
+ return false;
+ }
+ return impl_->IsDtlsActive();
+}
+
+bool TransportChannelProxy::GetSslRole(rtc::SSLRole* role) const {
+ ASSERT(rtc::Thread::Current() == worker_thread_);
+ if (!impl_) {
+ return false;
+ }
+ return impl_->GetSslRole(role);
+}
+
+bool TransportChannelProxy::SetSslRole(rtc::SSLRole role) {
+ ASSERT(rtc::Thread::Current() == worker_thread_);
+ if (!impl_) {
+ return false;
+ }
+ return impl_->SetSslRole(role);
+}
+
+bool TransportChannelProxy::SetSrtpCiphers(const std::vector<std::string>&
+ ciphers) {
+ ASSERT(rtc::Thread::Current() == worker_thread_);
+ pending_srtp_ciphers_ = ciphers; // Cache so we can send later, but always
+ // set so it stays consistent.
+ if (impl_) {
+ return impl_->SetSrtpCiphers(ciphers);
+ }
+ return true;
+}
+
+bool TransportChannelProxy::GetSrtpCipher(std::string* cipher) {
+ ASSERT(rtc::Thread::Current() == worker_thread_);
+ if (!impl_) {
+ return false;
+ }
+ return impl_->GetSrtpCipher(cipher);
+}
+
+bool TransportChannelProxy::GetSslCipher(std::string* cipher) {
+ ASSERT(rtc::Thread::Current() == worker_thread_);
+ if (!impl_) {
+ return false;
+ }
+ return impl_->GetSslCipher(cipher);
+}
+
+rtc::scoped_refptr<rtc::RTCCertificate>
+TransportChannelProxy::GetLocalCertificate() const {
+ ASSERT(rtc::Thread::Current() == worker_thread_);
+ if (!impl_) {
+ return nullptr;
+ }
+ return impl_->GetLocalCertificate();
+}
+
+bool TransportChannelProxy::GetRemoteSSLCertificate(
+ rtc::SSLCertificate** cert) const {
+ ASSERT(rtc::Thread::Current() == worker_thread_);
+ if (!impl_) {
+ return false;
+ }
+ return impl_->GetRemoteSSLCertificate(cert);
+}
+
+bool TransportChannelProxy::ExportKeyingMaterial(const std::string& label,
+ const uint8* context,
+ size_t context_len,
+ bool use_context,
+ uint8* result,
+ size_t result_len) {
+ ASSERT(rtc::Thread::Current() == worker_thread_);
+ if (!impl_) {
+ return false;
+ }
+ return impl_->ExportKeyingMaterial(label, context, context_len, use_context,
+ result, result_len);
+}
+
+IceRole TransportChannelProxy::GetIceRole() const {
+ ASSERT(rtc::Thread::Current() == worker_thread_);
+ if (!impl_) {
+ return ICEROLE_UNKNOWN;
+ }
+ return impl_->GetIceRole();
+}
+
+void TransportChannelProxy::OnReadableState(TransportChannel* channel) {
+ ASSERT(rtc::Thread::Current() == worker_thread_);
+ ASSERT(channel == impl_);
+ set_readable(impl_->readable());
+ // Note: SignalReadableState fired by set_readable.
+}
+
+void TransportChannelProxy::OnWritableState(TransportChannel* channel) {
+ ASSERT(rtc::Thread::Current() == worker_thread_);
+ ASSERT(channel == impl_);
+ set_writable(impl_->writable());
+ // Note: SignalWritableState fired by set_readable.
+}
+
+void TransportChannelProxy::OnReadPacket(
+ TransportChannel* channel, const char* data, size_t size,
+ const rtc::PacketTime& packet_time, int flags) {
+ ASSERT(rtc::Thread::Current() == worker_thread_);
+ ASSERT(channel == impl_);
+ SignalReadPacket(this, data, size, packet_time, flags);
+}
+
+void TransportChannelProxy::OnReadyToSend(TransportChannel* channel) {
+ ASSERT(rtc::Thread::Current() == worker_thread_);
+ ASSERT(channel == impl_);
+ SignalReadyToSend(this);
+}
+
+void TransportChannelProxy::OnRouteChange(TransportChannel* channel,
+ const Candidate& candidate) {
+ ASSERT(rtc::Thread::Current() == worker_thread_);
+ ASSERT(channel == impl_);
+ SignalRouteChange(this, candidate);
+}
+
+void TransportChannelProxy::OnMessage(rtc::Message* msg) {
+ ASSERT(rtc::Thread::Current() == worker_thread_);
+ if (msg->message_id == MSG_UPDATESTATE) {
+ // If impl_ is already readable or writable, push up those signals.
+ set_readable(impl_ ? impl_->readable() : false);
+ set_writable(impl_ ? impl_->writable() : false);
+ }
+}
+
+} // namespace cricket
diff --git a/webrtc/p2p/base/transportchannelproxy.h b/webrtc/p2p/base/transportchannelproxy.h
new file mode 100644
index 0000000..f10f507
--- /dev/null
+++ b/webrtc/p2p/base/transportchannelproxy.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_P2P_BASE_TRANSPORTCHANNELPROXY_H_
+#define WEBRTC_P2P_BASE_TRANSPORTCHANNELPROXY_H_
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "webrtc/p2p/base/transportchannel.h"
+#include "webrtc/base/messagehandler.h"
+
+namespace rtc {
+class Thread;
+}
+
+namespace cricket {
+
+class TransportChannelImpl;
+
+// Proxies calls between the client and the transport channel implementation.
+// This is needed because clients are allowed to create channels before the
+// network negotiation is complete. Hence, we create a proxy up front, and
+// when negotiation completes, connect the proxy to the implementaiton.
+class TransportChannelProxy : public TransportChannel,
+ public rtc::MessageHandler {
+ public:
+ TransportChannelProxy(const std::string& content_name,
+ int component);
+ ~TransportChannelProxy() override;
+
+ TransportChannelImpl* impl() { return impl_; }
+
+ TransportChannelState GetState() const override;
+
+ // Sets the implementation to which we will proxy.
+ void SetImplementation(TransportChannelImpl* impl);
+
+ // Implementation of the TransportChannel interface. These simply forward to
+ // the implementation.
+ int SendPacket(const char* data, size_t len,
+ const rtc::PacketOptions& options,
+ int flags) override;
+ int SetOption(rtc::Socket::Option opt, int value) override;
+ bool GetOption(rtc::Socket::Option opt, int* value) override;
+ int GetError() override;
+ virtual IceRole GetIceRole() const;
+ bool GetStats(ConnectionInfos* infos) override;
+ bool IsDtlsActive() const override;
+ bool GetSslRole(rtc::SSLRole* role) const override;
+ virtual bool SetSslRole(rtc::SSLRole role);
+ bool SetSrtpCiphers(const std::vector<std::string>& ciphers) override;
+ bool GetSrtpCipher(std::string* cipher) override;
+ bool GetSslCipher(std::string* cipher) override;
+ rtc::scoped_refptr<rtc::RTCCertificate> GetLocalCertificate() const override;
+ bool GetRemoteSSLCertificate(rtc::SSLCertificate** cert) const override;
+ bool ExportKeyingMaterial(const std::string& label,
+ const uint8* context,
+ size_t context_len,
+ bool use_context,
+ uint8* result,
+ size_t result_len) override;
+
+ private:
+ // Catch signals from the implementation channel. These just forward to the
+ // client (after updating our state to match).
+ void OnReadableState(TransportChannel* channel);
+ void OnWritableState(TransportChannel* channel);
+ void OnReadPacket(TransportChannel* channel, const char* data, size_t size,
+ const rtc::PacketTime& packet_time, int flags);
+ void OnReadyToSend(TransportChannel* channel);
+ void OnRouteChange(TransportChannel* channel, const Candidate& candidate);
+
+ void OnMessage(rtc::Message* message) override;
+
+ typedef std::pair<rtc::Socket::Option, int> OptionPair;
+ typedef std::vector<OptionPair> OptionList;
+ rtc::Thread* worker_thread_;
+ TransportChannelImpl* impl_;
+ OptionList options_;
+ std::vector<std::string> pending_srtp_ciphers_;
+
+ RTC_DISALLOW_COPY_AND_ASSIGN(TransportChannelProxy);
+};
+
+} // namespace cricket
+
+#endif // WEBRTC_P2P_BASE_TRANSPORTCHANNELPROXY_H_
diff --git a/webrtc/p2p/base/transportcontroller.cc b/webrtc/p2p/base/transportcontroller.cc
deleted file mode 100644
index f78882d..0000000
--- a/webrtc/p2p/base/transportcontroller.cc
+++ /dev/null
@@ -1,564 +0,0 @@
-/*
- * Copyright 2015 The WebRTC Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "webrtc/p2p/base/transportcontroller.h"
-
-#include "webrtc/base/bind.h"
-#include "webrtc/base/checks.h"
-#include "webrtc/base/thread.h"
-#include "webrtc/p2p/base/dtlstransport.h"
-#include "webrtc/p2p/base/p2ptransport.h"
-
-namespace cricket {
-
-enum {
- MSG_ICECONNECTIONSTATE,
- MSG_RECEIVING,
- MSG_ICEGATHERINGSTATE,
- MSG_CANDIDATESGATHERED,
-};
-
-struct CandidatesData : public rtc::MessageData {
- CandidatesData(const std::string& transport_name,
- const Candidates& candidates)
- : transport_name(transport_name), candidates(candidates) {}
-
- std::string transport_name;
- Candidates candidates;
-};
-
-TransportController::TransportController(rtc::Thread* signaling_thread,
- rtc::Thread* worker_thread,
- PortAllocator* port_allocator)
- : signaling_thread_(signaling_thread),
- worker_thread_(worker_thread),
- port_allocator_(port_allocator) {}
-
-TransportController::~TransportController() {
- worker_thread_->Invoke<void>(
- rtc::Bind(&TransportController::DestroyAllTransports_w, this));
- signaling_thread_->Clear(this);
-}
-
-bool TransportController::SetSslMaxProtocolVersion(
- rtc::SSLProtocolVersion version) {
- return worker_thread_->Invoke<bool>(rtc::Bind(
- &TransportController::SetSslMaxProtocolVersion_w, this, version));
-}
-
-void TransportController::SetIceConnectionReceivingTimeout(int timeout_ms) {
- worker_thread_->Invoke<void>(
- rtc::Bind(&TransportController::SetIceConnectionReceivingTimeout_w, this,
- timeout_ms));
-}
-
-void TransportController::SetIceRole(IceRole ice_role) {
- worker_thread_->Invoke<void>(
- rtc::Bind(&TransportController::SetIceRole_w, this, ice_role));
-}
-
-bool TransportController::GetSslRole(rtc::SSLRole* role) {
- return worker_thread_->Invoke<bool>(
- rtc::Bind(&TransportController::GetSslRole_w, this, role));
-}
-
-bool TransportController::SetLocalCertificate(
- const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) {
- return worker_thread_->Invoke<bool>(rtc::Bind(
- &TransportController::SetLocalCertificate_w, this, certificate));
-}
-
-bool TransportController::GetLocalCertificate(
- const std::string& transport_name,
- rtc::scoped_refptr<rtc::RTCCertificate>* certificate) {
- return worker_thread_->Invoke<bool>(
- rtc::Bind(&TransportController::GetLocalCertificate_w, this,
- transport_name, certificate));
-}
-
-bool TransportController::GetRemoteSSLCertificate(
- const std::string& transport_name,
- rtc::SSLCertificate** cert) {
- return worker_thread_->Invoke<bool>(
- rtc::Bind(&TransportController::GetRemoteSSLCertificate_w, this,
- transport_name, cert));
-}
-
-bool TransportController::SetLocalTransportDescription(
- const std::string& transport_name,
- const TransportDescription& tdesc,
- ContentAction action,
- std::string* err) {
- return worker_thread_->Invoke<bool>(
- rtc::Bind(&TransportController::SetLocalTransportDescription_w, this,
- transport_name, tdesc, action, err));
-}
-
-bool TransportController::SetRemoteTransportDescription(
- const std::string& transport_name,
- const TransportDescription& tdesc,
- ContentAction action,
- std::string* err) {
- return worker_thread_->Invoke<bool>(
- rtc::Bind(&TransportController::SetRemoteTransportDescription_w, this,
- transport_name, tdesc, action, err));
-}
-
-bool TransportController::AddRemoteCandidates(const std::string& transport_name,
- const Candidates& candidates,
- std::string* err) {
- return worker_thread_->Invoke<bool>(
- rtc::Bind(&TransportController::AddRemoteCandidates_w, this,
- transport_name, candidates, err));
-}
-
-bool TransportController::ReadyForRemoteCandidates(
- const std::string& transport_name) {
- return worker_thread_->Invoke<bool>(rtc::Bind(
- &TransportController::ReadyForRemoteCandidates_w, this, transport_name));
-}
-
-bool TransportController::GetStats(const std::string& transport_name,
- TransportStats* stats) {
- return worker_thread_->Invoke<bool>(
- rtc::Bind(&TransportController::GetStats_w, this, transport_name, stats));
-}
-
-TransportChannel* TransportController::CreateTransportChannel_w(
- const std::string& transport_name,
- int component) {
- RTC_DCHECK(worker_thread_->IsCurrent());
-
- Transport* transport = GetOrCreateTransport_w(transport_name);
- return transport->CreateChannel(component);
-}
-
-void TransportController::DestroyTransportChannel_w(
- const std::string& transport_name,
- int component) {
- RTC_DCHECK(worker_thread_->IsCurrent());
-
- Transport* transport = GetTransport_w(transport_name);
- if (!transport) {
- ASSERT(false);
- return;
- }
- transport->DestroyChannel(component);
-
- // Just as we create a Transport when its first channel is created,
- // we delete it when its last channel is deleted.
- if (!transport->HasChannels()) {
- DestroyTransport_w(transport_name);
- }
-}
-
-const rtc::scoped_refptr<rtc::RTCCertificate>&
-TransportController::certificate_for_testing() {
- return certificate_;
-}
-
-Transport* TransportController::CreateTransport_w(
- const std::string& transport_name) {
- RTC_DCHECK(worker_thread_->IsCurrent());
-
- Transport* transport = new DtlsTransport<P2PTransport>(
- transport_name, port_allocator(), certificate_);
- return transport;
-}
-
-Transport* TransportController::GetTransport_w(
- const std::string& transport_name) {
- RTC_DCHECK(worker_thread_->IsCurrent());
-
- auto iter = transports_.find(transport_name);
- return (iter != transports_.end()) ? iter->second : nullptr;
-}
-
-void TransportController::OnMessage(rtc::Message* pmsg) {
- RTC_DCHECK(signaling_thread_->IsCurrent());
-
- switch (pmsg->message_id) {
- case MSG_ICECONNECTIONSTATE: {
- rtc::TypedMessageData<IceConnectionState>* data =
- static_cast<rtc::TypedMessageData<IceConnectionState>*>(pmsg->pdata);
- SignalConnectionState(data->data());
- delete data;
- break;
- }
- case MSG_RECEIVING: {
- rtc::TypedMessageData<bool>* data =
- static_cast<rtc::TypedMessageData<bool>*>(pmsg->pdata);
- SignalReceiving(data->data());
- delete data;
- break;
- }
- case MSG_ICEGATHERINGSTATE: {
- rtc::TypedMessageData<IceGatheringState>* data =
- static_cast<rtc::TypedMessageData<IceGatheringState>*>(pmsg->pdata);
- SignalGatheringState(data->data());
- delete data;
- break;
- }
- case MSG_CANDIDATESGATHERED: {
- CandidatesData* data = static_cast<CandidatesData*>(pmsg->pdata);
- SignalCandidatesGathered(data->transport_name, data->candidates);
- delete data;
- break;
- }
- default:
- ASSERT(false);
- }
-}
-
-Transport* TransportController::GetOrCreateTransport_w(
- const std::string& transport_name) {
- RTC_DCHECK(worker_thread_->IsCurrent());
-
- Transport* transport = GetTransport_w(transport_name);
- if (transport) {
- return transport;
- }
-
- transport = CreateTransport_w(transport_name);
- // The stuff below happens outside of CreateTransport_w so that unit tests
- // can override CreateTransport_w to return a different type of transport.
- transport->SetSslMaxProtocolVersion(ssl_max_version_);
- transport->SetChannelReceivingTimeout(ice_receiving_timeout_ms_);
- transport->SetIceRole(ice_role_);
- transport->SetIceTiebreaker(ice_tiebreaker_);
- if (certificate_) {
- transport->SetLocalCertificate(certificate_);
- }
- transport->SignalConnecting.connect(
- this, &TransportController::OnTransportConnecting_w);
- transport->SignalWritableState.connect(
- this, &TransportController::OnTransportWritableState_w);
- transport->SignalReceivingState.connect(
- this, &TransportController::OnTransportReceivingState_w);
- transport->SignalCompleted.connect(
- this, &TransportController::OnTransportCompleted_w);
- transport->SignalFailed.connect(this,
- &TransportController::OnTransportFailed_w);
- transport->SignalGatheringState.connect(
- this, &TransportController::OnTransportGatheringState_w);
- transport->SignalCandidatesGathered.connect(
- this, &TransportController::OnTransportCandidatesGathered_w);
- transport->SignalRoleConflict.connect(
- this, &TransportController::OnTransportRoleConflict_w);
- transports_[transport_name] = transport;
-
- return transport;
-}
-
-void TransportController::DestroyTransport_w(
- const std::string& transport_name) {
- RTC_DCHECK(worker_thread_->IsCurrent());
-
- auto iter = transports_.find(transport_name);
- if (iter != transports_.end()) {
- delete iter->second;
- transports_.erase(transport_name);
- }
- // Destroying a transport may cause aggregate state to change.
- UpdateAggregateStates_w();
-}
-
-void TransportController::DestroyAllTransports_w() {
- RTC_DCHECK(worker_thread_->IsCurrent());
-
- for (const auto& kv : transports_) {
- delete kv.second;
- }
- transports_.clear();
-}
-
-bool TransportController::SetSslMaxProtocolVersion_w(
- rtc::SSLProtocolVersion version) {
- RTC_DCHECK(worker_thread_->IsCurrent());
-
- // Max SSL version can only be set before transports are created.
- if (!transports_.empty()) {
- return false;
- }
-
- ssl_max_version_ = version;
- return true;
-}
-
-void TransportController::SetIceConnectionReceivingTimeout_w(int timeout_ms) {
- RTC_DCHECK(worker_thread_->IsCurrent());
- ice_receiving_timeout_ms_ = timeout_ms;
- for (const auto& kv : transports_) {
- kv.second->SetChannelReceivingTimeout(timeout_ms);
- }
-}
-
-void TransportController::SetIceRole_w(IceRole ice_role) {
- RTC_DCHECK(worker_thread_->IsCurrent());
- ice_role_ = ice_role;
- for (const auto& kv : transports_) {
- kv.second->SetIceRole(ice_role_);
- }
-}
-
-bool TransportController::GetSslRole_w(rtc::SSLRole* role) {
- RTC_DCHECK(worker_thread()->IsCurrent());
-
- if (transports_.empty()) {
- return false;
- }
- return transports_.begin()->second->GetSslRole(role);
-}
-
-bool TransportController::SetLocalCertificate_w(
- const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) {
- RTC_DCHECK(worker_thread_->IsCurrent());
-
- if (certificate_) {
- return false;
- }
- if (!certificate) {
- return false;
- }
- certificate_ = certificate;
-
- for (const auto& kv : transports_) {
- kv.second->SetLocalCertificate(certificate_);
- }
- return true;
-}
-
-bool TransportController::GetLocalCertificate_w(
- const std::string& transport_name,
- rtc::scoped_refptr<rtc::RTCCertificate>* certificate) {
- RTC_DCHECK(worker_thread_->IsCurrent());
-
- Transport* t = GetTransport_w(transport_name);
- if (!t) {
- return false;
- }
-
- return t->GetLocalCertificate(certificate);
-}
-
-bool TransportController::GetRemoteSSLCertificate_w(
- const std::string& transport_name,
- rtc::SSLCertificate** cert) {
- RTC_DCHECK(worker_thread_->IsCurrent());
-
- Transport* t = GetTransport_w(transport_name);
- if (!t) {
- return false;
- }
-
- return t->GetRemoteSSLCertificate(cert);
-}
-
-bool TransportController::SetLocalTransportDescription_w(
- const std::string& transport_name,
- const TransportDescription& tdesc,
- ContentAction action,
- std::string* err) {
- RTC_DCHECK(worker_thread()->IsCurrent());
-
- Transport* transport = GetTransport_w(transport_name);
- if (!transport) {
- // If we didn't find a transport, that's not an error;
- // it could have been deleted as a result of bundling.
- // TODO(deadbeef): Make callers smarter so they won't attempt to set a
- // description on a deleted transport.
- return true;
- }
-
- return transport->SetLocalTransportDescription(tdesc, action, err);
-}
-
-bool TransportController::SetRemoteTransportDescription_w(
- const std::string& transport_name,
- const TransportDescription& tdesc,
- ContentAction action,
- std::string* err) {
- RTC_DCHECK(worker_thread()->IsCurrent());
-
- Transport* transport = GetTransport_w(transport_name);
- if (!transport) {
- // If we didn't find a transport, that's not an error;
- // it could have been deleted as a result of bundling.
- // TODO(deadbeef): Make callers smarter so they won't attempt to set a
- // description on a deleted transport.
- return true;
- }
-
- return transport->SetRemoteTransportDescription(tdesc, action, err);
-}
-
-bool TransportController::AddRemoteCandidates_w(
- const std::string& transport_name,
- const Candidates& candidates,
- std::string* err) {
- RTC_DCHECK(worker_thread()->IsCurrent());
-
- Transport* transport = GetTransport_w(transport_name);
- if (!transport) {
- // If we didn't find a transport, that's not an error;
- // it could have been deleted as a result of bundling.
- return true;
- }
-
- return transport->AddRemoteCandidates(candidates, err);
-}
-
-bool TransportController::ReadyForRemoteCandidates_w(
- const std::string& transport_name) {
- RTC_DCHECK(worker_thread()->IsCurrent());
-
- Transport* transport = GetTransport_w(transport_name);
- if (!transport) {
- return false;
- }
- return transport->ready_for_remote_candidates();
-}
-
-bool TransportController::GetStats_w(const std::string& transport_name,
- TransportStats* stats) {
- RTC_DCHECK(worker_thread()->IsCurrent());
-
- Transport* transport = GetTransport_w(transport_name);
- if (!transport) {
- return false;
- }
- return transport->GetStats(stats);
-}
-
-void TransportController::OnTransportConnecting_w(Transport* transport) {
- RTC_DCHECK(worker_thread_->IsCurrent());
- UpdateAggregateStates_w();
-}
-
-void TransportController::OnTransportWritableState_w(Transport* transport) {
- RTC_DCHECK(worker_thread_->IsCurrent());
- UpdateAggregateStates_w();
-}
-
-void TransportController::OnTransportReceivingState_w(Transport* transport) {
- RTC_DCHECK(worker_thread_->IsCurrent());
- UpdateAggregateStates_w();
-}
-
-void TransportController::OnTransportCompleted_w(Transport* transport) {
- RTC_DCHECK(worker_thread_->IsCurrent());
- UpdateAggregateStates_w();
-}
-
-void TransportController::OnTransportFailed_w(Transport* transport) {
- RTC_DCHECK(worker_thread_->IsCurrent());
- UpdateAggregateStates_w();
-}
-
-void TransportController::OnTransportGatheringState_w(Transport* transport) {
- RTC_DCHECK(worker_thread_->IsCurrent());
- UpdateAggregateStates_w();
-}
-
-void TransportController::OnTransportCandidatesGathered_w(
- Transport* transport,
- const std::vector<Candidate>& candidates) {
- RTC_DCHECK(worker_thread_->IsCurrent());
- CandidatesData* data = new CandidatesData(transport->name(), candidates);
- signaling_thread_->Post(this, MSG_CANDIDATESGATHERED, data);
-}
-
-void TransportController::OnTransportRoleConflict_w() {
- RTC_DCHECK(worker_thread_->IsCurrent());
-
- if (ice_role_switch_) {
- LOG(LS_WARNING) << "Repeat of role conflict signal from Transport.";
- return;
- }
-
- ice_role_switch_ = true;
- IceRole reversed_role = (ice_role_ == ICEROLE_CONTROLLING)
- ? ICEROLE_CONTROLLED
- : ICEROLE_CONTROLLING;
- for (const auto& kv : transports_) {
- kv.second->SetIceRole(reversed_role);
- }
-}
-
-void TransportController::UpdateAggregateStates_w() {
- RTC_DCHECK(worker_thread_->IsCurrent());
-
- IceConnectionState new_connection_state = kIceConnectionConnecting;
- IceGatheringState new_gathering_state = kIceGatheringNew;
- bool any_receiving = false;
- bool any_failed = false;
- bool all_connected = HasChannels_w();
- bool all_completed = HasChannels_w();
- bool any_gathering = false;
- bool all_done_gathering = HasChannels_w();
- for (const auto& kv : transports_) {
- // Ignore transports without channels since they're about to be deleted,
- // and their state is meaningless.
- if (!kv.second->HasChannels()) {
- continue;
- }
- any_receiving = any_receiving || kv.second->any_channel_receiving();
- any_failed = any_failed || kv.second->AnyChannelFailed();
- all_connected = all_connected && kv.second->all_channels_writable();
- all_completed = all_completed && kv.second->AllChannelsCompleted();
- any_gathering =
- any_gathering || kv.second->gathering_state() != kIceGatheringNew;
- all_done_gathering = all_done_gathering &&
- kv.second->gathering_state() == kIceGatheringComplete;
- }
-
- if (any_failed) {
- new_connection_state = kIceConnectionFailed;
- } else if (all_completed) {
- new_connection_state = kIceConnectionCompleted;
- } else if (all_connected) {
- new_connection_state = kIceConnectionConnected;
- }
- if (connection_state_ != new_connection_state) {
- connection_state_ = new_connection_state;
- signaling_thread_->Post(
- this, MSG_ICECONNECTIONSTATE,
- new rtc::TypedMessageData<IceConnectionState>(new_connection_state));
- }
-
- if (receiving_ != any_receiving) {
- receiving_ = any_receiving;
- signaling_thread_->Post(this, MSG_RECEIVING,
- new rtc::TypedMessageData<bool>(any_receiving));
- }
-
- if (all_done_gathering) {
- new_gathering_state = kIceGatheringComplete;
- } else if (any_gathering) {
- new_gathering_state = kIceGatheringGathering;
- }
- if (gathering_state_ != new_gathering_state) {
- gathering_state_ = new_gathering_state;
- signaling_thread_->Post(
- this, MSG_ICEGATHERINGSTATE,
- new rtc::TypedMessageData<IceGatheringState>(new_gathering_state));
- }
-}
-
-bool TransportController::HasChannels_w() {
- for (const auto& kv : transports_) {
- if (kv.second->HasChannels()) {
- return true;
- }
- }
- return false;
-}
-
-} // namespace cricket
diff --git a/webrtc/p2p/base/transportcontroller.h b/webrtc/p2p/base/transportcontroller.h
deleted file mode 100644
index 44eb9d4..0000000
--- a/webrtc/p2p/base/transportcontroller.h
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * Copyright 2015 The WebRTC Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef WEBRTC_P2P_BASE_TRANSPORTCONTROLLER_H_
-#define WEBRTC_P2P_BASE_TRANSPORTCONTROLLER_H_
-
-#include <map>
-#include <string>
-#include <vector>
-
-#include "webrtc/base/sigslot.h"
-#include "webrtc/base/sslstreamadapter.h"
-#include "webrtc/p2p/base/candidate.h"
-#include "webrtc/p2p/base/transport.h"
-
-namespace rtc {
-class Thread;
-}
-
-namespace cricket {
-
-class TransportController : public sigslot::has_slots<>,
- public rtc::MessageHandler {
- public:
- TransportController(rtc::Thread* signaling_thread,
- rtc::Thread* worker_thread,
- PortAllocator* port_allocator);
-
- virtual ~TransportController();
-
- rtc::Thread* signaling_thread() const { return signaling_thread_; }
- rtc::Thread* worker_thread() const { return worker_thread_; }
-
- PortAllocator* port_allocator() const { return port_allocator_; }
-
- // Can only be set before transports are created.
- // TODO(deadbeef): Make this an argument to the constructor once BaseSession
- // and WebRtcSession are combined
- bool SetSslMaxProtocolVersion(rtc::SSLProtocolVersion version);
-
- void SetIceConnectionReceivingTimeout(int timeout_ms);
- void SetIceRole(IceRole ice_role);
-
- // TODO(deadbeef) - Return role of each transport, as role may differ from
- // one another.
- // In current implementaion we just return the role of the first transport
- // alphabetically.
- bool GetSslRole(rtc::SSLRole* role);
-
- // Specifies the identity to use in this session.
- // Can only be called once.
- bool SetLocalCertificate(
- const rtc::scoped_refptr<rtc::RTCCertificate>& certificate);
- bool GetLocalCertificate(
- const std::string& transport_name,
- rtc::scoped_refptr<rtc::RTCCertificate>* certificate);
- // Caller owns returned certificate
- bool GetRemoteSSLCertificate(const std::string& transport_name,
- rtc::SSLCertificate** cert);
- bool SetLocalTransportDescription(const std::string& transport_name,
- const TransportDescription& tdesc,
- ContentAction action,
- std::string* err);
- bool SetRemoteTransportDescription(const std::string& transport_name,
- const TransportDescription& tdesc,
- ContentAction action,
- std::string* err);
- bool AddRemoteCandidates(const std::string& transport_name,
- const Candidates& candidates,
- std::string* err);
- bool ReadyForRemoteCandidates(const std::string& transport_name);
- bool GetStats(const std::string& transport_name, TransportStats* stats);
-
- virtual TransportChannel* CreateTransportChannel_w(
- const std::string& transport_name,
- int component);
- virtual void DestroyTransportChannel_w(const std::string& transport_name,
- int component);
-
- // All of these signals are fired on the signalling thread.
-
- // If any transport failed => failed,
- // Else if all completed => completed,
- // Else if all connected => connected,
- // Else => connecting
- sigslot::signal1<IceConnectionState> SignalConnectionState;
-
- // Receiving if any transport is receiving
- sigslot::signal1<bool> SignalReceiving;
-
- // If all transports done gathering => complete,
- // Else if any are gathering => gathering,
- // Else => new
- sigslot::signal1<IceGatheringState> SignalGatheringState;
-
- // (transport_name, candidates)
- sigslot::signal2<const std::string&, const Candidates&>
- SignalCandidatesGathered;
-
- // for unit test
- const rtc::scoped_refptr<rtc::RTCCertificate>& certificate_for_testing();
-
- protected:
- // Protected and virtual so we can override it in unit tests.
- virtual Transport* CreateTransport_w(const std::string& transport_name);
-
- // For unit tests
- const std::map<std::string, Transport*>& transports() { return transports_; }
- Transport* GetTransport_w(const std::string& transport_name);
-
- private:
- void OnMessage(rtc::Message* pmsg) override;
-
- Transport* GetOrCreateTransport_w(const std::string& transport_name);
- void DestroyTransport_w(const std::string& transport_name);
- void DestroyAllTransports_w();
-
- bool SetSslMaxProtocolVersion_w(rtc::SSLProtocolVersion version);
- void SetIceConnectionReceivingTimeout_w(int timeout_ms);
- void SetIceRole_w(IceRole ice_role);
- bool GetSslRole_w(rtc::SSLRole* role);
- bool SetLocalCertificate_w(
- const rtc::scoped_refptr<rtc::RTCCertificate>& certificate);
- bool GetLocalCertificate_w(
- const std::string& transport_name,
- rtc::scoped_refptr<rtc::RTCCertificate>* certificate);
- bool GetRemoteSSLCertificate_w(const std::string& transport_name,
- rtc::SSLCertificate** cert);
- bool SetLocalTransportDescription_w(const std::string& transport_name,
- const TransportDescription& tdesc,
- ContentAction action,
- std::string* err);
- bool SetRemoteTransportDescription_w(const std::string& transport_name,
- const TransportDescription& tdesc,
- ContentAction action,
- std::string* err);
- bool AddRemoteCandidates_w(const std::string& transport_name,
- const Candidates& candidates,
- std::string* err);
- bool ReadyForRemoteCandidates_w(const std::string& transport_name);
- bool GetStats_w(const std::string& transport_name, TransportStats* stats);
-
- // Handlers for signals from Transport.
- void OnTransportConnecting_w(Transport* transport);
- void OnTransportWritableState_w(Transport* transport);
- void OnTransportReceivingState_w(Transport* transport);
- void OnTransportCompleted_w(Transport* transport);
- void OnTransportFailed_w(Transport* transport);
- void OnTransportGatheringState_w(Transport* transport);
- void OnTransportCandidatesGathered_w(
- Transport* transport,
- const std::vector<Candidate>& candidates);
- void OnTransportRoleConflict_w();
-
- void UpdateAggregateStates_w();
- bool HasChannels_w();
-
- rtc::Thread* const signaling_thread_ = nullptr;
- rtc::Thread* const worker_thread_ = nullptr;
- typedef std::map<std::string, Transport*> TransportMap;
- TransportMap transports_;
-
- PortAllocator* const port_allocator_ = nullptr;
- rtc::SSLProtocolVersion ssl_max_version_ = rtc::SSL_PROTOCOL_DTLS_10;
-
- // Aggregate state for Transports
- IceConnectionState connection_state_ = kIceConnectionConnecting;
- bool receiving_ = false;
- IceGatheringState gathering_state_ = kIceGatheringNew;
-
- // TODO(deadbeef): Move the fields below down to the transports themselves
-
- // Timeout value in milliseconds for which no ICE connection receives
- // any packets
- int ice_receiving_timeout_ms_ = -1;
- IceRole ice_role_ = ICEROLE_CONTROLLING;
- // Flag which will be set to true after the first role switch
- bool ice_role_switch_ = false;
- uint64 ice_tiebreaker_ = rtc::CreateRandomId64();
- rtc::scoped_refptr<rtc::RTCCertificate> certificate_;
-};
-
-} // namespace cricket
-
-#endif // WEBRTC_P2P_BASE_TRANSPORTCONTROLLER_H_
diff --git a/webrtc/p2p/base/transportcontroller_unittest.cc b/webrtc/p2p/base/transportcontroller_unittest.cc
deleted file mode 100644
index dd89353..0000000
--- a/webrtc/p2p/base/transportcontroller_unittest.cc
+++ /dev/null
@@ -1,675 +0,0 @@
-/*
- * Copyright 2015 The WebRTC Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include <map>
-
-#include "webrtc/base/fakesslidentity.h"
-#include "webrtc/base/gunit.h"
-#include "webrtc/base/helpers.h"
-#include "webrtc/base/scoped_ptr.h"
-#include "webrtc/base/sslidentity.h"
-#include "webrtc/base/thread.h"
-#include "webrtc/p2p/base/dtlstransportchannel.h"
-#include "webrtc/p2p/base/faketransportcontroller.h"
-#include "webrtc/p2p/base/p2ptransportchannel.h"
-#include "webrtc/p2p/base/portallocator.h"
-#include "webrtc/p2p/base/transportcontroller.h"
-#include "webrtc/p2p/client/fakeportallocator.h"
-
-static const int kTimeout = 100;
-static const char kIceUfrag1[] = "TESTICEUFRAG0001";
-static const char kIcePwd1[] = "TESTICEPWD00000000000001";
-static const char kIceUfrag2[] = "TESTICEUFRAG0002";
-static const char kIcePwd2[] = "TESTICEPWD00000000000002";
-
-using cricket::Candidate;
-using cricket::Candidates;
-using cricket::FakeTransportChannel;
-using cricket::FakeTransportController;
-using cricket::IceConnectionState;
-using cricket::IceGatheringState;
-using cricket::TransportChannel;
-using cricket::TransportController;
-using cricket::TransportDescription;
-using cricket::TransportStats;
-
-// Only subclassing from FakeTransportController because currently that's the
-// only way to have a TransportController with fake TransportChannels.
-//
-// TODO(deadbeef): Change this once the Transport/TransportChannel class
-// heirarchy is cleaned up, and we can pass a "TransportChannelFactory" or
-// something similar into TransportController.
-typedef FakeTransportController TransportControllerForTest;
-
-class TransportControllerTest : public testing::Test,
- public sigslot::has_slots<> {
- public:
- TransportControllerTest()
- : transport_controller_(new TransportControllerForTest()),
- signaling_thread_(rtc::Thread::Current()) {
- ConnectTransportControllerSignals();
- }
-
- void CreateTransportControllerWithWorkerThread() {
- if (!worker_thread_) {
- worker_thread_.reset(new rtc::Thread());
- worker_thread_->Start();
- }
- transport_controller_.reset(
- new TransportControllerForTest(worker_thread_.get()));
- ConnectTransportControllerSignals();
- }
-
- void ConnectTransportControllerSignals() {
- transport_controller_->SignalConnectionState.connect(
- this, &TransportControllerTest::OnConnectionState);
- transport_controller_->SignalReceiving.connect(
- this, &TransportControllerTest::OnReceiving);
- transport_controller_->SignalGatheringState.connect(
- this, &TransportControllerTest::OnGatheringState);
- transport_controller_->SignalCandidatesGathered.connect(
- this, &TransportControllerTest::OnCandidatesGathered);
- }
-
- FakeTransportChannel* CreateChannel(const std::string& content,
- int component) {
- TransportChannel* channel =
- transport_controller_->CreateTransportChannel_w(content, component);
- return static_cast<FakeTransportChannel*>(channel);
- }
-
- void DestroyChannel(const std::string& content, int component) {
- transport_controller_->DestroyTransportChannel_w(content, component);
- }
-
- Candidate CreateCandidate(int component) {
- Candidate c;
- c.set_address(rtc::SocketAddress("192.168.1.1", 8000));
- c.set_component(1);
- c.set_protocol(cricket::UDP_PROTOCOL_NAME);
- c.set_priority(1);
- return c;
- }
-
- // Used for thread hopping test.
- void CreateChannelsAndCompleteConnectionOnWorkerThread() {
- worker_thread_->Invoke<void>(rtc::Bind(
- &TransportControllerTest::CreateChannelsAndCompleteConnection_w, this));
- }
-
- void CreateChannelsAndCompleteConnection_w() {
- transport_controller_->SetIceRole(cricket::ICEROLE_CONTROLLING);
- FakeTransportChannel* channel1 = CreateChannel("audio", 1);
- ASSERT_NE(nullptr, channel1);
- FakeTransportChannel* channel2 = CreateChannel("video", 1);
- ASSERT_NE(nullptr, channel2);
-
- TransportDescription local_desc(
- std::vector<std::string>(), kIceUfrag1, kIcePwd1, cricket::ICEMODE_FULL,
- cricket::CONNECTIONROLE_ACTPASS, nullptr, Candidates());
- std::string err;
- transport_controller_->SetLocalTransportDescription(
- "audio", local_desc, cricket::CA_OFFER, &err);
- transport_controller_->SetLocalTransportDescription(
- "video", local_desc, cricket::CA_OFFER, &err);
- channel1->SignalCandidateGathered(channel1, CreateCandidate(1));
- channel2->SignalCandidateGathered(channel2, CreateCandidate(1));
- channel1->SetCandidatesGatheringComplete();
- channel2->SetCandidatesGatheringComplete();
- channel1->SetConnectionCount(2);
- channel2->SetConnectionCount(2);
- channel1->SetReceiving(true);
- channel2->SetReceiving(true);
- channel1->SetWritable(true);
- channel2->SetWritable(true);
- channel1->SetConnectionCount(1);
- channel2->SetConnectionCount(1);
- }
-
- protected:
- void OnConnectionState(IceConnectionState state) {
- if (!signaling_thread_->IsCurrent()) {
- signaled_on_non_signaling_thread_ = true;
- }
- connection_state_ = state;
- ++connection_state_signal_count_;
- }
-
- void OnReceiving(bool receiving) {
- if (!signaling_thread_->IsCurrent()) {
- signaled_on_non_signaling_thread_ = true;
- }
- receiving_ = receiving;
- ++receiving_signal_count_;
- }
-
- void OnGatheringState(IceGatheringState state) {
- if (!signaling_thread_->IsCurrent()) {
- signaled_on_non_signaling_thread_ = true;
- }
- gathering_state_ = state;
- ++gathering_state_signal_count_;
- }
-
- void OnCandidatesGathered(const std::string& transport_name,
- const Candidates& candidates) {
- if (!signaling_thread_->IsCurrent()) {
- signaled_on_non_signaling_thread_ = true;
- }
- candidates_[transport_name].insert(candidates_[transport_name].end(),
- candidates.begin(), candidates.end());
- ++candidates_signal_count_;
- }
-
- rtc::scoped_ptr<rtc::Thread> worker_thread_; // Not used for most tests.
- rtc::scoped_ptr<TransportControllerForTest> transport_controller_;
-
- // Information received from signals from transport controller.
- IceConnectionState connection_state_ = cricket::kIceConnectionConnecting;
- bool receiving_ = false;
- IceGatheringState gathering_state_ = cricket::kIceGatheringNew;
- // transport_name => candidates
- std::map<std::string, Candidates> candidates_;
- // Counts of each signal emitted.
- int connection_state_signal_count_ = 0;
- int receiving_signal_count_ = 0;
- int gathering_state_signal_count_ = 0;
- int candidates_signal_count_ = 0;
-
- // Used to make sure signals only come on signaling thread.
- rtc::Thread* const signaling_thread_ = nullptr;
- bool signaled_on_non_signaling_thread_ = false;
-};
-
-TEST_F(TransportControllerTest, TestSetIceReceivingTimeout) {
- FakeTransportChannel* channel1 = CreateChannel("audio", 1);
- ASSERT_NE(nullptr, channel1);
-
- transport_controller_->SetIceConnectionReceivingTimeout(1000);
- EXPECT_EQ(1000, channel1->receiving_timeout());
-
- // Test that value stored in controller is applied to new channels.
- FakeTransportChannel* channel2 = CreateChannel("video", 1);
- ASSERT_NE(nullptr, channel2);
- EXPECT_EQ(1000, channel2->receiving_timeout());
-}
-
-TEST_F(TransportControllerTest, TestSetSslMaxProtocolVersion) {
- EXPECT_TRUE(transport_controller_->SetSslMaxProtocolVersion(
- rtc::SSL_PROTOCOL_DTLS_12));
- FakeTransportChannel* channel = CreateChannel("audio", 1);
-
- ASSERT_NE(nullptr, channel);
- EXPECT_EQ(rtc::SSL_PROTOCOL_DTLS_12, channel->ssl_max_protocol_version());
-
- // Setting max version after transport is created should fail.
- EXPECT_FALSE(transport_controller_->SetSslMaxProtocolVersion(
- rtc::SSL_PROTOCOL_DTLS_10));
-}
-
-TEST_F(TransportControllerTest, TestSetIceRole) {
- FakeTransportChannel* channel1 = CreateChannel("audio", 1);
- ASSERT_NE(nullptr, channel1);
-
- transport_controller_->SetIceRole(cricket::ICEROLE_CONTROLLING);
- EXPECT_EQ(cricket::ICEROLE_CONTROLLING, channel1->GetIceRole());
- transport_controller_->SetIceRole(cricket::ICEROLE_CONTROLLED);
- EXPECT_EQ(cricket::ICEROLE_CONTROLLED, channel1->GetIceRole());
-
- // Test that value stored in controller is applied to new channels.
- FakeTransportChannel* channel2 = CreateChannel("video", 1);
- ASSERT_NE(nullptr, channel2);
- EXPECT_EQ(cricket::ICEROLE_CONTROLLED, channel2->GetIceRole());
-}
-
-// Test that when one channel encounters a role conflict, the ICE role is
-// swapped on every channel.
-TEST_F(TransportControllerTest, TestIceRoleConflict) {
- FakeTransportChannel* channel1 = CreateChannel("audio", 1);
- ASSERT_NE(nullptr, channel1);
- FakeTransportChannel* channel2 = CreateChannel("video", 1);
- ASSERT_NE(nullptr, channel2);
-
- transport_controller_->SetIceRole(cricket::ICEROLE_CONTROLLING);
- EXPECT_EQ(cricket::ICEROLE_CONTROLLING, channel1->GetIceRole());
- EXPECT_EQ(cricket::ICEROLE_CONTROLLING, channel2->GetIceRole());
-
- channel1->SignalRoleConflict(channel1);
- EXPECT_EQ(cricket::ICEROLE_CONTROLLED, channel1->GetIceRole());
- EXPECT_EQ(cricket::ICEROLE_CONTROLLED, channel2->GetIceRole());
-}
-
-TEST_F(TransportControllerTest, TestGetSslRole) {
- FakeTransportChannel* channel = CreateChannel("audio", 1);
- ASSERT_NE(nullptr, channel);
- ASSERT_TRUE(channel->SetSslRole(rtc::SSL_CLIENT));
- rtc::SSLRole role;
- EXPECT_TRUE(transport_controller_->GetSslRole(&role));
- EXPECT_EQ(rtc::SSL_CLIENT, role);
-}
-
-TEST_F(TransportControllerTest, TestSetAndGetLocalCertificate) {
- rtc::scoped_refptr<rtc::RTCCertificate> certificate1 =
- rtc::RTCCertificate::Create(
- rtc::scoped_ptr<rtc::SSLIdentity>(
- rtc::SSLIdentity::Generate("session1", rtc::KT_DEFAULT))
- .Pass());
- rtc::scoped_refptr<rtc::RTCCertificate> certificate2 =
- rtc::RTCCertificate::Create(
- rtc::scoped_ptr<rtc::SSLIdentity>(
- rtc::SSLIdentity::Generate("session2", rtc::KT_DEFAULT))
- .Pass());
- rtc::scoped_refptr<rtc::RTCCertificate> returned_certificate;
-
- FakeTransportChannel* channel1 = CreateChannel("audio", 1);
- ASSERT_NE(nullptr, channel1);
-
- EXPECT_TRUE(transport_controller_->SetLocalCertificate(certificate1));
- EXPECT_TRUE(transport_controller_->GetLocalCertificate(
- "audio", &returned_certificate));
- EXPECT_EQ(certificate1->identity()->certificate().ToPEMString(),
- returned_certificate->identity()->certificate().ToPEMString());
-
- // Should fail if called for a nonexistant transport.
- EXPECT_FALSE(transport_controller_->GetLocalCertificate(
- "video", &returned_certificate));
-
- // Test that identity stored in controller is applied to new channels.
- FakeTransportChannel* channel2 = CreateChannel("video", 1);
- ASSERT_NE(nullptr, channel2);
- EXPECT_TRUE(transport_controller_->GetLocalCertificate(
- "video", &returned_certificate));
- EXPECT_EQ(certificate1->identity()->certificate().ToPEMString(),
- returned_certificate->identity()->certificate().ToPEMString());
-
- // Shouldn't be able to change the identity once set.
- EXPECT_FALSE(transport_controller_->SetLocalCertificate(certificate2));
-}
-
-TEST_F(TransportControllerTest, TestGetRemoteSSLCertificate) {
- rtc::FakeSSLCertificate fake_certificate("fake_data");
- rtc::scoped_ptr<rtc::SSLCertificate> returned_certificate;
-
- FakeTransportChannel* channel = CreateChannel("audio", 1);
- ASSERT_NE(nullptr, channel);
-
- channel->SetRemoteSSLCertificate(&fake_certificate);
- EXPECT_TRUE(transport_controller_->GetRemoteSSLCertificate(
- "audio", returned_certificate.accept()));
- EXPECT_EQ(fake_certificate.ToPEMString(),
- returned_certificate->ToPEMString());
-
- // Should fail if called for a nonexistant transport.
- EXPECT_FALSE(transport_controller_->GetRemoteSSLCertificate(
- "video", returned_certificate.accept()));
-}
-
-TEST_F(TransportControllerTest, TestSetLocalTransportDescription) {
- FakeTransportChannel* channel = CreateChannel("audio", 1);
- ASSERT_NE(nullptr, channel);
- TransportDescription local_desc(
- std::vector<std::string>(), kIceUfrag1, kIcePwd1, cricket::ICEMODE_FULL,
- cricket::CONNECTIONROLE_ACTPASS, nullptr, Candidates());
- std::string err;
- EXPECT_TRUE(transport_controller_->SetLocalTransportDescription(
- "audio", local_desc, cricket::CA_OFFER, &err));
- // Check that ICE ufrag and pwd were propagated to channel.
- EXPECT_EQ(kIceUfrag1, channel->ice_ufrag());
- EXPECT_EQ(kIcePwd1, channel->ice_pwd());
- // We also expect that the channel started gathering as a result of the
- // description being set.
- EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
- EXPECT_EQ(1, gathering_state_signal_count_);
-}
-
-TEST_F(TransportControllerTest, TestSetRemoteTransportDescription) {
- FakeTransportChannel* channel = CreateChannel("audio", 1);
- ASSERT_NE(nullptr, channel);
- TransportDescription remote_desc(
- std::vector<std::string>(), kIceUfrag1, kIcePwd1, cricket::ICEMODE_FULL,
- cricket::CONNECTIONROLE_ACTPASS, nullptr, Candidates());
- std::string err;
- EXPECT_TRUE(transport_controller_->SetRemoteTransportDescription(
- "audio", remote_desc, cricket::CA_OFFER, &err));
- // Check that ICE ufrag and pwd were propagated to channel.
- EXPECT_EQ(kIceUfrag1, channel->remote_ice_ufrag());
- EXPECT_EQ(kIcePwd1, channel->remote_ice_pwd());
-}
-
-TEST_F(TransportControllerTest, TestAddRemoteCandidates) {
- FakeTransportChannel* channel = CreateChannel("audio", 1);
- ASSERT_NE(nullptr, channel);
- Candidates candidates;
- candidates.push_back(CreateCandidate(1));
- std::string err;
- EXPECT_TRUE(
- transport_controller_->AddRemoteCandidates("audio", candidates, &err));
- EXPECT_EQ(1U, channel->remote_candidates().size());
-}
-
-TEST_F(TransportControllerTest, TestReadyForRemoteCandidates) {
- FakeTransportChannel* channel = CreateChannel("audio", 1);
- ASSERT_NE(nullptr, channel);
- // We expect to be ready for remote candidates only after local and remote
- // descriptions are set.
- EXPECT_FALSE(transport_controller_->ReadyForRemoteCandidates("audio"));
-
- std::string err;
- TransportDescription remote_desc(
- std::vector<std::string>(), kIceUfrag1, kIcePwd1, cricket::ICEMODE_FULL,
- cricket::CONNECTIONROLE_ACTPASS, nullptr, Candidates());
- EXPECT_TRUE(transport_controller_->SetRemoteTransportDescription(
- "audio", remote_desc, cricket::CA_OFFER, &err));
- EXPECT_FALSE(transport_controller_->ReadyForRemoteCandidates("audio"));
-
- TransportDescription local_desc(
- std::vector<std::string>(), kIceUfrag2, kIcePwd2, cricket::ICEMODE_FULL,
- cricket::CONNECTIONROLE_ACTPASS, nullptr, Candidates());
- EXPECT_TRUE(transport_controller_->SetLocalTransportDescription(
- "audio", local_desc, cricket::CA_ANSWER, &err));
- EXPECT_TRUE(transport_controller_->ReadyForRemoteCandidates("audio"));
-}
-
-TEST_F(TransportControllerTest, TestGetStats) {
- FakeTransportChannel* channel1 = CreateChannel("audio", 1);
- ASSERT_NE(nullptr, channel1);
- FakeTransportChannel* channel2 = CreateChannel("audio", 2);
- ASSERT_NE(nullptr, channel2);
- FakeTransportChannel* channel3 = CreateChannel("video", 1);
- ASSERT_NE(nullptr, channel3);
-
- TransportStats stats;
- EXPECT_TRUE(transport_controller_->GetStats("audio", &stats));
- EXPECT_EQ("audio", stats.transport_name);
- EXPECT_EQ(2U, stats.channel_stats.size());
-}
-
-// Test that transport gets destroyed when it has no more channels.
-TEST_F(TransportControllerTest, TestCreateAndDestroyChannel) {
- FakeTransportChannel* channel1 = CreateChannel("audio", 1);
- ASSERT_NE(nullptr, channel1);
- FakeTransportChannel* channel2 = CreateChannel("audio", 1);
- ASSERT_NE(nullptr, channel2);
- ASSERT_EQ(channel1, channel2);
- FakeTransportChannel* channel3 = CreateChannel("audio", 2);
- ASSERT_NE(nullptr, channel3);
-
- // Using GetStats to check if transport is destroyed from an outside class's
- // perspective.
- TransportStats stats;
- EXPECT_TRUE(transport_controller_->GetStats("audio", &stats));
- DestroyChannel("audio", 2);
- DestroyChannel("audio", 1);
- EXPECT_TRUE(transport_controller_->GetStats("audio", &stats));
- DestroyChannel("audio", 1);
- EXPECT_FALSE(transport_controller_->GetStats("audio", &stats));
-}
-
-TEST_F(TransportControllerTest, TestSignalConnectionStateFailed) {
- // Need controlling ICE role to get in failed state.
- transport_controller_->SetIceRole(cricket::ICEROLE_CONTROLLING);
- FakeTransportChannel* channel1 = CreateChannel("audio", 1);
- ASSERT_NE(nullptr, channel1);
- FakeTransportChannel* channel2 = CreateChannel("video", 1);
- ASSERT_NE(nullptr, channel2);
-
- // Should signal "failed" if any channel failed; channel is considered failed
- // if it previously had a connection but now has none, and gathering is
- // complete.
- channel1->SetCandidatesGatheringComplete();
- channel1->SetConnectionCount(1);
- channel1->SetConnectionCount(0);
- EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
- EXPECT_EQ(1, connection_state_signal_count_);
-}
-
-TEST_F(TransportControllerTest, TestSignalConnectionStateConnected) {
- transport_controller_->SetIceRole(cricket::ICEROLE_CONTROLLING);
- FakeTransportChannel* channel1 = CreateChannel("audio", 1);
- ASSERT_NE(nullptr, channel1);
- FakeTransportChannel* channel2 = CreateChannel("video", 1);
- ASSERT_NE(nullptr, channel2);
- FakeTransportChannel* channel3 = CreateChannel("video", 2);
- ASSERT_NE(nullptr, channel3);
-
- // First, have one channel connect, and another fail, to ensure that
- // the first channel connecting didn't trigger a "connected" state signal.
- // We should only get a signal when all are connected.
- channel1->SetConnectionCount(2);
- channel1->SetWritable(true);
- channel3->SetCandidatesGatheringComplete();
- channel3->SetConnectionCount(1);
- channel3->SetConnectionCount(0);
- EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
- // Signal count of 1 means that the only signal emitted was "failed".
- EXPECT_EQ(1, connection_state_signal_count_);
-
- // Destroy the failed channel to return to "connecting" state.
- DestroyChannel("video", 2);
- EXPECT_EQ_WAIT(cricket::kIceConnectionConnecting, connection_state_,
- kTimeout);
- EXPECT_EQ(2, connection_state_signal_count_);
-
- // Make the remaining channel reach a connected state.
- channel2->SetConnectionCount(2);
- channel2->SetWritable(true);
- EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
- EXPECT_EQ(3, connection_state_signal_count_);
-}
-
-TEST_F(TransportControllerTest, TestSignalConnectionStateComplete) {
- transport_controller_->SetIceRole(cricket::ICEROLE_CONTROLLING);
- FakeTransportChannel* channel1 = CreateChannel("audio", 1);
- ASSERT_NE(nullptr, channel1);
- FakeTransportChannel* channel2 = CreateChannel("video", 1);
- ASSERT_NE(nullptr, channel2);
- FakeTransportChannel* channel3 = CreateChannel("video", 2);
- ASSERT_NE(nullptr, channel3);
-
- // Similar to above test, but we're now reaching the completed state, which
- // means only one connection per FakeTransportChannel.
- channel1->SetCandidatesGatheringComplete();
- channel1->SetConnectionCount(1);
- channel1->SetWritable(true);
- channel3->SetCandidatesGatheringComplete();
- channel3->SetConnectionCount(1);
- channel3->SetConnectionCount(0);
- EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
- // Signal count of 1 means that the only signal emitted was "failed".
- EXPECT_EQ(1, connection_state_signal_count_);
-
- // Destroy the failed channel to return to "connecting" state.
- DestroyChannel("video", 2);
- EXPECT_EQ_WAIT(cricket::kIceConnectionConnecting, connection_state_,
- kTimeout);
- EXPECT_EQ(2, connection_state_signal_count_);
-
- // Make the remaining channel reach a connected state.
- channel2->SetCandidatesGatheringComplete();
- channel2->SetConnectionCount(2);
- channel2->SetWritable(true);
- EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
- EXPECT_EQ(3, connection_state_signal_count_);
-
- // Finally, transition to completed state.
- channel2->SetConnectionCount(1);
- EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
- EXPECT_EQ(4, connection_state_signal_count_);
-}
-
-// Make sure that if we're "connected" and remove a transport, we stay in the
-// "connected" state.
-TEST_F(TransportControllerTest, TestDestroyTransportAndStayConnected) {
- FakeTransportChannel* channel1 = CreateChannel("audio", 1);
- ASSERT_NE(nullptr, channel1);
- FakeTransportChannel* channel2 = CreateChannel("video", 1);
- ASSERT_NE(nullptr, channel2);
-
- channel1->SetCandidatesGatheringComplete();
- channel1->SetConnectionCount(2);
- channel1->SetWritable(true);
- channel2->SetCandidatesGatheringComplete();
- channel2->SetConnectionCount(2);
- channel2->SetWritable(true);
- EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
- EXPECT_EQ(1, connection_state_signal_count_);
-
- // Destroy one channel, then "complete" the other one, so we reach
- // a known state.
- DestroyChannel("video", 1);
- channel1->SetConnectionCount(1);
- EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
- // Signal count of 2 means the deletion didn't cause any unexpected signals
- EXPECT_EQ(2, connection_state_signal_count_);
-}
-
-// If we destroy the last/only transport, we should simply transition to
-// "connecting".
-TEST_F(TransportControllerTest, TestDestroyLastTransportWhileConnected) {
- FakeTransportChannel* channel = CreateChannel("audio", 1);
- ASSERT_NE(nullptr, channel);
-
- channel->SetCandidatesGatheringComplete();
- channel->SetConnectionCount(2);
- channel->SetWritable(true);
- EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
- EXPECT_EQ(1, connection_state_signal_count_);
-
- DestroyChannel("audio", 1);
- EXPECT_EQ_WAIT(cricket::kIceConnectionConnecting, connection_state_,
- kTimeout);
- // Signal count of 2 means the deletion didn't cause any unexpected signals
- EXPECT_EQ(2, connection_state_signal_count_);
-}
-
-TEST_F(TransportControllerTest, TestSignalReceiving) {
- FakeTransportChannel* channel1 = CreateChannel("audio", 1);
- ASSERT_NE(nullptr, channel1);
- FakeTransportChannel* channel2 = CreateChannel("video", 1);
- ASSERT_NE(nullptr, channel2);
-
- // Should signal receiving as soon as any channel is receiving.
- channel1->SetReceiving(true);
- EXPECT_TRUE_WAIT(receiving_, kTimeout);
- EXPECT_EQ(1, receiving_signal_count_);
-
- channel2->SetReceiving(true);
- channel1->SetReceiving(false);
- channel2->SetReceiving(false);
- EXPECT_TRUE_WAIT(!receiving_, kTimeout);
- EXPECT_EQ(2, receiving_signal_count_);
-}
-
-TEST_F(TransportControllerTest, TestSignalGatheringStateGathering) {
- FakeTransportChannel* channel1 = CreateChannel("audio", 1);
- ASSERT_NE(nullptr, channel1);
- FakeTransportChannel* channel2 = CreateChannel("video", 1);
- ASSERT_NE(nullptr, channel2);
- // Connect starts candidate gathering.
- channel1->Connect();
- // Should be in the gathering state as soon as any transport starts gathering.
- EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
- EXPECT_EQ(1, gathering_state_signal_count_);
-}
-
-TEST_F(TransportControllerTest, TestSignalGatheringStateComplete) {
- FakeTransportChannel* channel1 = CreateChannel("audio", 1);
- ASSERT_NE(nullptr, channel1);
- FakeTransportChannel* channel2 = CreateChannel("video", 1);
- ASSERT_NE(nullptr, channel2);
- FakeTransportChannel* channel3 = CreateChannel("data", 1);
- ASSERT_NE(nullptr, channel3);
-
- channel3->Connect();
- EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
- EXPECT_EQ(1, gathering_state_signal_count_);
-
- // Have one channel finish gathering, then destroy it, to make sure gathering
- // completion wasn't signalled if only one transport finished gathering.
- channel3->SetCandidatesGatheringComplete();
- DestroyChannel("data", 1);
- EXPECT_EQ_WAIT(cricket::kIceGatheringNew, gathering_state_, kTimeout);
- EXPECT_EQ(2, gathering_state_signal_count_);
-
- // Make remaining channels start and then finish gathering.
- channel1->Connect();
- channel2->Connect();
- EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
- EXPECT_EQ(3, gathering_state_signal_count_);
-
- channel1->SetCandidatesGatheringComplete();
- channel2->SetCandidatesGatheringComplete();
- EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
- EXPECT_EQ(4, gathering_state_signal_count_);
-}
-
-// Test that when the last transport that hasn't finished connecting and/or
-// gathering is destroyed, the aggregate state jumps to "completed". This can
-// happen if, for example, we have an audio and video transport, the audio
-// transport completes, then we start bundling video on the audio transport.
-TEST_F(TransportControllerTest,
- TestSignalingWhenLastIncompleteTransportDestroyed) {
- transport_controller_->SetIceRole(cricket::ICEROLE_CONTROLLING);
- FakeTransportChannel* channel1 = CreateChannel("audio", 1);
- ASSERT_NE(nullptr, channel1);
- FakeTransportChannel* channel2 = CreateChannel("video", 1);
- ASSERT_NE(nullptr, channel2);
-
- channel1->SetCandidatesGatheringComplete();
- EXPECT_EQ_WAIT(cricket::kIceGatheringGathering, gathering_state_, kTimeout);
- EXPECT_EQ(1, gathering_state_signal_count_);
-
- channel1->SetConnectionCount(1);
- channel1->SetWritable(true);
- DestroyChannel("video", 1);
- EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
- EXPECT_EQ(1, connection_state_signal_count_);
- EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
- EXPECT_EQ(2, gathering_state_signal_count_);
-}
-
-TEST_F(TransportControllerTest, TestSignalCandidatesGathered) {
- FakeTransportChannel* channel = CreateChannel("audio", 1);
- ASSERT_NE(nullptr, channel);
-
- // Transport won't signal candidates until it has a local description.
- TransportDescription local_desc(
- std::vector<std::string>(), kIceUfrag1, kIcePwd1, cricket::ICEMODE_FULL,
- cricket::CONNECTIONROLE_ACTPASS, nullptr, Candidates());
- std::string err;
- EXPECT_TRUE(transport_controller_->SetLocalTransportDescription(
- "audio", local_desc, cricket::CA_OFFER, &err));
-
- channel->SignalCandidateGathered(channel, CreateCandidate(1));
- EXPECT_EQ_WAIT(1, candidates_signal_count_, kTimeout);
- EXPECT_EQ(1U, candidates_["audio"].size());
-}
-
-TEST_F(TransportControllerTest, TestSignalingOccursOnSignalingThread) {
- CreateTransportControllerWithWorkerThread();
- CreateChannelsAndCompleteConnectionOnWorkerThread();
-
- // connecting --> connected --> completed
- EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
- EXPECT_EQ(2, connection_state_signal_count_);
-
- EXPECT_TRUE_WAIT(receiving_, kTimeout);
- EXPECT_EQ(1, receiving_signal_count_);
-
- // new --> gathering --> complete
- EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
- EXPECT_EQ(2, gathering_state_signal_count_);
-
- EXPECT_EQ_WAIT(1U, candidates_["audio"].size(), kTimeout);
- EXPECT_EQ_WAIT(1U, candidates_["video"].size(), kTimeout);
- EXPECT_EQ(2, candidates_signal_count_);
-
- EXPECT_TRUE(!signaled_on_non_signaling_thread_);
-}
diff --git a/webrtc/p2p/base/transportdescriptionfactory.cc b/webrtc/p2p/base/transportdescriptionfactory.cc
index 1ddf55d..4c701df 100644
--- a/webrtc/p2p/base/transportdescriptionfactory.cc
+++ b/webrtc/p2p/base/transportdescriptionfactory.cc
@@ -14,6 +14,7 @@
#include "webrtc/base/helpers.h"
#include "webrtc/base/logging.h"
#include "webrtc/base/messagedigest.h"
+#include "webrtc/base/scoped_ptr.h"
#include "webrtc/base/sslfingerprint.h"
namespace cricket {
diff --git a/webrtc/p2p/p2p.gyp b/webrtc/p2p/p2p.gyp
index b5409f4..45c9e13 100644
--- a/webrtc/p2p/p2p.gyp
+++ b/webrtc/p2p/p2p.gyp
@@ -66,8 +66,8 @@
'base/transportchannel.cc',
'base/transportchannel.h',
'base/transportchannelimpl.h',
- 'base/transportcontroller.cc',
- 'base/transportcontroller.h',
+ 'base/transportchannelproxy.cc',
+ 'base/transportchannelproxy.h',
'base/transportdescription.cc',
'base/transportdescription.h',
'base/transportdescriptionfactory.cc',
diff --git a/webrtc/p2p/p2p_tests.gypi b/webrtc/p2p/p2p_tests.gypi
index ba7f553..8c2c2b3 100644
--- a/webrtc/p2p/p2p_tests.gypi
+++ b/webrtc/p2p/p2p_tests.gypi
@@ -15,12 +15,13 @@
'direct_dependent_settings': {
'sources': [
'base/dtlstransportchannel_unittest.cc',
- 'base/faketransportcontroller.h',
+ 'base/fakesession.h',
'base/p2ptransportchannel_unittest.cc',
'base/port_unittest.cc',
'base/pseudotcp_unittest.cc',
'base/relayport_unittest.cc',
'base/relayserver_unittest.cc',
+ 'base/session_unittest.cc',
'base/stun_unittest.cc',
'base/stunport_unittest.cc',
'base/stunrequest_unittest.cc',
@@ -29,7 +30,6 @@
'base/teststunserver.h',
'base/testturnserver.h',
'base/transport_unittest.cc',
- 'base/transportcontroller_unittest.cc',
'base/transportdescriptionfactory_unittest.cc',
'base/turnport_unittest.cc',
'client/fakeportallocator.h',