Reland of TransportController refactoring. (patchset #1 id:1 of https://codereview.webrtc.org/1358413003/ )
Reason for revert:
This CL just landed: https://codereview.chromium.org/1323243006/
Which fixes the FYI bots for the original CL, and breaks them for this revert.
Original issue's description:
> Revert of TransportController refactoring. (patchset #6 id:100001 of https://codereview.webrtc.org/1350523003/ )
>
> Reason for revert:
> This CL causes problems with the WebRTC-in-Chromium FYI bots. Presumably it needs to be done in several steps, where removed files are emptied instead of removed in the first step.
>
> Original issue's description:
> > TransportController refactoring.
> >
> > Getting rid of TransportProxy, and in its place adding a
> > TransportController class which will facilitate access to and manage
> > the lifetimes of Transports. These Transports will now be accessed
> > solely from the worker thread, simplifying their implementation.
> >
> > This refactoring also pulls Transport-related code out of BaseSession.
> > Which means that BaseChannels will now rely on the TransportController
> > interface to create channels, rather than BaseSession.
> >
> > Committed: https://crrev.com/47ee2f3b9f33e8938948c482c921d4e13a3acd83
> > Cr-Commit-Position: refs/heads/master@{#10022}
>
> TBR=pthatcher@webrtc.org,deadbeef@webrtc.org
> NOPRESUBMIT=true
> NOTREECHECKS=true
> NOTRY=true
>
> Committed: https://crrev.com/a81a42f584baa0d93a4b93da9632415e8922450c
> Cr-Commit-Position: refs/heads/master@{#10024}
TBR=pthatcher@webrtc.org,torbjorng@webrtc.org
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
Review URL: https://codereview.webrtc.org/1361773005
Cr-Commit-Position: refs/heads/master@{#10036}
diff --git a/webrtc/base/fakenetwork.h b/webrtc/base/fakenetwork.h
index 4b6bb68..065d08d 100644
--- a/webrtc/base/fakenetwork.h
+++ b/webrtc/base/fakenetwork.h
@@ -29,12 +29,7 @@
class FakeNetworkManager : public NetworkManagerBase,
public MessageHandler {
public:
- FakeNetworkManager()
- : thread_(Thread::Current()),
- next_index_(0),
- started_(false),
- sent_first_update_(false) {
- }
+ FakeNetworkManager() : thread_(Thread::Current()) {}
typedef std::vector<SocketAddress> IfaceList;
@@ -58,20 +53,18 @@
}
virtual void StartUpdating() {
- if (started_) {
- if (sent_first_update_)
+ ++start_count_;
+ if (start_count_ == 1) {
+ sent_first_update_ = false;
+ thread_->Post(this);
+ } else {
+ if (sent_first_update_) {
SignalNetworksChanged();
- return;
+ }
}
-
- started_ = true;
- sent_first_update_ = false;
- thread_->Post(this);
}
- virtual void StopUpdating() {
- started_ = false;
- }
+ virtual void StopUpdating() { --start_count_; }
// MessageHandler interface.
virtual void OnMessage(Message* msg) {
@@ -82,7 +75,7 @@
private:
void DoUpdateNetworks() {
- if (!started_)
+ if (start_count_ == 0)
return;
std::vector<Network*> networks;
for (IfaceList::iterator it = ifaces_.begin();
@@ -111,9 +104,9 @@
Thread* thread_;
IfaceList ifaces_;
- int next_index_;
- bool started_;
- bool sent_first_update_;
+ int next_index_ = 0;
+ int start_count_ = 0;
+ bool sent_first_update_ = false;
};
} // namespace rtc
diff --git a/webrtc/p2p/base/dtlstransport.h b/webrtc/p2p/base/dtlstransport.h
index 9559c1e..c448eb1 100644
--- a/webrtc/p2p/base/dtlstransport.h
+++ b/webrtc/p2p/base/dtlstransport.h
@@ -11,7 +11,6 @@
#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"
@@ -23,33 +22,31 @@
class PortAllocator;
-// Base should be a descendant of cricket::Transport
-// TODO(hbos): Add appropriate RTC_DCHECK thread checks to all methods.
+// 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.
template<class Base>
class DtlsTransport : public Base {
public:
- DtlsTransport(rtc::Thread* signaling_thread,
- rtc::Thread* worker_thread,
- const std::string& content_name,
+ DtlsTransport(const std::string& name,
PortAllocator* allocator,
const rtc::scoped_refptr<rtc::RTCCertificate>& certificate)
- : Base(signaling_thread, worker_thread, content_name, allocator),
+ : Base(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 SetCertificate_w(
+
+ void SetLocalCertificate(
const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) override {
- RTC_DCHECK(Base::worker_thread()->IsCurrent());
certificate_ = certificate;
}
- bool GetCertificate_w(
+ bool GetLocalCertificate(
rtc::scoped_refptr<rtc::RTCCertificate>* certificate) override {
- RTC_DCHECK(Base::worker_thread()->IsCurrent());
if (!certificate_)
return false;
@@ -57,15 +54,13 @@
return true;
}
- bool SetSslMaxProtocolVersion_w(rtc::SSLProtocolVersion version) override {
- RTC_DCHECK(Base::worker_thread()->IsCurrent());
+ bool SetSslMaxProtocolVersion(rtc::SSLProtocolVersion version) override {
ssl_max_version_ = version;
return true;
}
- bool ApplyLocalTransportDescription_w(TransportChannelImpl* channel,
- std::string* error_desc) override {
- RTC_DCHECK(Base::worker_thread()->IsCurrent());
+ bool ApplyLocalTransportDescription(TransportChannelImpl* channel,
+ std::string* error_desc) override {
rtc::SSLFingerprint* local_fp =
Base::local_description()->identity_fingerprint.get();
@@ -98,12 +93,11 @@
}
// Apply the description in the base class.
- return Base::ApplyLocalTransportDescription_w(channel, error_desc);
+ return Base::ApplyLocalTransportDescription(channel, error_desc);
}
- bool NegotiateTransportDescription_w(ContentAction local_role,
- std::string* error_desc) override {
- RTC_DCHECK(Base::worker_thread()->IsCurrent());
+ bool NegotiateTransportDescription(ContentAction local_role,
+ std::string* error_desc) override {
if (!Base::local_description() || !Base::remote_description()) {
const std::string msg = "Local and Remote description must be set before "
"transport descriptions are negotiated";
@@ -200,7 +194,7 @@
}
// Now run the negotiation for the base class.
- return Base::NegotiateTransportDescription_w(local_role, error_desc);
+ return Base::NegotiateTransportDescription(local_role, error_desc);
}
DtlsTransportChannelWrapper* CreateTransportChannel(int component) override {
@@ -219,18 +213,15 @@
Base::DestroyTransportChannel(base_channel);
}
- bool GetSslRole_w(rtc::SSLRole* ssl_role) const override {
- RTC_DCHECK(Base::worker_thread()->IsCurrent());
+ bool GetSslRole(rtc::SSLRole* ssl_role) const override {
ASSERT(ssl_role != NULL);
*ssl_role = secure_role_;
return true;
}
private:
- bool ApplyNegotiatedTransportDescription_w(
- TransportChannelImpl* channel,
- std::string* error_desc) override {
- RTC_DCHECK(Base::worker_thread()->IsCurrent());
+ bool ApplyNegotiatedTransportDescription(TransportChannelImpl* channel,
+ std::string* error_desc) override {
// Set ssl role. Role must be set before fingerprint is applied, which
// initiates DTLS setup.
if (!channel->SetSslRole(secure_role_)) {
@@ -245,7 +236,7 @@
return BadTransportDescription("Failed to apply remote fingerprint.",
error_desc);
}
- return Base::ApplyNegotiatedTransportDescription_w(channel, error_desc);
+ return Base::ApplyNegotiatedTransportDescription(channel, error_desc);
}
rtc::scoped_refptr<rtc::RTCCertificate> certificate_;
diff --git a/webrtc/p2p/base/dtlstransportchannel.cc b/webrtc/p2p/base/dtlstransportchannel.cc
index dcebdee..b434d08 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->content_name(), channel->component()),
+ Transport* transport,
+ TransportChannelImpl* channel)
+ : TransportChannelImpl(channel->transport_name(), channel->component()),
transport_(transport),
worker_thread_(rtc::Thread::Current()),
channel_(channel),
@@ -103,12 +103,10 @@
&DtlsTransportChannelWrapper::OnReadPacket);
channel_->SignalReadyToSend.connect(this,
&DtlsTransportChannelWrapper::OnReadyToSend);
- channel_->SignalRequestSignaling.connect(this,
- &DtlsTransportChannelWrapper::OnRequestSignaling);
- channel_->SignalCandidateReady.connect(this,
- &DtlsTransportChannelWrapper::OnCandidateReady);
- channel_->SignalCandidatesAllocationDone.connect(this,
- &DtlsTransportChannelWrapper::OnCandidatesAllocationDone);
+ channel_->SignalGatheringState.connect(
+ this, &DtlsTransportChannelWrapper::OnGatheringState);
+ channel_->SignalCandidateGathered.connect(
+ this, &DtlsTransportChannelWrapper::OnCandidateGathered);
channel_->SignalRoleConflict.connect(this,
&DtlsTransportChannelWrapper::OnRoleConflict);
channel_->SignalRouteChange.connect(this,
@@ -211,7 +209,7 @@
return true;
}
- // Allow SetRemoteFingerprint with a NULL digest even if SetLocalIdentity
+ // Allow SetRemoteFingerprint with a NULL digest even if SetLocalCertificate
// hasn't been called.
if (dtls_state_ > STATE_OFFERED ||
(dtls_state_ == STATE_NONE && !digest_alg.empty())) {
@@ -591,22 +589,17 @@
return downward_->OnPacketReceived(data, size);
}
-void DtlsTransportChannelWrapper::OnRequestSignaling(
+void DtlsTransportChannelWrapper::OnGatheringState(
TransportChannelImpl* channel) {
ASSERT(channel == channel_);
- SignalRequestSignaling(this);
+ SignalGatheringState(this);
}
-void DtlsTransportChannelWrapper::OnCandidateReady(
- TransportChannelImpl* channel, const Candidate& c) {
+void DtlsTransportChannelWrapper::OnCandidateGathered(
+ TransportChannelImpl* channel,
+ const Candidate& c) {
ASSERT(channel == channel_);
- SignalCandidateReady(this, c);
-}
-
-void DtlsTransportChannelWrapper::OnCandidatesAllocationDone(
- TransportChannelImpl* channel) {
- ASSERT(channel == channel_);
- SignalCandidatesAllocationDone(this);
+ SignalCandidateGathered(this, c);
}
void DtlsTransportChannelWrapper::OnRoleConflict(
diff --git a/webrtc/p2p/base/dtlstransportchannel.h b/webrtc/p2p/base/dtlstransportchannel.h
index ddedcbc..ea6a579 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:
- StreamInterfaceChannel(TransportChannel* channel);
+ explicit StreamInterfaceChannel(TransportChannel* channel);
// Push in a packet; this gets pulled out from Read().
bool OnPacketReceived(const char* data, size_t size);
@@ -35,10 +35,14 @@
// 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
@@ -93,12 +97,8 @@
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,7 +109,8 @@
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;
@@ -120,15 +121,11 @@
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);
@@ -168,9 +165,7 @@
}
// TransportChannelImpl calls.
- Transport* GetTransport() override {
- return transport_;
- }
+ Transport* GetTransport() override { return transport_; }
TransportChannelState GetState() const override {
return channel_->GetState();
@@ -192,11 +187,14 @@
void Connect() override;
- void OnSignalingReady() override {
- channel_->OnSignalingReady();
+ void MaybeStartGathering() override { channel_->MaybeStartGathering(); }
+
+ IceGatheringState gathering_state() const override {
+ return channel_->gathering_state();
}
- void OnCandidate(const Candidate& candidate) override {
- channel_->OnCandidate(candidate);
+
+ void AddRemoteCandidate(const Candidate& candidate) override {
+ channel_->AddRemoteCandidate(candidate);
}
void SetReceivingTimeout(int receiving_timeout_ms) override {
@@ -217,9 +215,8 @@
bool SetupDtls();
bool MaybeStartDtls();
bool HandleDtlsPacket(const char* data, size_t size);
- void OnRequestSignaling(TransportChannelImpl* channel);
- void OnCandidateReady(TransportChannelImpl* channel, const Candidate& c);
- void OnCandidatesAllocationDone(TransportChannelImpl* channel);
+ void OnGatheringState(TransportChannelImpl* channel);
+ void OnCandidateGathered(TransportChannelImpl* channel, const Candidate& c);
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 10640f9..95696e2 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/fakesession.h"
+#include "webrtc/p2p/base/faketransportcontroller.h"
#include "webrtc/base/common.h"
#include "webrtc/base/dscp.h"
#include "webrtc/base/gunit.h"
@@ -21,7 +21,6 @@
#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())) { \
@@ -45,19 +44,14 @@
class DtlsTestClient : public sigslot::has_slots<> {
public:
- 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) {
- }
+ 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) {}
void CreateCertificate(rtc::KeyType key_type) {
certificate_ = rtc::RTCCertificate::Create(
rtc::scoped_ptr<rtc::SSLIdentity>(
@@ -71,13 +65,12 @@
use_dtls_srtp_ = true;
}
void SetupMaxProtocolVersion(rtc::SSLProtocolVersion version) {
- ASSERT(transport_.get() == NULL);
+ ASSERT(!transport_);
ssl_max_version_ = version;
}
void SetupChannels(int count, cricket::IceRole role) {
transport_.reset(new cricket::DtlsTransport<cricket::FakeTransport>(
- signaling_thread_, worker_thread_, "dtls content name", nullptr,
- certificate_));
+ "dtls content name", nullptr, certificate_));
transport_->SetAsync(true);
transport_->SetIceRole(role);
transport_->SetIceTiebreaker(
@@ -118,8 +111,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).
@@ -163,18 +156,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) ?
- NULL : local_fingerprint.get(),
+ (action == cricket::CA_ANSWER && !remote_cert)
+ ? nullptr
+ : 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
@@ -199,7 +192,9 @@
return true;
}
- bool writable() const { return transport_->writable(); }
+ bool all_channels_writable() const {
+ return transport_->all_channels_writable();
+ }
void CheckRole(rtc::SSLRole role) {
if (role == rtc::SSL_CLIENT) {
@@ -337,8 +332,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);
}
@@ -372,8 +367,6 @@
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_;
@@ -389,16 +382,13 @@
class DtlsTransportChannelTest : public testing::Test {
public:
- 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) {
- }
+ DtlsTransportChannelTest()
+ : client1_("P1"),
+ client2_("P2"),
+ 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);
@@ -440,8 +430,10 @@
if (!rv)
return false;
- EXPECT_TRUE_WAIT(client1_.writable() && client2_.writable(), 10000);
- if (!client1_.writable() || !client2_.writable())
+ EXPECT_TRUE_WAIT(
+ client1_.all_channels_writable() && client2_.all_channels_writable(),
+ 10000);
+ if (!client1_.all_channels_writable() || !client2_.all_channels_writable())
return false;
// Check that we used the right roles.
@@ -818,7 +810,9 @@
cricket::CONNECTIONROLE_ACTIVE, NF_REOFFER);
bool rv = client1_.Connect(&client2_);
EXPECT_TRUE(rv);
- EXPECT_TRUE_WAIT(client1_.writable() && client2_.writable(), 10000);
+ EXPECT_TRUE_WAIT(
+ client1_.all_channels_writable() && client2_.all_channels_writable(),
+ 10000);
TestTransfer(0, 1000, 100, true);
TestTransfer(1, 1000, 100, true);
@@ -837,8 +831,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()->GetCertificate(&certificate1));
- ASSERT_TRUE(client2_.transport()->GetCertificate(&certificate2));
+ ASSERT_TRUE(client1_.transport()->GetLocalCertificate(&certificate1));
+ ASSERT_TRUE(client2_.transport()->GetLocalCertificate(&certificate2));
ASSERT_NE(certificate1->ssl_certificate().ToPEMString(),
certificate2->ssl_certificate().ToPEMString());
ASSERT_FALSE(
@@ -861,8 +855,8 @@
rtc::scoped_ptr<rtc::SSLCertificate> remote_cert2;
// After connection, each side has a distinct local certificate.
- ASSERT_TRUE(client1_.transport()->GetCertificate(&certificate1));
- ASSERT_TRUE(client2_.transport()->GetCertificate(&certificate2));
+ ASSERT_TRUE(client1_.transport()->GetLocalCertificate(&certificate1));
+ ASSERT_TRUE(client2_.transport()->GetLocalCertificate(&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
deleted file mode 100644
index bd3c089..0000000
--- a/webrtc/p2p/base/fakesession.h
+++ /dev/null
@@ -1,506 +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_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
new file mode 100644
index 0000000..e356e81
--- /dev/null
+++ b/webrtc/p2p/base/faketransportcontroller.h
@@ -0,0 +1,537 @@
+/*
+ * 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;
+ }
+ }
+
+ void MaybeStartGathering() override {
+ if (gathering_state_ == kIceGatheringNew) {
+ 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();
+ transport->MaybeStartGathering();
+ }
+ }
+
+ 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 b919fde..abc4c14 100644
--- a/webrtc/p2p/base/p2ptransport.cc
+++ b/webrtc/p2p/base/p2ptransport.cc
@@ -20,21 +20,15 @@
namespace cricket {
-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(const std::string& name, PortAllocator* allocator)
+ : Transport(name, allocator) {}
P2PTransport::~P2PTransport() {
DestroyAllChannels();
}
TransportChannelImpl* P2PTransport::CreateTransportChannel(int component) {
- return new P2PTransportChannel(content_name(), component, this,
- port_allocator());
+ return new P2PTransportChannel(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 2e27bd8..0f965b4 100644
--- a/webrtc/p2p/base/p2ptransport.h
+++ b/webrtc/p2p/base/p2ptransport.h
@@ -16,12 +16,10 @@
namespace cricket {
+// Everything in this class should be called on the worker thread.
class P2PTransport : public Transport {
public:
- P2PTransport(rtc::Thread* signaling_thread,
- rtc::Thread* worker_thread,
- const std::string& content_name,
- PortAllocator* allocator);
+ P2PTransport(const std::string& name, PortAllocator* allocator);
virtual ~P2PTransport();
protected:
diff --git a/webrtc/p2p/base/p2ptransportchannel.cc b/webrtc/p2p/base/p2ptransportchannel.cc
index ee99060..e7f5c94 100644
--- a/webrtc/p2p/base/p2ptransportchannel.cc
+++ b/webrtc/p2p/base/p2ptransportchannel.cc
@@ -11,6 +11,7 @@
#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.
@@ -169,28 +170,27 @@
namespace cricket {
-P2PTransportChannel::P2PTransportChannel(const std::string& content_name,
+P2PTransportChannel::P2PTransportChannel(const std::string& transport_name,
int component,
P2PTransport* transport,
- 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) {
-}
+ 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) {}
P2PTransportChannel::~P2PTransportChannel() {
ASSERT(worker_thread_ == rtc::Thread::Current());
@@ -231,6 +231,7 @@
connection->SignalDestroyed.connect(
this, &P2PTransportChannel::OnConnectionDestroyed);
connection->SignalNominated.connect(this, &P2PTransportChannel::OnNominated);
+ had_connection_ = true;
}
void P2PTransportChannel::SetIceRole(IceRole ice_role) {
@@ -265,8 +266,9 @@
TransportChannelState P2PTransportChannel::GetState() const {
std::set<rtc::Network*> networks;
- if (connections_.size() == 0) {
- return TransportChannelState::STATE_FAILED;
+ if (connections_.empty()) {
+ return had_connection_ ? TransportChannelState::STATE_FAILED
+ : TransportChannelState::STATE_INIT;
}
for (uint32 i = 0; i < connections_.size(); ++i) {
@@ -288,21 +290,10 @@
void P2PTransportChannel::SetIceCredentials(const std::string& ice_ufrag,
const std::string& ice_pwd) {
ASSERT(worker_thread_ == rtc::Thread::Current());
- bool ice_restart = false;
- if (!ice_ufrag_.empty() && !ice_pwd_.empty()) {
- // Restart candidate allocation if there is any change in either
- // ice ufrag or password.
- ice_restart =
- IceCredentialsChanged(ice_ufrag_, ice_pwd_, ice_ufrag, ice_pwd);
- }
-
ice_ufrag_ = ice_ufrag;
ice_pwd_ = ice_pwd;
-
- if (ice_restart) {
- // Restart candidate gathering.
- Allocate();
- }
+ // Note: Candidate gathering will restart when MaybeStartGathering is next
+ // called.
}
void P2PTransportChannel::SetRemoteIceCredentials(const std::string& ice_ufrag,
@@ -359,9 +350,6 @@
return;
}
- // Kick off an allocator session
- Allocate();
-
// Start pinging as the ports come in.
thread()->Post(this, MSG_PING);
@@ -369,6 +357,22 @@
check_receiving_delay_, this, MSG_CHECK_RECEIVING);
}
+void P2PTransportChannel::MaybeStartGathering() {
+ // Start gathering if we never started before, or if an ICE restart occurred.
+ if (allocator_sessions_.empty() ||
+ IceCredentialsChanged(allocator_sessions_.back()->ice_ufrag(),
+ allocator_sessions_.back()->ice_pwd(), ice_ufrag_,
+ ice_pwd_)) {
+ if (gathering_state_ != kIceGatheringGathering) {
+ gathering_state_ = kIceGatheringGathering;
+ SignalGatheringState(this);
+ }
+ // Time for a new allocator
+ AddAllocatorSession(allocator_->CreateSession(
+ SessionId(), transport_name(), component(), ice_ufrag_, ice_pwd_));
+ }
+}
+
// A new port is available, attempt to make connections for it
void P2PTransportChannel::OnPortReady(PortAllocatorSession *session,
PortInterface* port) {
@@ -413,17 +417,21 @@
// 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) {
- SignalCandidateReady(this, candidates[i]);
+ SignalCandidateGathered(this, candidates[i]);
}
}
void P2PTransportChannel::OnCandidatesAllocationDone(
PortAllocatorSession* session) {
ASSERT(worker_thread_ == rtc::Thread::Current());
- SignalCandidatesAllocationDone(this);
+ gathering_state_ = kIceGatheringComplete;
+ LOG(LS_INFO) << "P2PTransportChannel: " << transport_name() << ", component "
+ << component() << " gathering complete";
+ SignalGatheringState(this);
}
// Handle stun packets
@@ -494,8 +502,7 @@
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;
}
@@ -545,8 +552,7 @@
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,16 +581,6 @@
// 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);
@@ -606,7 +602,7 @@
}
}
-void P2PTransportChannel::OnCandidate(const Candidate& candidate) {
+void P2PTransportChannel::AddRemoteCandidate(const Candidate& candidate) {
ASSERT(worker_thread_ == rtc::Thread::Current());
uint32 generation = candidate.generation();
@@ -847,7 +843,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.receiving = connection->receiving();
@@ -881,14 +877,6 @@
return static_cast<rtc::DiffServCodePoint> (it->second);
}
-// 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.
void P2PTransportChannel::UpdateConnectionStates() {
uint32 now = rtc::Time();
@@ -1228,8 +1216,7 @@
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_) {
@@ -1311,9 +1298,10 @@
}
// 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 a8f1666..92969c8 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& content_name,
+ P2PTransportChannel(const std::string& transport_name,
int component,
P2PTransport* transport,
- PortAllocator *allocator);
- ~P2PTransportChannel() override;
+ PortAllocator* allocator);
+ virtual ~P2PTransportChannel();
// From TransportChannelImpl:
Transport* GetTransport() override { return transport_; }
@@ -69,15 +69,20 @@
const std::string& ice_pwd) override;
void SetRemoteIceMode(IceMode mode) override;
void Connect() override;
- void OnSignalingReady() override;
- void OnCandidate(const Candidate& candidate) override;
+ void MaybeStartGathering() override;
+ IceGatheringState gathering_state() const override {
+ return gathering_state_;
+ }
+ void AddRemoteCandidate(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_; }
@@ -96,13 +101,9 @@
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,14 +111,10 @@
}
// 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 {
@@ -165,7 +162,6 @@
return allocator_sessions_.back();
}
- void Allocate();
void UpdateConnectionStates();
void RequestSort();
void SortConnections();
@@ -213,7 +209,7 @@
void OnNominated(Connection* conn);
- void OnMessage(rtc::Message *pmsg) override;
+ void OnMessage(rtc::Message* pmsg) override;
void OnSort();
void OnPing();
@@ -223,10 +219,9 @@
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_;
@@ -238,6 +233,7 @@
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_;
@@ -248,6 +244,7 @@
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 d0277f4..485449f 100644
--- a/webrtc/p2p/base/p2ptransportchannel_unittest.cc
+++ b/webrtc/p2p/base/p2ptransportchannel_unittest.cc
@@ -297,10 +297,8 @@
const std::string& remote_ice_pwd) {
cricket::P2PTransportChannel* channel = new cricket::P2PTransportChannel(
"test content name", component, NULL, GetAllocator(endpoint));
- channel->SignalRequestSignaling.connect(
- this, &P2PTransportChannelTestBase::OnChannelRequestSignaling);
- channel->SignalCandidateReady.connect(this,
- &P2PTransportChannelTestBase::OnCandidate);
+ channel->SignalCandidateGathered.connect(
+ this, &P2PTransportChannelTestBase::OnCandidate);
channel->SignalReadPacket.connect(
this, &P2PTransportChannelTestBase::OnReadPacket);
channel->SignalRoleConflict.connect(
@@ -314,6 +312,7 @@
channel->SetIceRole(GetEndpoint(endpoint)->ice_role());
channel->SetIceTiebreaker(GetEndpoint(endpoint)->GetIceTiebreaker());
channel->Connect();
+ channel->MaybeStartGathering();
return channel;
}
void DestroyChannels() {
@@ -389,10 +388,9 @@
}
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
@@ -512,8 +510,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);
@@ -562,7 +560,7 @@
}
// This test waits for the transport to become receiving and writable on both
- // end points. Once they are, the end points set new local ice credentials to
+ // end points. Once they are, the end points set new local ice credentials and
// restart the ice gathering. Finally it waits for the transport to select a
// new connection using the newly generated ice candidates.
// Before calling this function the end points must be configured.
@@ -582,8 +580,10 @@
ep1_ch1()->SetIceCredentials(kIceUfrag[2], kIcePwd[2]);
ep1_ch1()->SetRemoteIceCredentials(kIceUfrag[3], kIcePwd[3]);
+ ep1_ch1()->MaybeStartGathering();
ep2_ch1()->SetIceCredentials(kIceUfrag[3], kIcePwd[3]);
ep2_ch1()->SetRemoteIceCredentials(kIceUfrag[2], kIcePwd[2]);
+ ep2_ch1()->MaybeStartGathering();
EXPECT_TRUE_WAIT_MARGIN(LocalCandidate(ep1_ch1())->generation() !=
old_local_candidate1->generation(),
@@ -626,9 +626,6 @@
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) {
@@ -669,7 +666,7 @@
}
LOG(LS_INFO) << "Candidate(" << data->channel->component() << "->"
<< rch->component() << "): " << c.ToString();
- rch->OnCandidate(c);
+ rch->AddRemoteCandidate(c);
break;
}
}
@@ -804,8 +801,10 @@
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(
@@ -821,8 +820,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);
@@ -1026,15 +1025,14 @@
// 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) \
@@ -1089,8 +1087,7 @@
// 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();
@@ -1099,8 +1096,7 @@
// 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()->receiving() && ep1_ch1()->writable() &&
@@ -1126,8 +1122,7 @@
// 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);
@@ -1171,8 +1166,7 @@
// 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);
@@ -1214,8 +1208,7 @@
// 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;
@@ -1230,8 +1223,7 @@
// 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);
@@ -1252,8 +1244,7 @@
// 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);
@@ -1414,11 +1405,10 @@
// 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);
@@ -1473,8 +1463,7 @@
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.
@@ -1560,11 +1549,12 @@
// Remove the public interface, add the alternate interface, and allocate
- // a new generation of candidates for the new interface (via Connect()).
+ // a new generation of candidates for the new interface (via
+ // MaybeStartGathering()).
LOG(LS_INFO) << "Draining...";
AddAddress(1, kAlternateAddrs[1]);
RemoveAddress(1, kPublicAddrs[1]);
- ep2_ch1()->Connect();
+ ep2_ch1()->MaybeStartGathering();
// We should switch over to use the alternate address after
// an exchange of pings.
@@ -1591,17 +1581,11 @@
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) {
@@ -1648,8 +1632,9 @@
cricket::P2PTransportChannel ch("trigger checks", 1, nullptr, &pa);
PrepareChannel(&ch);
ch.Connect();
- ch.OnCandidate(CreateCandidate("1.1.1.1", 1, 1));
- ch.OnCandidate(CreateCandidate("2.2.2.2", 2, 2));
+ ch.MaybeStartGathering();
+ ch.AddRemoteCandidate(CreateCandidate("1.1.1.1", 1, 1));
+ ch.AddRemoteCandidate(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);
@@ -1672,8 +1657,9 @@
cricket::P2PTransportChannel ch("trigger checks", 1, nullptr, &pa);
PrepareChannel(&ch);
ch.Connect();
- ch.OnCandidate(CreateCandidate("1.1.1.1", 1, 1));
- ch.OnCandidate(CreateCandidate("2.2.2.2", 2, 2));
+ ch.MaybeStartGathering();
+ ch.AddRemoteCandidate(CreateCandidate("1.1.1.1", 1, 1));
+ ch.AddRemoteCandidate(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);
@@ -1696,16 +1682,17 @@
cricket::P2PTransportChannel ch("connection resurrection", 1, nullptr, &pa);
PrepareChannel(&ch);
ch.Connect();
+ ch.MaybeStartGathering();
// Create conn1 and keep track of original candidate priority.
- ch.OnCandidate(CreateCandidate("1.1.1.1", 1, 1));
+ ch.AddRemoteCandidate(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
// receiving/writable. This will prune conn1.
- ch.OnCandidate(CreateCandidate("2.2.2.2", 2, 2));
+ ch.AddRemoteCandidate(CreateCandidate("2.2.2.2", 2, 2));
cricket::Connection* conn2 = WaitForConnectionTo(&ch, "2.2.2.2", 2);
ASSERT_TRUE(conn2 != nullptr);
conn2->ReceivedPing();
@@ -1752,7 +1739,8 @@
EXPECT_EQ(500, ch.receiving_timeout());
EXPECT_EQ(50, ch.check_receiving_delay());
ch.Connect();
- ch.OnCandidate(CreateCandidate("1.1.1.1", 1, 1));
+ ch.MaybeStartGathering();
+ ch.AddRemoteCandidate(CreateCandidate("1.1.1.1", 1, 1));
cricket::Connection* conn1 = WaitForConnectionTo(&ch, "1.1.1.1", 1);
ASSERT_TRUE(conn1 != nullptr);
@@ -1773,14 +1761,15 @@
PrepareChannel(&ch);
ch.SetIceRole(cricket::ICEROLE_CONTROLLED);
ch.Connect();
- ch.OnCandidate(CreateCandidate("1.1.1.1", 1, 1));
+ ch.MaybeStartGathering();
+ ch.AddRemoteCandidate(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.OnCandidate(CreateCandidate("2.2.2.2", 2, 10));
+ ch.AddRemoteCandidate(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());
@@ -1788,7 +1777,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.OnCandidate(CreateCandidate("3.3.3.3", 3, 1));
+ ch.AddRemoteCandidate(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.
@@ -1803,7 +1792,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.OnCandidate(CreateCandidate("4.4.4.4", 4, 100));
+ ch.AddRemoteCandidate(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());
@@ -1828,6 +1817,7 @@
PrepareChannel(&ch);
ch.SetIceRole(cricket::ICEROLE_CONTROLLED);
ch.Connect();
+ ch.MaybeStartGathering();
// A minimal STUN message with prflx priority.
cricket::IceMessage request;
request.SetType(cricket::STUN_BINDING_REQUEST);
@@ -1846,7 +1836,7 @@
EXPECT_EQ(conn1, ch.best_connection());
// Another connection is nominated via use_candidate.
- ch.OnCandidate(CreateCandidate("2.2.2.2", 2, 1));
+ ch.AddRemoteCandidate(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.
@@ -1892,7 +1882,8 @@
PrepareChannel(&ch);
ch.SetIceRole(cricket::ICEROLE_CONTROLLED);
ch.Connect();
- ch.OnCandidate(CreateCandidate("1.1.1.1", 1, 10));
+ ch.MaybeStartGathering();
+ ch.AddRemoteCandidate(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());
@@ -1900,7 +1891,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.OnCandidate(CreateCandidate("2.2.2.2", 2, 1));
+ ch.AddRemoteCandidate(CreateCandidate("2.2.2.2", 2, 1));
cricket::Connection* conn2 = WaitForConnectionTo(&ch, "2.2.2.2", 2);
ASSERT_TRUE(conn2 != nullptr);
conn2->ReceivedPing(); // Start receiving.
diff --git a/webrtc/p2p/base/portallocator.cc b/webrtc/p2p/base/portallocator.cc
index 76455b5..b97ad55 100644
--- a/webrtc/p2p/base/portallocator.cc
+++ b/webrtc/p2p/base/portallocator.cc
@@ -8,6 +8,7 @@
* be found in the AUTHORS file in the root of the source tree.
*/
+#include "webrtc/base/checks.h"
#include "webrtc/p2p/base/portallocator.h"
namespace cricket {
@@ -21,8 +22,10 @@
component_(component),
flags_(flags),
generation_(0),
- username_(ice_ufrag),
- password_(ice_pwd) {
+ ice_ufrag_(ice_ufrag),
+ ice_pwd_(ice_pwd) {
+ RTC_DCHECK(!ice_ufrag.empty());
+ RTC_DCHECK(!ice_pwd.empty());
}
PortAllocatorSession* PortAllocator::CreateSession(
diff --git a/webrtc/p2p/base/portallocator.h b/webrtc/p2p/base/portallocator.h
index b754376..6e3efa8 100644
--- a/webrtc/p2p/base/portallocator.h
+++ b/webrtc/p2p/base/portallocator.h
@@ -74,11 +74,10 @@
class PortAllocatorSession : public sigslot::has_slots<> {
public:
// Content name passed in mostly for logging and debugging.
- // TODO(mallinath) - Change username and password to ice_ufrag and ice_pwd.
PortAllocatorSession(const std::string& content_name,
int component,
- const std::string& username,
- const std::string& password,
+ const std::string& ice_ufrag,
+ const std::string& ice_pwd,
uint32 flags);
// Subclasses should clean up any ports created.
@@ -103,9 +102,14 @@
virtual void set_generation(uint32 generation) { generation_ = generation; }
sigslot::signal1<PortAllocatorSession*> SignalDestroyed;
+ const std::string& ice_ufrag() const { return ice_ufrag_; }
+ const std::string& ice_pwd() const { return ice_pwd_; }
+
protected:
- const std::string& username() const { return username_; }
- const std::string& password() const { return password_; }
+ // TODO(deadbeef): Get rid of these when everyone switches to ice_ufrag and
+ // ice_pwd.
+ const std::string& username() const { return ice_ufrag_; }
+ const std::string& password() const { return ice_pwd_; }
std::string content_name_;
int component_;
@@ -113,8 +117,8 @@
private:
uint32 flags_;
uint32 generation_;
- std::string username_;
- std::string password_;
+ std::string ice_ufrag_;
+ std::string ice_pwd_;
};
class PortAllocator : public sigslot::has_slots<> {
diff --git a/webrtc/p2p/base/session.cc b/webrtc/p2p/base/session.cc
index 23680b9..83edb63 100644
--- a/webrtc/p2p/base/session.cc
+++ b/webrtc/p2p/base/session.cc
@@ -10,11 +10,6 @@
#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"
@@ -22,266 +17,15 @@
#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:
@@ -326,7 +70,6 @@
rtc::Thread* worker_thread,
PortAllocator* port_allocator,
const std::string& sid,
- const std::string& content_type,
bool initiator)
: state_(STATE_INIT),
error_(ERROR_NONE),
@@ -334,13 +77,11 @@
worker_thread_(worker_thread),
port_allocator_(port_allocator),
sid_(sid),
- 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) {
+ transport_controller_(new TransportController(signaling_thread,
+ worker_thread,
+ port_allocator)) {
ASSERT(signaling_thread->IsCurrent());
+ set_initiator(initiator);
}
BaseSession::~BaseSession() {
@@ -350,11 +91,6 @@
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 {
@@ -384,37 +120,23 @@
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,
@@ -428,23 +150,17 @@
bool BaseSession::PushdownLocalTransportDescription(
const SessionDescription* sdesc,
ContentAction action,
- 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;
- }
+ std::string* err) {
+ ASSERT(signaling_thread()->IsCurrent());
- iter->second->ConnectChannels();
+ if (!sdesc) {
+ return false;
+ }
+
+ for (const TransportInfo& tinfo : sdesc->transport_infos()) {
+ if (!transport_controller_->SetLocalTransportDescription(
+ tinfo.content_name, tinfo.description, action, err)) {
+ return false;
}
}
@@ -454,134 +170,23 @@
bool BaseSession::PushdownRemoteTransportDescription(
const SessionDescription* sdesc,
ContentAction action,
- std::string* error_desc) {
- // Update the Transports with the right information.
- for (TransportMap::iterator iter = transports_.begin();
- iter != transports_.end(); ++iter) {
- TransportDescription tdesc;
+ std::string* err) {
+ ASSERT(signaling_thread()->IsCurrent());
- // 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;
- }
+ if (!sdesc) {
+ return false;
+ }
+
+ for (const TransportInfo& tinfo : sdesc->transport_infos()) {
+ if (!transport_controller_->SetRemoteTransportDescription(
+ tinfo.content_name, tinfo.description, action, err)) {
+ 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_) {
@@ -601,180 +206,18 @@
}
}
-void BaseSession::OnSignalingReady() {
- ASSERT(signaling_thread()->IsCurrent());
- for (TransportMap::iterator iter = transports_.begin();
- iter != transports_.end(); ++iter) {
- iter->second->OnSignalingReady();
- }
+void BaseSession::SetIceConnectionReceivingTimeout(int timeout_ms) {
+ transport_controller_->SetIceConnectionReceivingTimeout(timeout_ms);
}
-// 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::MaybeStartGathering() {
+ transport_controller_->MaybeStartGathering();
}
void BaseSession::LogState(State old_state, State new_state) {
LOG(LS_INFO) << "Session:" << id()
<< " Old state:" << StateToString(old_state)
- << " New state:" << StateToString(new_state)
- << " Type:" << content_type();
+ << " New state:" << StateToString(new_state);
}
// static
diff --git a/webrtc/p2p/base/session.h b/webrtc/p2p/base/session.h
index 8d7aa21..d8721fd 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,136 +31,8 @@
class P2PTransportChannel;
class Transport;
class TransportChannel;
-class TransportChannelProxy;
class TransportChannelImpl;
-
-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;
+class TransportController;
// Statistics for all the transports of this session.
typedef std::map<std::string, TransportStats> TransportStatsMap;
@@ -224,7 +96,6 @@
rtc::Thread* worker_thread,
PortAllocator* port_allocator,
const std::string& sid,
- const std::string& content_type,
bool initiator);
virtual ~BaseSession();
@@ -236,14 +107,6 @@
// 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;
@@ -260,6 +123,9 @@
// 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.
@@ -280,151 +146,29 @@
// 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_;
- }
+ // Start gathering candidates for any new transports, or transports doing an
+ // ICE restart.
+ void MaybeStartGathering();
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);
- protected:
- bool IsCandidateAllocationDone() const;
+ TransportController* transport_controller() {
+ return transport_controller_.get();
+ }
+ protected:
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(
@@ -434,8 +178,6 @@
const SessionDescription* sdesc, ContentAction action,
std::string* error_desc);
- void MaybeCandidateAllocationDone();
-
// Log session state.
void LogState(State old_state, State new_state);
@@ -449,21 +191,10 @@
rtc::Thread* const worker_thread_;
PortAllocator* const port_allocator_;
const std::string sid_;
- const std::string content_type_;
bool initiator_;
- rtc::scoped_refptr<rtc::RTCCertificate> certificate_;
- rtc::SSLProtocolVersion ssl_max_version_;
+ rtc::scoped_ptr<TransportController> transport_controller_;
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
deleted file mode 100644
index 3419cc3..0000000
--- a/webrtc/p2p/base/session_unittest.cc
+++ /dev/null
@@ -1,100 +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/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 d626ad3..b7aba75 100644
--- a/webrtc/p2p/base/transport.cc
+++ b/webrtc/p2p/base/transport.cc
@@ -8,6 +8,8 @@
* 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"
@@ -22,39 +24,6 @@
using rtc::Bind;
-enum {
- MSG_ONSIGNALINGREADY = 1,
- MSG_ONREMOTECANDIDATE,
- 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())
@@ -96,58 +65,59 @@
new_desc.ice_ufrag, new_desc.ice_pwd);
}
-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(const std::string& name, PortAllocator* allocator)
+ : name_(name), allocator_(allocator) {}
Transport::~Transport() {
- ASSERT(signaling_thread_->IsCurrent());
- ASSERT(destroyed_);
+ 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;
}
void Transport::SetIceRole(IceRole 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));
+ ice_role_ = role;
+ for (auto& iter : channels_) {
+ iter.second->SetIceRole(ice_role_);
+ }
}
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;
@@ -156,12 +126,6 @@
}
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);
@@ -172,35 +136,73 @@
const TransportDescription& description,
ContentAction action,
std::string* error_desc) {
- return worker_thread_->Invoke<bool>(Bind(
- &Transport::SetLocalTransportDescription_w, this,
- description, action, 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;
+ ConnectChannels();
+ }
+
+ return ret;
}
bool Transport::SetRemoteTransportDescription(
const TransportDescription& description,
ContentAction action,
std::string* error_desc) {
- return worker_thread_->Invoke<bool>(Bind(
- &Transport::SetRemoteTransportDescription_w, this,
- description, action, 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;
}
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;
@@ -216,7 +218,7 @@
// Increase the ref count.
iterator->second.AddRef();
- destroyed_ = false;
+ channels_destroyed_ = false;
if (impl_exists) {
// If this is an existing channel, we should just return it without
@@ -228,23 +230,21 @@
impl->SetIceRole(ice_role_);
impl->SetIceTiebreaker(tiebreaker_);
impl->SetReceivingTimeout(channel_receiving_timeout_);
- // TODO(ronghuawu): Change CreateChannel_w to be able to return error since
- // below Apply**Description_w calls can fail.
+ // TODO(ronghuawu): Change CreateChannel to be able to return error since
+ // below Apply**Description calls can fail.
if (local_description_)
- ApplyLocalTransportDescription_w(impl, NULL);
+ ApplyLocalTransportDescription(impl, NULL);
if (remote_description_)
- ApplyRemoteTransportDescription_w(impl, NULL);
+ ApplyRemoteTransportDescription(impl, NULL);
if (local_description_ && remote_description_)
- ApplyNegotiatedTransportDescription_w(impl, NULL);
+ ApplyNegotiatedTransportDescription(impl, NULL);
impl->SignalWritableState.connect(this, &Transport::OnChannelWritableState);
impl->SignalReceivingState.connect(this, &Transport::OnChannelReceivingState);
- impl->SignalRequestSignaling.connect(
- this, &Transport::OnChannelRequestSignaling);
- impl->SignalCandidateReady.connect(this, &Transport::OnChannelCandidateReady);
+ impl->SignalGatheringState.connect(this, &Transport::OnChannelGatheringState);
+ impl->SignalCandidateGathered.connect(this,
+ &Transport::OnChannelCandidateGathered);
impl->SignalRouteChange.connect(this, &Transport::OnChannelRouteChange);
- impl->SignalCandidatesAllocationDone.connect(
- this, &Transport::OnChannelCandidatesAllocationDone);
impl->SignalRoleConflict.connect(this, &Transport::OnRoleConflict);
impl->SignalConnectionRemoved.connect(
this, &Transport::OnChannelConnectionRemoved);
@@ -254,36 +254,22 @@
if (channels_.size() == 1) {
// If this is the first channel, then indicate that we have started
// connecting.
- signaling_thread()->Post(this, MSG_CONNECTING, NULL);
+ SignalConnecting(this);
}
}
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;
@@ -293,34 +279,30 @@
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.
- signaling_thread()->Post(this, MSG_CONNECTING, NULL);
+ SignalConnecting(this);
}
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.
+ 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;
- signaling_thread()->Post(this, MSG_CANDIDATEREADY, NULL);
if (!local_description_) {
// TOOD(mallinath) : TransportDescription(TD) shouldn't be generated here.
@@ -329,38 +311,28 @@
// Session.
// Session must generate local TD before remote candidates pushed when
// initiate request initiated by the remote.
- LOG(LS_INFO) << "Transport::ConnectChannels_w: No local description has "
+ LOG(LS_INFO) << "Transport::ConnectChannels: 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_w(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(desc, CA_OFFER, NULL);
}
- CallChannels_w(&TransportChannelImpl::Connect);
- if (!channels_.empty()) {
- signaling_thread()->Post(this, MSG_CONNECTING, NULL);
+ CallChannels(&TransportChannelImpl::Connect);
+ if (HasChannels()) {
+ SignalConnecting(this);
}
}
-void Transport::OnConnecting_s() {
- ASSERT(signaling_thread()->IsCurrent());
- SignalConnecting(this);
+void Transport::MaybeStartGathering() {
+ if (connect_requested_) {
+ CallChannels(&TransportChannelImpl::MaybeStartGathering);
+ }
}
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();
@@ -368,27 +340,15 @@
impls.push_back(iter.second.get());
}
- {
- rtc::CritScope cs(&crit_);
- channels_.clear();
+ channels_.clear();
+
+ for (TransportChannelImpl* impl : impls) {
+ DestroyTransportChannel(impl);
}
-
- for (size_t i = 0; i < impls.size(); ++i)
- DestroyTransportChannel(impls[i]);
+ channels_destroyed_ = true;
}
-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());
+void Transport::CallChannels(TransportChannelFunc func) {
for (const auto& iter : channels_) {
((iter.second.get())->*func)();
}
@@ -427,14 +387,7 @@
bool Transport::GetStats(TransportStats* stats) {
- 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->transport_name = name();
stats->channel_stats.clear();
for (auto iter : channels_) {
ChannelMapEntry& entry = iter.second;
@@ -450,82 +403,45 @@
return true;
}
-bool Transport::GetSslRole(rtc::SSLRole* ssl_role) const {
- return worker_thread_->Invoke<bool>(Bind(
- &Transport::GetSslRole_w, this, ssl_role));
-}
+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::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) {
- OnRemoteCandidate(*iter);
+ TransportChannelImpl* channel = GetChannel(iter->component());
+ if (channel != NULL) {
+ channel->AddRemoteCandidate(*iter);
+ }
}
-}
-
-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);
- }
+ return true;
}
void Transport::OnChannelWritableState(TransportChannel* channel) {
- 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);
- }
+ LOG(LS_INFO) << name() << " TransportChannel " << channel->component()
+ << " writability changed to " << channel->writable()
+ << ". Check if transport is complete.";
+ UpdateWritableState();
+ MaybeSignalCompleted();
}
void Transport::OnChannelReceivingState(TransportChannel* channel) {
- ASSERT(worker_thread()->IsCurrent());
- signaling_thread()->Post(this, MSG_RECEIVINGSTATE);
+ UpdateReceivingState();
}
-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_);
+TransportState Transport::GetTransportState(TransportStateType state_type) {
bool any = false;
bool all = !channels_.empty();
for (const auto iter : channels_) {
@@ -553,106 +469,44 @@
return TRANSPORT_STATE_NONE;
}
-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::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_s() {
- ASSERT(signaling_thread()->IsCurrent());
- LOG(LS_INFO) << "Transport: " << content_name_ << ", allocating candidates";
- SignalRequestSignaling(this);
-}
-
-void Transport::OnChannelCandidateReady(TransportChannelImpl* channel,
- const Candidate& candidate) {
+void Transport::OnChannelCandidateGathered(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_) {
- 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);
- }
+ candidates.push_back(candidate);
+ SignalCandidatesGathered(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) {
- signaling_thread_->Post(this, MSG_ROLECONFLICT);
+ SignalRoleConflict();
}
void Transport::OnChannelConnectionRemoved(TransportChannelImpl* channel) {
- ASSERT(worker_thread()->IsCurrent());
- MaybeCompleted_w();
+ LOG(LS_INFO) << name() << " TransportChannel " << channel->component()
+ << " connection removed. Check if transport is complete.";
+ MaybeSignalCompleted();
// Check if the state is now Failed.
// Failed is only available in the Controlling ICE role.
@@ -660,158 +514,97 @@
return;
}
- 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()) {
+ // Failed can only occur after candidate gathering has stopped.
+ if (channel->gathering_state() != kIceGatheringComplete) {
return;
}
if (channel->GetState() == TransportChannelState::STATE_FAILED) {
// A Transport has failed if any of its channels have no remaining
// connections.
- signaling_thread_->Post(this, MSG_FAILED);
+ SignalFailed(this);
}
}
-void Transport::MaybeCompleted_w() {
- ASSERT(worker_thread()->IsCurrent());
+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)?
+}
- // When there is no channel created yet, calling this function could fire an
- // IceConnectionCompleted event prematurely.
- if (channels_.empty()) {
- return;
+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;
}
- // 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;
+ 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.";
}
- }
-
- 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_);
+ SignalGatheringState(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::UpdateReceivingState() {
+ TransportState receiving = GetTransportState(TRANSPORT_RECEIVING_STATE);
+ if (receiving_ != receiving) {
+ receiving_ = receiving;
+ SignalReceivingState(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);
+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);
}
-
- // 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;
}
-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_w(TransportChannelImpl* ch,
- std::string* error_desc) {
- ASSERT(worker_thread()->IsCurrent());
+bool Transport::ApplyLocalTransportDescription(TransportChannelImpl* ch,
+ std::string* error_desc) {
ch->SetIceCredentials(local_description_->ice_ufrag,
local_description_->ice_pwd);
return true;
}
-bool Transport::ApplyRemoteTransportDescription_w(TransportChannelImpl* ch,
- std::string* error_desc) {
+bool Transport::ApplyRemoteTransportDescription(TransportChannelImpl* ch,
+ std::string* error_desc) {
ch->SetRemoteIceCredentials(remote_description_->ice_ufrag,
remote_description_->ice_pwd);
return true;
}
-bool Transport::ApplyNegotiatedTransportDescription_w(
- TransportChannelImpl* channel, std::string* error_desc) {
- ASSERT(worker_thread()->IsCurrent());
+bool Transport::ApplyNegotiatedTransportDescription(
+ TransportChannelImpl* channel,
+ std::string* error_desc) {
channel->SetRemoteIceMode(remote_ice_mode_);
return true;
}
-bool Transport::NegotiateTransportDescription_w(ContentAction local_role,
- std::string* error_desc) {
- ASSERT(worker_thread()->IsCurrent());
+bool Transport::NegotiateTransportDescription(ContentAction local_role,
+ std::string* error_desc) {
// TODO(ekr@rtfm.com): This is ICE-specific stuff. Refactor into
// P2PTransport.
@@ -819,7 +612,7 @@
// ice_lite, this local end point should take CONTROLLING role.
if (ice_role_ == ICEROLE_CONTROLLED &&
remote_description_->ice_mode == ICEMODE_LITE) {
- SetIceRole_w(ICEROLE_CONTROLLING);
+ SetIceRole(ICEROLE_CONTROLLING);
}
// Update remote ice_mode to all existing channels.
@@ -831,57 +624,10 @@
// creation, we have the negotiation state saved until a new
// negotiation happens.
for (auto& iter : channels_) {
- if (!ApplyNegotiatedTransportDescription_w(iter.second.get(), error_desc))
+ if (!ApplyNegotiatedTransportDescription(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_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 72a0895..cd763ab 100644
--- a/webrtc/p2p/base/transport.h
+++ b/webrtc/p2p/base/transport.h
@@ -15,15 +15,11 @@
// 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 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).
+// On Threading: Transport performs work solely on the worker thread, and so
+// its methods should only be called on the worker thread.
//
-// Note: Subclasses must call DestroyChannels() in their own constructors.
-// It is not possible to do so here because the subclass constructor will
+// Note: Subclasses must call DestroyChannels() in their own destructors.
+// It is not possible to do so here because the subclass destructor will
// already have run.
#ifndef WEBRTC_P2P_BASE_TRANSPORT_H_
@@ -36,16 +32,11 @@
#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;
@@ -54,6 +45,26 @@
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" and "receiving", we need to differentiate between
// none, all, and some.
enum TransportState {
@@ -124,7 +135,7 @@
// Information about the stats of a transport.
struct TransportStats {
- std::string content_name;
+ std::string transport_name;
TransportChannelStatsList channel_stats;
};
@@ -135,22 +146,13 @@
const std::string& new_ufrag,
const std::string& new_pwd);
-class Transport : public rtc::MessageHandler,
- public sigslot::has_slots<> {
+class Transport : public sigslot::has_slots<> {
public:
- Transport(rtc::Thread* signaling_thread,
- rtc::Thread* worker_thread,
- const std::string& content_name,
- PortAllocator* allocator);
+ Transport(const std::string& name, PortAllocator* allocator);
virtual ~Transport();
- // 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 name of this transport.
+ const std::string& name() const { return name_; }
// Returns the port allocator object for this transport.
PortAllocator* port_allocator() { return allocator_; }
@@ -172,6 +174,14 @@
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*> SignalWritableState;
sigslot::signal1<Transport*> SignalReceivingState;
@@ -190,21 +200,23 @@
void SetChannelReceivingTimeout(int timeout_ms);
// Must be called before applying local session description.
- void SetCertificate(
- const rtc::scoped_refptr<rtc::RTCCertificate>& certificate);
+ virtual void SetLocalCertificate(
+ const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) {}
- // Get a copy of the local identity provided by SetIdentity.
- bool GetCertificate(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 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));
}
@@ -212,7 +224,6 @@
void DestroyChannel(int component);
// Set the local TransportDescription to be used by TransportChannels.
- // This should be called before ConnectChannels().
bool SetLocalTransportDescription(const TransportDescription& description,
ContentAction action,
std::string* error_desc);
@@ -227,6 +238,11 @@
void ConnectChannels();
sigslot::signal1<Transport*> SignalConnecting;
+ // Tells channels to start gathering candidates if necessary.
+ // Should be called after ConnectChannels() has been called at least once,
+ // which will happen in SetLocalTransportDescription.
+ void MaybeStartGathering();
+
// Resets all of the channels back to their initial state. They are no
// longer connecting.
void ResetChannels();
@@ -236,20 +252,15 @@
bool GetStats(TransportStats* stats);
- // 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();
+ sigslot::signal1<Transport*> SignalGatheringState;
// Handles sending of ready candidates and receiving of remote candidates.
- sigslot::signal2<Transport*,
- const std::vector<Candidate>&> SignalCandidatesReady;
+ sigslot::signal2<Transport*, const std::vector<Candidate>&>
+ SignalCandidatesGathered;
- sigslot::signal1<Transport*> SignalCandidatesAllocationDone;
- void OnRemoteCandidates(const std::vector<Candidate>& candidates);
+ // Called when one or more candidates are ready from the remote peer.
+ bool AddRemoteCandidates(const std::vector<Candidate>& candidates,
+ std::string* error);
// If candidate is not acceptable, returns false and sets error.
// Call this before calling OnRemoteCandidates.
@@ -264,10 +275,12 @@
// Forwards the signal from TransportChannel to BaseSession.
sigslot::signal0<> SignalRoleConflict;
- virtual bool GetSslRole(rtc::SSLRole* ssl_role) const;
+ virtual bool GetSslRole(rtc::SSLRole* ssl_role) const { return false; }
// Must be called before channel is starting to connect.
- virtual bool SetSslMaxProtocolVersion(rtc::SSLProtocolVersion version);
+ virtual bool SetSslMaxProtocolVersion(rtc::SSLProtocolVersion version) {
+ return false;
+ }
protected:
// These are called by Create/DestroyChannel above in order to create or
@@ -275,9 +288,6 @@
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 {
@@ -290,53 +300,37 @@
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_w(TransportChannelImpl* channel,
- std::string* error_desc);
+ virtual bool ApplyLocalTransportDescription(TransportChannelImpl* channel,
+ std::string* error_desc);
// Pushes down remote ice credentials from the remote description to the
// transport channel.
- virtual bool ApplyRemoteTransportDescription_w(TransportChannelImpl* ch,
- std::string* error_desc);
+ virtual bool ApplyRemoteTransportDescription(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_w(ContentAction local_role,
- std::string* error_desc);
+ virtual bool NegotiateTransportDescription(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_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;
- }
+ virtual bool ApplyNegotiatedTransportDescription(
+ TransportChannelImpl* channel,
+ std::string* error_desc);
private:
struct ChannelMapEntry {
- ChannelMapEntry() : impl_(NULL), candidates_allocated_(false), ref_(0) {}
+ ChannelMapEntry() : impl_(NULL), ref_(0) {}
explicit ChannelMapEntry(TransportChannelImpl *impl)
: impl_(impl),
- candidates_allocated_(false),
ref_(0) {
}
@@ -349,14 +343,9 @@
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_;
- bool candidates_allocated_;
+ private:
+ TransportChannelImpl* impl_;
int ref_;
};
@@ -369,92 +358,55 @@
// Called when the receiving state of a channel changes.
void OnChannelReceivingState(TransportChannel* channel);
- // Called when a channel requests signaling.
- void OnChannelRequestSignaling(TransportChannelImpl* channel);
+ // Called when a channel starts finishes gathering candidates
+ void OnChannelGatheringState(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 OnChannelCandidateReady(TransportChannelImpl* channel,
- const Candidate& candidate);
+ void OnChannelCandidateGathered(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 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_w(TransportChannelFunc func);
+ void CallChannels(TransportChannelFunc func);
// Computes the AND and OR of the channel's read/write/receiving state
// (argument picks the operation).
- 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);
+ TransportState GetTransportState(TransportStateType type);
// Sends SignalCompleted if we are now in that state.
- void MaybeCompleted_w();
+ void MaybeSignalCompleted();
- rtc::Thread* const signaling_thread_;
- rtc::Thread* const worker_thread_;
- const std::string content_name_;
+ // Sends SignalGatheringState if gathering state changed
+ void UpdateGatheringState();
+
+ void UpdateWritableState();
+ void UpdateReceivingState();
+
+ const std::string name_;
PortAllocator* const allocator_;
- 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_;
+ 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;
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 43b761a..9febfe3 100644
--- a/webrtc/p2p/base/transport_unittest.cc
+++ b/webrtc/p2p/base/transport_unittest.cc
@@ -11,8 +11,7 @@
#include "webrtc/base/fakesslidentity.h"
#include "webrtc/base/gunit.h"
#include "webrtc/base/network.h"
-#include "webrtc/base/thread.h"
-#include "webrtc/p2p/base/fakesession.h"
+#include "webrtc/p2p/base/faketransportcontroller.h"
#include "webrtc/p2p/base/p2ptransport.h"
using cricket::Candidate;
@@ -35,9 +34,7 @@
public sigslot::has_slots<> {
public:
TransportTest()
- : thread_(rtc::Thread::Current()),
- transport_(new FakeTransport(
- thread_, thread_, "test content name", NULL)),
+ : transport_(new FakeTransport("test content name")),
channel_(NULL),
connecting_signalled_(false),
completed_(false),
@@ -73,7 +70,6 @@
failed_ = true;
}
- rtc::Thread* thread_;
rtc::scoped_ptr<FakeTransport> transport_;
FakeTransportChannel* channel_;
bool connecting_signalled_;
@@ -85,20 +81,7 @@
TEST_F(TransportTest, TestConnectChannelsDoesSignal) {
EXPECT_TRUE(SetupChannel());
transport_->ConnectChannels();
- 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_);
+ EXPECT_TRUE(connecting_signalled_);
}
// This test verifies channels are created with proper ICE
@@ -232,7 +215,7 @@
NULL));
channel_->SetConnectionCount(2);
- channel_->SignalCandidatesAllocationDone(channel_);
+ channel_->SetCandidatesGatheringComplete();
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 5d5a7c9..97a4113 100644
--- a/webrtc/p2p/base/transportchannel.cc
+++ b/webrtc/p2p/base/transportchannel.cc
@@ -18,7 +18,7 @@
const char RECEIVING_ABBREV[2] = { '_', 'R' };
const char WRITABLE_ABBREV[2] = { '_', 'W' };
std::stringstream ss;
- ss << "Channel[" << content_name_ << "|" << component_ << "|"
+ ss << "Channel[" << transport_name_ << "|" << component_ << "|"
<< RECEIVING_ABBREV[receiving_] << WRITABLE_ABBREV[writable_] << "]";
return ss.str();
}
diff --git a/webrtc/p2p/base/transportchannel.h b/webrtc/p2p/base/transportchannel.h
index f195a0e..5e7adfa 100644
--- a/webrtc/p2p/base/transportchannel.h
+++ b/webrtc/p2p/base/transportchannel.h
@@ -37,14 +37,19 @@
};
// Used to indicate channel's connection state.
-enum TransportChannelState { STATE_CONNECTING, STATE_COMPLETED, STATE_FAILED };
+enum TransportChannelState {
+ STATE_INIT,
+ STATE_CONNECTING, // Will enter this state once a connection is created
+ 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& content_name, int component)
- : content_name_(content_name),
+ explicit TransportChannel(const std::string& transport_name, int component)
+ : transport_name_(transport_name),
component_(component),
writable_(false),
receiving_(false) {}
@@ -60,7 +65,7 @@
// Returns the session id of this channel.
virtual const std::string SessionId() const { return std::string(); }
- const std::string& content_name() const { return content_name_; }
+ const std::string& transport_name() const { return transport_name_; }
int component() const { return component_; }
// Returns the states of this channel. Each time one of these states changes,
@@ -146,10 +151,9 @@
// Sets the receiving state, signaling if necessary.
void set_receiving(bool receiving);
-
private:
// Used mostly for debugging.
- std::string content_name_;
+ std::string transport_name_;
int component_;
bool writable_;
bool receiving_;
diff --git a/webrtc/p2p/base/transportchannelimpl.h b/webrtc/p2p/base/transportchannelimpl.h
index 3aca951..ddddf15 100644
--- a/webrtc/p2p/base/transportchannelimpl.h
+++ b/webrtc/p2p/base/transportchannelimpl.h
@@ -32,8 +32,9 @@
// client.
class TransportChannelImpl : public TransportChannel {
public:
- explicit TransportChannelImpl(const std::string& content_name, int component)
- : TransportChannel(content_name, component) {}
+ explicit TransportChannelImpl(const std::string& transport_name,
+ int component)
+ : TransportChannel(transport_name, component) {}
// Returns the transport that created this channel.
virtual Transport* GetTransport() = 0;
@@ -63,11 +64,11 @@
// Begins the process of attempting to make a connection to the other client.
virtual void Connect() = 0;
- // 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;
+ // Start gathering candidates if not already started, or if an ICE restart
+ // occurred.
+ virtual void MaybeStartGathering() = 0;
+
+ sigslot::signal1<TransportChannelImpl*> SignalGatheringState;
// Handles sending and receiving of candidates. The Transport
// receives the candidates and may forward them to the relevant
@@ -77,9 +78,11 @@
// 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&> SignalCandidateReady;
- virtual void OnCandidate(const Candidate& candidate) = 0;
+ sigslot::signal2<TransportChannelImpl*, const Candidate&>
+ SignalCandidateGathered;
+ virtual void AddRemoteCandidate(const Candidate& candidate) = 0;
+
+ virtual IceGatheringState gathering_state() const = 0;
// DTLS methods
virtual bool SetLocalCertificate(
@@ -92,9 +95,6 @@
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
deleted file mode 100644
index 74d1e1d..0000000
--- a/webrtc/p2p/base/transportchannelproxy.cc
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
- * 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_->SignalWritableState.connect(
- this, &TransportChannelProxy::OnWritableState);
- impl_->SignalReceivingState.connect(
- this, &TransportChannelProxy::OnReceivingState);
- 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::OnWritableState(TransportChannel* channel) {
- ASSERT(rtc::Thread::Current() == worker_thread_);
- ASSERT(channel == impl_);
- set_writable(impl_->writable());
- // Note: SignalWritableState fired by set_writable.
-}
-
-void TransportChannelProxy::OnReceivingState(TransportChannel* channel) {
- ASSERT(rtc::Thread::Current() == worker_thread_);
- ASSERT(channel == impl_);
- set_receiving(impl_->receiving());
- // Note: SignalReceivingState fired by set_receiving.
-}
-
-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 receiving or writable, push up those signals.
- set_writable(impl_ ? impl_->writable() : false);
- set_receiving(impl_ ? impl_->receiving() : false);
- }
-}
-
-} // namespace cricket
diff --git a/webrtc/p2p/base/transportchannelproxy.h b/webrtc/p2p/base/transportchannelproxy.h
deleted file mode 100644
index 80ee20a..0000000
--- a/webrtc/p2p/base/transportchannelproxy.h
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * 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 OnReceivingState(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
new file mode 100644
index 0000000..4d9e403
--- /dev/null
+++ b/webrtc/p2p/base/transportcontroller.cc
@@ -0,0 +1,575 @@
+/*
+ * 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));
+}
+
+void TransportController::MaybeStartGathering() {
+ worker_thread_->Invoke<void>(
+ rtc::Bind(&TransportController::MaybeStartGathering_w, this));
+}
+
+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);
+}
+
+void TransportController::MaybeStartGathering_w() {
+ for (const auto& kv : transports_) {
+ kv.second->MaybeStartGathering();
+ }
+}
+
+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
new file mode 100644
index 0000000..e31eb83
--- /dev/null
+++ b/webrtc/p2p/base/transportcontroller.h
@@ -0,0 +1,196 @@
+/*
+ * 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);
+ // Start gathering candidates for any new transports, or transports doing an
+ // ICE restart.
+ void MaybeStartGathering();
+ 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);
+ void MaybeStartGathering_w();
+ 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
new file mode 100644
index 0000000..c783525
--- /dev/null
+++ b/webrtc/p2p/base/transportcontroller_unittest.cc
@@ -0,0 +1,679 @@
+/*
+ * 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);
+ transport_controller_->MaybeStartGathering();
+ 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());
+ // After setting local description, we should be able to start gathering
+ // candidates.
+ transport_controller_->MaybeStartGathering();
+ 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* channel = CreateChannel("audio", 1);
+ ASSERT_NE(nullptr, channel);
+ channel->Connect();
+ channel->MaybeStartGathering();
+ // 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();
+ channel3->MaybeStartGathering();
+ 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();
+ channel1->MaybeStartGathering();
+ channel2->Connect();
+ channel2->MaybeStartGathering();
+ 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));
+ transport_controller_->MaybeStartGathering();
+
+ 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 4c701df..1ddf55d 100644
--- a/webrtc/p2p/base/transportdescriptionfactory.cc
+++ b/webrtc/p2p/base/transportdescriptionfactory.cc
@@ -14,7 +14,6 @@
#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 45c9e13..b5409f4 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/transportchannelproxy.cc',
- 'base/transportchannelproxy.h',
+ 'base/transportcontroller.cc',
+ 'base/transportcontroller.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 8c2c2b3..ba7f553 100644
--- a/webrtc/p2p/p2p_tests.gypi
+++ b/webrtc/p2p/p2p_tests.gypi
@@ -15,13 +15,12 @@
'direct_dependent_settings': {
'sources': [
'base/dtlstransportchannel_unittest.cc',
- 'base/fakesession.h',
+ 'base/faketransportcontroller.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',
@@ -30,6 +29,7 @@
'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',