2015-09-23 11:50:27 -07:00
|
|
|
/*
|
|
|
|
|
* 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.
|
|
|
|
|
*/
|
|
|
|
|
|
2017-09-29 10:51:43 -07:00
|
|
|
#include "pc/transportcontroller.h"
|
2015-09-23 11:50:27 -07:00
|
|
|
|
2015-09-30 10:32:59 -07:00
|
|
|
#include <algorithm>
|
2016-04-26 03:13:22 -07:00
|
|
|
#include <memory>
|
2015-09-30 10:32:59 -07:00
|
|
|
|
2017-09-15 06:47:31 +02:00
|
|
|
#include "p2p/base/port.h"
|
|
|
|
|
#include "rtc_base/bind.h"
|
|
|
|
|
#include "rtc_base/checks.h"
|
|
|
|
|
#include "rtc_base/thread.h"
|
2015-09-23 11:50:27 -07:00
|
|
|
|
2016-12-13 16:38:36 -08:00
|
|
|
namespace {
|
2015-09-23 11:50:27 -07:00
|
|
|
|
|
|
|
|
enum {
|
|
|
|
|
MSG_ICECONNECTIONSTATE,
|
|
|
|
|
MSG_RECEIVING,
|
|
|
|
|
MSG_ICEGATHERINGSTATE,
|
|
|
|
|
MSG_CANDIDATESGATHERED,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct CandidatesData : public rtc::MessageData {
|
|
|
|
|
CandidatesData(const std::string& transport_name,
|
2016-12-13 16:38:36 -08:00
|
|
|
const cricket::Candidates& candidates)
|
2015-09-23 11:50:27 -07:00
|
|
|
: transport_name(transport_name), candidates(candidates) {}
|
|
|
|
|
|
|
|
|
|
std::string transport_name;
|
2016-12-13 16:38:36 -08:00
|
|
|
cricket::Candidates candidates;
|
|
|
|
|
};
|
|
|
|
|
|
2017-09-29 10:51:43 -07:00
|
|
|
} // namespace
|
2016-12-13 16:38:36 -08:00
|
|
|
|
|
|
|
|
namespace cricket {
|
|
|
|
|
|
|
|
|
|
// This class groups the DTLS and ICE channels, and helps keep track of
|
|
|
|
|
// how many external objects (BaseChannels) reference each channel.
|
|
|
|
|
class TransportController::ChannelPair {
|
|
|
|
|
public:
|
|
|
|
|
// TODO(deadbeef): Change the types of |dtls| and |ice| to
|
2017-01-19 16:54:25 -08:00
|
|
|
// DtlsTransport and P2PTransportChannelWrapper, once TransportChannelImpl is
|
|
|
|
|
// removed.
|
|
|
|
|
ChannelPair(DtlsTransportInternal* dtls, IceTransportInternal* ice)
|
2016-12-13 16:38:36 -08:00
|
|
|
: ice_(ice), dtls_(dtls) {}
|
|
|
|
|
|
|
|
|
|
// Currently, all ICE-related calls still go through this DTLS channel. But
|
|
|
|
|
// that will change once we get rid of TransportChannelImpl, and the DTLS
|
|
|
|
|
// channel interface no longer includes ICE-specific methods.
|
2017-01-19 16:54:25 -08:00
|
|
|
const DtlsTransportInternal* dtls() const { return dtls_.get(); }
|
|
|
|
|
DtlsTransportInternal* dtls() { return dtls_.get(); }
|
2017-01-12 15:58:31 -08:00
|
|
|
const IceTransportInternal* ice() const { return ice_.get(); }
|
|
|
|
|
IceTransportInternal* ice() { return ice_.get(); }
|
2016-12-13 16:38:36 -08:00
|
|
|
|
|
|
|
|
private:
|
2017-01-12 15:58:31 -08:00
|
|
|
std::unique_ptr<IceTransportInternal> ice_;
|
2017-01-19 16:54:25 -08:00
|
|
|
std::unique_ptr<DtlsTransportInternal> dtls_;
|
2016-12-13 16:38:36 -08:00
|
|
|
|
|
|
|
|
RTC_DISALLOW_COPY_AND_ASSIGN(ChannelPair);
|
2015-09-23 11:50:27 -07:00
|
|
|
};
|
|
|
|
|
|
Negotiate the same SRTP crypto suites for every DTLS association formed.
Before this CL, we would negotiate:
- No crypto suites for data m= sections.
- A full set for audio m= sections.
- The full set, minus SRTP_AES128_CM_SHA1_32 for video m= sections.
However, this doesn't make sense with BUNDLE, since any DTLS
association could end up being used for any type of media. If
video is "bundled on" the audio transport (which is typical), it
will actually end up using SRTP_AES128_CM_SHA1_32.
So, this CL moves the responsibility of deciding SRTP crypto suites out
of BaseChannel and into DtlsTransport. The only two possibilities are
now "normal set" or "normal set + GCM", if enabled by the PC factory
options.
This fixes an issue (see linked bug) that was occurring when audio/video
were "bundled onto" the data transport. Since the data transport
wasn't negotiating any SRTP crypto suites, none were available to use
for audio/video, so the application would get black video/no audio.
This CL doesn't affect the SDES SRTP crypto suite negotiation;
it only affects the negotiation in the DLTS handshake, through
the use_srtp extension.
BUG=chromium:711243
Review-Url: https://codereview.webrtc.org/2815513012
Cr-Commit-Position: refs/heads/master@{#17810}
2017-04-21 03:23:33 -07:00
|
|
|
TransportController::TransportController(
|
|
|
|
|
rtc::Thread* signaling_thread,
|
|
|
|
|
rtc::Thread* network_thread,
|
|
|
|
|
PortAllocator* port_allocator,
|
|
|
|
|
bool redetermine_role_on_ice_restart,
|
|
|
|
|
const rtc::CryptoOptions& crypto_options)
|
2015-09-23 11:50:27 -07:00
|
|
|
: signaling_thread_(signaling_thread),
|
2016-05-12 09:20:31 +02:00
|
|
|
network_thread_(network_thread),
|
2016-08-26 20:59:24 -07:00
|
|
|
port_allocator_(port_allocator),
|
Negotiate the same SRTP crypto suites for every DTLS association formed.
Before this CL, we would negotiate:
- No crypto suites for data m= sections.
- A full set for audio m= sections.
- The full set, minus SRTP_AES128_CM_SHA1_32 for video m= sections.
However, this doesn't make sense with BUNDLE, since any DTLS
association could end up being used for any type of media. If
video is "bundled on" the audio transport (which is typical), it
will actually end up using SRTP_AES128_CM_SHA1_32.
So, this CL moves the responsibility of deciding SRTP crypto suites out
of BaseChannel and into DtlsTransport. The only two possibilities are
now "normal set" or "normal set + GCM", if enabled by the PC factory
options.
This fixes an issue (see linked bug) that was occurring when audio/video
were "bundled onto" the data transport. Since the data transport
wasn't negotiating any SRTP crypto suites, none were available to use
for audio/video, so the application would get black video/no audio.
This CL doesn't affect the SDES SRTP crypto suite negotiation;
it only affects the negotiation in the DLTS handshake, through
the use_srtp extension.
BUG=chromium:711243
Review-Url: https://codereview.webrtc.org/2815513012
Cr-Commit-Position: refs/heads/master@{#17810}
2017-04-21 03:23:33 -07:00
|
|
|
redetermine_role_on_ice_restart_(redetermine_role_on_ice_restart),
|
|
|
|
|
crypto_options_(crypto_options) {}
|
2015-09-23 11:50:27 -07:00
|
|
|
|
|
|
|
|
TransportController::~TransportController() {
|
2016-12-06 16:22:06 -08:00
|
|
|
// Channel destructors may try to send packets, so this needs to happen on
|
|
|
|
|
// the network thread.
|
2016-05-12 09:20:31 +02:00
|
|
|
network_thread_->Invoke<void>(
|
2016-06-10 14:17:27 -07:00
|
|
|
RTC_FROM_HERE,
|
2016-12-06 16:22:06 -08:00
|
|
|
rtc::Bind(&TransportController::DestroyAllChannels_n, this));
|
2015-09-23 11:50:27 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool TransportController::SetSslMaxProtocolVersion(
|
|
|
|
|
rtc::SSLProtocolVersion version) {
|
2016-06-10 14:17:27 -07:00
|
|
|
return network_thread_->Invoke<bool>(
|
|
|
|
|
RTC_FROM_HERE, rtc::Bind(&TransportController::SetSslMaxProtocolVersion_n,
|
|
|
|
|
this, version));
|
2015-09-23 11:50:27 -07:00
|
|
|
}
|
|
|
|
|
|
2015-09-28 07:57:34 -07:00
|
|
|
void TransportController::SetIceConfig(const IceConfig& config) {
|
2016-05-12 09:20:31 +02:00
|
|
|
network_thread_->Invoke<void>(
|
2016-06-10 14:17:27 -07:00
|
|
|
RTC_FROM_HERE,
|
2016-05-12 09:20:31 +02:00
|
|
|
rtc::Bind(&TransportController::SetIceConfig_n, this, config));
|
2015-09-23 11:50:27 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TransportController::SetIceRole(IceRole ice_role) {
|
2016-05-12 09:20:31 +02:00
|
|
|
network_thread_->Invoke<void>(
|
2016-06-10 14:17:27 -07:00
|
|
|
RTC_FROM_HERE,
|
2016-05-12 09:20:31 +02:00
|
|
|
rtc::Bind(&TransportController::SetIceRole_n, this, ice_role));
|
2015-09-23 11:50:27 -07:00
|
|
|
}
|
|
|
|
|
|
2016-12-10 13:15:33 -08:00
|
|
|
void TransportController::SetNeedsIceRestartFlag() {
|
|
|
|
|
for (auto& kv : transports_) {
|
|
|
|
|
kv.second->SetNeedsIceRestartFlag();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool TransportController::NeedsIceRestart(
|
|
|
|
|
const std::string& transport_name) const {
|
|
|
|
|
const JsepTransport* transport = GetJsepTransport(transport_name);
|
|
|
|
|
if (!transport) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return transport->NeedsIceRestart();
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-08 15:35:57 -08:00
|
|
|
bool TransportController::GetSslRole(const std::string& transport_name,
|
2016-12-06 16:22:06 -08:00
|
|
|
rtc::SSLRole* role) const {
|
2016-06-10 14:17:27 -07:00
|
|
|
return network_thread_->Invoke<bool>(
|
|
|
|
|
RTC_FROM_HERE, rtc::Bind(&TransportController::GetSslRole_n, this,
|
|
|
|
|
transport_name, role));
|
2015-09-23 11:50:27 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool TransportController::SetLocalCertificate(
|
|
|
|
|
const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) {
|
2016-06-10 14:17:27 -07:00
|
|
|
return network_thread_->Invoke<bool>(
|
|
|
|
|
RTC_FROM_HERE, rtc::Bind(&TransportController::SetLocalCertificate_n,
|
|
|
|
|
this, certificate));
|
2015-09-23 11:50:27 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool TransportController::GetLocalCertificate(
|
|
|
|
|
const std::string& transport_name,
|
2016-12-06 16:22:06 -08:00
|
|
|
rtc::scoped_refptr<rtc::RTCCertificate>* certificate) const {
|
2016-12-19 04:58:02 -08:00
|
|
|
if (network_thread_->IsCurrent()) {
|
|
|
|
|
return GetLocalCertificate_n(transport_name, certificate);
|
|
|
|
|
}
|
2016-05-12 09:20:31 +02:00
|
|
|
return network_thread_->Invoke<bool>(
|
2016-06-10 14:17:27 -07:00
|
|
|
RTC_FROM_HERE, rtc::Bind(&TransportController::GetLocalCertificate_n,
|
|
|
|
|
this, transport_name, certificate));
|
2015-09-23 11:50:27 -07:00
|
|
|
}
|
|
|
|
|
|
2016-04-26 03:13:22 -07:00
|
|
|
std::unique_ptr<rtc::SSLCertificate>
|
2016-04-06 05:15:06 -07:00
|
|
|
TransportController::GetRemoteSSLCertificate(
|
2016-12-06 16:22:06 -08:00
|
|
|
const std::string& transport_name) const {
|
2016-12-19 04:58:02 -08:00
|
|
|
if (network_thread_->IsCurrent()) {
|
|
|
|
|
return GetRemoteSSLCertificate_n(transport_name);
|
|
|
|
|
}
|
2016-05-12 09:20:31 +02:00
|
|
|
return network_thread_->Invoke<std::unique_ptr<rtc::SSLCertificate>>(
|
2016-06-10 14:17:27 -07:00
|
|
|
RTC_FROM_HERE, rtc::Bind(&TransportController::GetRemoteSSLCertificate_n,
|
|
|
|
|
this, transport_name));
|
2015-09-23 11:50:27 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool TransportController::SetLocalTransportDescription(
|
|
|
|
|
const std::string& transport_name,
|
|
|
|
|
const TransportDescription& tdesc,
|
|
|
|
|
ContentAction action,
|
|
|
|
|
std::string* err) {
|
2016-05-12 09:20:31 +02:00
|
|
|
return network_thread_->Invoke<bool>(
|
2016-06-10 14:17:27 -07:00
|
|
|
RTC_FROM_HERE,
|
2016-05-12 09:20:31 +02:00
|
|
|
rtc::Bind(&TransportController::SetLocalTransportDescription_n, this,
|
2015-09-23 11:50:27 -07:00
|
|
|
transport_name, tdesc, action, err));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool TransportController::SetRemoteTransportDescription(
|
|
|
|
|
const std::string& transport_name,
|
|
|
|
|
const TransportDescription& tdesc,
|
|
|
|
|
ContentAction action,
|
|
|
|
|
std::string* err) {
|
2016-05-12 09:20:31 +02:00
|
|
|
return network_thread_->Invoke<bool>(
|
2016-06-10 14:17:27 -07:00
|
|
|
RTC_FROM_HERE,
|
2016-05-12 09:20:31 +02:00
|
|
|
rtc::Bind(&TransportController::SetRemoteTransportDescription_n, this,
|
2015-09-23 11:50:27 -07:00
|
|
|
transport_name, tdesc, action, err));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TransportController::MaybeStartGathering() {
|
2016-05-12 09:20:31 +02:00
|
|
|
network_thread_->Invoke<void>(
|
2016-06-10 14:17:27 -07:00
|
|
|
RTC_FROM_HERE,
|
2016-05-12 09:20:31 +02:00
|
|
|
rtc::Bind(&TransportController::MaybeStartGathering_n, this));
|
2015-09-23 11:50:27 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool TransportController::AddRemoteCandidates(const std::string& transport_name,
|
|
|
|
|
const Candidates& candidates,
|
|
|
|
|
std::string* err) {
|
2016-05-12 09:20:31 +02:00
|
|
|
return network_thread_->Invoke<bool>(
|
2016-06-10 14:17:27 -07:00
|
|
|
RTC_FROM_HERE, rtc::Bind(&TransportController::AddRemoteCandidates_n,
|
|
|
|
|
this, transport_name, candidates, err));
|
2015-09-23 11:50:27 -07:00
|
|
|
}
|
|
|
|
|
|
2016-03-14 11:59:18 -07:00
|
|
|
bool TransportController::RemoveRemoteCandidates(const Candidates& candidates,
|
|
|
|
|
std::string* err) {
|
2016-06-10 14:17:27 -07:00
|
|
|
return network_thread_->Invoke<bool>(
|
|
|
|
|
RTC_FROM_HERE, rtc::Bind(&TransportController::RemoveRemoteCandidates_n,
|
|
|
|
|
this, candidates, err));
|
2016-03-14 11:59:18 -07:00
|
|
|
}
|
|
|
|
|
|
2015-09-23 11:50:27 -07:00
|
|
|
bool TransportController::ReadyForRemoteCandidates(
|
2016-12-06 16:22:06 -08:00
|
|
|
const std::string& transport_name) const {
|
2016-06-10 14:17:27 -07:00
|
|
|
return network_thread_->Invoke<bool>(
|
|
|
|
|
RTC_FROM_HERE, rtc::Bind(&TransportController::ReadyForRemoteCandidates_n,
|
|
|
|
|
this, transport_name));
|
2015-09-23 11:50:27 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool TransportController::GetStats(const std::string& transport_name,
|
|
|
|
|
TransportStats* stats) {
|
2016-12-19 04:58:02 -08:00
|
|
|
if (network_thread_->IsCurrent()) {
|
|
|
|
|
return GetStats_n(transport_name, stats);
|
|
|
|
|
}
|
2016-05-12 09:20:31 +02:00
|
|
|
return network_thread_->Invoke<bool>(
|
2016-06-10 14:17:27 -07:00
|
|
|
RTC_FROM_HERE,
|
2016-05-12 09:20:31 +02:00
|
|
|
rtc::Bind(&TransportController::GetStats_n, this, transport_name, stats));
|
2015-09-23 11:50:27 -07:00
|
|
|
}
|
|
|
|
|
|
2016-12-06 16:22:06 -08:00
|
|
|
void TransportController::SetMetricsObserver(
|
|
|
|
|
webrtc::MetricsObserverInterface* metrics_observer) {
|
|
|
|
|
return network_thread_->Invoke<void>(
|
|
|
|
|
RTC_FROM_HERE, rtc::Bind(&TransportController::SetMetricsObserver_n, this,
|
|
|
|
|
metrics_observer));
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-19 16:54:25 -08:00
|
|
|
DtlsTransportInternal* TransportController::CreateDtlsTransport(
|
2017-01-12 19:37:48 -08:00
|
|
|
const std::string& transport_name,
|
|
|
|
|
int component) {
|
2017-01-19 16:54:25 -08:00
|
|
|
return network_thread_->Invoke<DtlsTransportInternal*>(
|
|
|
|
|
RTC_FROM_HERE, rtc::Bind(&TransportController::CreateDtlsTransport_n,
|
2017-01-12 19:37:48 -08:00
|
|
|
this, transport_name, component));
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-19 16:54:25 -08:00
|
|
|
DtlsTransportInternal* TransportController::CreateDtlsTransport_n(
|
2015-09-23 11:50:27 -07:00
|
|
|
const std::string& transport_name,
|
|
|
|
|
int component) {
|
2016-05-12 09:20:31 +02:00
|
|
|
RTC_DCHECK(network_thread_->IsCurrent());
|
2015-09-23 11:50:27 -07:00
|
|
|
|
2016-12-06 16:22:06 -08:00
|
|
|
RefCountedChannel* existing_channel = GetChannel_n(transport_name, component);
|
|
|
|
|
if (existing_channel) {
|
2015-09-30 10:32:59 -07:00
|
|
|
// Channel already exists; increment reference count and return.
|
2016-12-06 16:22:06 -08:00
|
|
|
existing_channel->AddRef();
|
|
|
|
|
return existing_channel->dtls();
|
2015-09-30 10:32:59 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Need to create a new channel.
|
2016-12-10 13:15:33 -08:00
|
|
|
JsepTransport* transport = GetOrCreateJsepTransport(transport_name);
|
2016-12-06 16:22:06 -08:00
|
|
|
|
|
|
|
|
// Create DTLS channel wrapping ICE channel, and configure it.
|
2017-01-12 15:58:31 -08:00
|
|
|
IceTransportInternal* ice =
|
2016-12-06 16:22:06 -08:00
|
|
|
CreateIceTransportChannel_n(transport_name, component);
|
2017-01-19 16:54:25 -08:00
|
|
|
DtlsTransportInternal* dtls =
|
2016-12-06 16:22:06 -08:00
|
|
|
CreateDtlsTransportChannel_n(transport_name, component, ice);
|
2017-01-19 16:54:25 -08:00
|
|
|
dtls->ice_transport()->SetMetricsObserver(metrics_observer_);
|
|
|
|
|
dtls->ice_transport()->SetIceRole(ice_role_);
|
|
|
|
|
dtls->ice_transport()->SetIceTiebreaker(ice_tiebreaker_);
|
|
|
|
|
dtls->ice_transport()->SetIceConfig(ice_config_);
|
2017-09-19 13:47:59 -07:00
|
|
|
if (certificate_) {
|
|
|
|
|
bool set_cert_success = dtls->SetLocalCertificate(certificate_);
|
|
|
|
|
RTC_DCHECK(set_cert_success);
|
|
|
|
|
}
|
2016-12-06 16:22:06 -08:00
|
|
|
|
|
|
|
|
// Connect to signals offered by the channels. Currently, the DTLS channel
|
|
|
|
|
// forwards signals from the ICE channel, so we only need to connect to the
|
|
|
|
|
// DTLS channel. In the future this won't be the case.
|
|
|
|
|
dtls->SignalWritableState.connect(
|
2016-05-12 09:20:31 +02:00
|
|
|
this, &TransportController::OnChannelWritableState_n);
|
2016-12-06 16:22:06 -08:00
|
|
|
dtls->SignalReceivingState.connect(
|
2016-05-12 09:20:31 +02:00
|
|
|
this, &TransportController::OnChannelReceivingState_n);
|
2017-01-19 16:54:25 -08:00
|
|
|
dtls->SignalDtlsHandshakeError.connect(
|
|
|
|
|
this, &TransportController::OnDtlsHandshakeError);
|
|
|
|
|
dtls->ice_transport()->SignalGatheringState.connect(
|
2016-05-12 09:20:31 +02:00
|
|
|
this, &TransportController::OnChannelGatheringState_n);
|
2017-01-19 16:54:25 -08:00
|
|
|
dtls->ice_transport()->SignalCandidateGathered.connect(
|
2016-05-12 09:20:31 +02:00
|
|
|
this, &TransportController::OnChannelCandidateGathered_n);
|
2017-01-19 16:54:25 -08:00
|
|
|
dtls->ice_transport()->SignalCandidatesRemoved.connect(
|
2016-05-12 09:20:31 +02:00
|
|
|
this, &TransportController::OnChannelCandidatesRemoved_n);
|
2017-01-19 16:54:25 -08:00
|
|
|
dtls->ice_transport()->SignalRoleConflict.connect(
|
2016-05-12 09:20:31 +02:00
|
|
|
this, &TransportController::OnChannelRoleConflict_n);
|
2017-01-19 16:54:25 -08:00
|
|
|
dtls->ice_transport()->SignalStateChanged.connect(
|
2016-05-24 13:15:02 -07:00
|
|
|
this, &TransportController::OnChannelStateChanged_n);
|
2016-12-13 16:38:36 -08:00
|
|
|
RefCountedChannel* new_pair = new RefCountedChannel(dtls, ice);
|
|
|
|
|
new_pair->AddRef();
|
|
|
|
|
channels_.insert(channels_.end(), new_pair);
|
2016-12-06 16:22:06 -08:00
|
|
|
bool channel_added = transport->AddChannel(dtls, component);
|
|
|
|
|
RTC_DCHECK(channel_added);
|
2015-09-30 10:32:59 -07:00
|
|
|
// Adding a channel could cause aggregate state to change.
|
2016-05-12 09:20:31 +02:00
|
|
|
UpdateAggregateStates_n();
|
2016-12-06 16:22:06 -08:00
|
|
|
return dtls;
|
2015-09-23 11:50:27 -07:00
|
|
|
}
|
|
|
|
|
|
2017-01-19 16:54:25 -08:00
|
|
|
void TransportController::DestroyDtlsTransport(
|
2017-01-17 18:32:35 -08:00
|
|
|
const std::string& transport_name,
|
|
|
|
|
int component) {
|
|
|
|
|
network_thread_->Invoke<void>(
|
2017-01-19 16:54:25 -08:00
|
|
|
RTC_FROM_HERE, rtc::Bind(&TransportController::DestroyDtlsTransport_n,
|
2017-01-17 18:32:35 -08:00
|
|
|
this, transport_name, component));
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-19 16:54:25 -08:00
|
|
|
void TransportController::DestroyDtlsTransport_n(
|
2015-09-23 11:50:27 -07:00
|
|
|
const std::string& transport_name,
|
|
|
|
|
int component) {
|
2016-05-12 09:20:31 +02:00
|
|
|
RTC_DCHECK(network_thread_->IsCurrent());
|
2016-12-06 16:22:06 -08:00
|
|
|
auto it = GetChannelIterator_n(transport_name, component);
|
2015-09-30 10:32:59 -07:00
|
|
|
if (it == channels_.end()) {
|
2017-11-09 11:09:25 +01:00
|
|
|
RTC_LOG(LS_WARNING) << "Attempting to delete " << transport_name
|
|
|
|
|
<< " TransportChannel " << component
|
|
|
|
|
<< ", which doesn't exist.";
|
2015-09-30 10:32:59 -07:00
|
|
|
return;
|
|
|
|
|
}
|
2017-10-19 13:15:17 +02:00
|
|
|
// Release one reference to the RefCountedChannel, and do additional cleanup
|
|
|
|
|
// only if it was the last one. Matches the AddRef logic in
|
|
|
|
|
// CreateDtlsTransport_n.
|
|
|
|
|
if ((*it)->Release() == rtc::RefCountReleaseStatus::kOtherRefsRemained) {
|
2015-09-23 11:50:27 -07:00
|
|
|
return;
|
|
|
|
|
}
|
2016-12-06 15:28:55 -08:00
|
|
|
channels_.erase(it);
|
2016-12-06 16:22:06 -08:00
|
|
|
|
2016-12-10 13:15:33 -08:00
|
|
|
JsepTransport* t = GetJsepTransport(transport_name);
|
2016-12-06 16:22:06 -08:00
|
|
|
bool channel_removed = t->RemoveChannel(component);
|
|
|
|
|
RTC_DCHECK(channel_removed);
|
2015-09-23 11:50:27 -07:00
|
|
|
// Just as we create a Transport when its first channel is created,
|
|
|
|
|
// we delete it when its last channel is deleted.
|
2016-12-06 16:22:06 -08:00
|
|
|
if (!t->HasChannels()) {
|
|
|
|
|
transports_.erase(transport_name);
|
2015-09-23 11:50:27 -07:00
|
|
|
}
|
2015-09-30 10:32:59 -07:00
|
|
|
// Removing a channel could cause aggregate state to change.
|
2016-05-12 09:20:31 +02:00
|
|
|
UpdateAggregateStates_n();
|
2015-09-23 11:50:27 -07:00
|
|
|
}
|
|
|
|
|
|
2016-12-06 16:22:06 -08:00
|
|
|
std::vector<std::string> TransportController::transport_names_for_testing() {
|
|
|
|
|
std::vector<std::string> ret;
|
|
|
|
|
for (const auto& kv : transports_) {
|
|
|
|
|
ret.push_back(kv.first);
|
|
|
|
|
}
|
|
|
|
|
return ret;
|
2015-09-23 11:50:27 -07:00
|
|
|
}
|
|
|
|
|
|
2017-01-19 16:54:25 -08:00
|
|
|
std::vector<DtlsTransportInternal*>
|
|
|
|
|
TransportController::channels_for_testing() {
|
|
|
|
|
std::vector<DtlsTransportInternal*> ret;
|
2016-12-13 16:38:36 -08:00
|
|
|
for (RefCountedChannel* channel : channels_) {
|
|
|
|
|
ret.push_back(channel->dtls());
|
2016-12-06 15:28:55 -08:00
|
|
|
}
|
2016-12-06 16:22:06 -08:00
|
|
|
return ret;
|
2016-12-06 14:56:17 -08:00
|
|
|
}
|
2015-09-23 11:50:27 -07:00
|
|
|
|
2017-01-19 16:54:25 -08:00
|
|
|
DtlsTransportInternal* TransportController::get_channel_for_testing(
|
2016-12-06 16:22:06 -08:00
|
|
|
const std::string& transport_name,
|
|
|
|
|
int component) {
|
|
|
|
|
RefCountedChannel* ch = GetChannel_n(transport_name, component);
|
|
|
|
|
return ch ? ch->dtls() : nullptr;
|
|
|
|
|
}
|
2016-12-06 14:56:17 -08:00
|
|
|
|
2017-01-12 15:58:31 -08:00
|
|
|
IceTransportInternal* TransportController::CreateIceTransportChannel_n(
|
2016-12-06 16:22:06 -08:00
|
|
|
const std::string& transport_name,
|
|
|
|
|
int component) {
|
|
|
|
|
return new P2PTransportChannel(transport_name, component, port_allocator_);
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-19 16:54:25 -08:00
|
|
|
DtlsTransportInternal* TransportController::CreateDtlsTransportChannel_n(
|
2016-12-06 16:22:06 -08:00
|
|
|
const std::string&,
|
|
|
|
|
int,
|
2017-01-12 15:58:31 -08:00
|
|
|
IceTransportInternal* ice) {
|
Negotiate the same SRTP crypto suites for every DTLS association formed.
Before this CL, we would negotiate:
- No crypto suites for data m= sections.
- A full set for audio m= sections.
- The full set, minus SRTP_AES128_CM_SHA1_32 for video m= sections.
However, this doesn't make sense with BUNDLE, since any DTLS
association could end up being used for any type of media. If
video is "bundled on" the audio transport (which is typical), it
will actually end up using SRTP_AES128_CM_SHA1_32.
So, this CL moves the responsibility of deciding SRTP crypto suites out
of BaseChannel and into DtlsTransport. The only two possibilities are
now "normal set" or "normal set + GCM", if enabled by the PC factory
options.
This fixes an issue (see linked bug) that was occurring when audio/video
were "bundled onto" the data transport. Since the data transport
wasn't negotiating any SRTP crypto suites, none were available to use
for audio/video, so the application would get black video/no audio.
This CL doesn't affect the SDES SRTP crypto suite negotiation;
it only affects the negotiation in the DLTS handshake, through
the use_srtp extension.
BUG=chromium:711243
Review-Url: https://codereview.webrtc.org/2815513012
Cr-Commit-Position: refs/heads/master@{#17810}
2017-04-21 03:23:33 -07:00
|
|
|
DtlsTransport* dtls = new DtlsTransport(ice, crypto_options_);
|
2016-12-06 16:22:06 -08:00
|
|
|
dtls->SetSslMaxProtocolVersion(ssl_max_version_);
|
|
|
|
|
return dtls;
|
2015-09-23 11:50:27 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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:
|
2017-01-11 05:56:46 -08:00
|
|
|
RTC_NOTREACHED();
|
2015-09-23 11:50:27 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-13 16:38:36 -08:00
|
|
|
std::vector<TransportController::RefCountedChannel*>::iterator
|
2016-12-06 16:22:06 -08:00
|
|
|
TransportController::GetChannelIterator_n(const std::string& transport_name,
|
|
|
|
|
int component) {
|
|
|
|
|
RTC_DCHECK(network_thread_->IsCurrent());
|
2016-12-13 16:38:36 -08:00
|
|
|
return std::find_if(channels_.begin(), channels_.end(),
|
|
|
|
|
[transport_name, component](RefCountedChannel* channel) {
|
|
|
|
|
return channel->dtls()->transport_name() ==
|
|
|
|
|
transport_name &&
|
|
|
|
|
channel->dtls()->component() == component;
|
|
|
|
|
});
|
2015-09-30 10:32:59 -07:00
|
|
|
}
|
|
|
|
|
|
2016-12-13 16:38:36 -08:00
|
|
|
std::vector<TransportController::RefCountedChannel*>::const_iterator
|
2016-12-06 16:22:06 -08:00
|
|
|
TransportController::GetChannelIterator_n(const std::string& transport_name,
|
|
|
|
|
int component) const {
|
2016-12-06 14:56:17 -08:00
|
|
|
RTC_DCHECK(network_thread_->IsCurrent());
|
2016-12-06 16:22:06 -08:00
|
|
|
return std::find_if(
|
|
|
|
|
channels_.begin(), channels_.end(),
|
2016-12-13 16:38:36 -08:00
|
|
|
[transport_name, component](const RefCountedChannel* channel) {
|
|
|
|
|
return channel->dtls()->transport_name() == transport_name &&
|
|
|
|
|
channel->dtls()->component() == component;
|
2016-12-06 16:22:06 -08:00
|
|
|
});
|
|
|
|
|
}
|
2015-09-23 11:50:27 -07:00
|
|
|
|
2016-12-10 13:15:33 -08:00
|
|
|
const JsepTransport* TransportController::GetJsepTransport(
|
2016-12-06 16:22:06 -08:00
|
|
|
const std::string& transport_name) const {
|
|
|
|
|
auto it = transports_.find(transport_name);
|
|
|
|
|
return (it == transports_.end()) ? nullptr : it->second.get();
|
|
|
|
|
}
|
2015-09-23 11:50:27 -07:00
|
|
|
|
2016-12-10 13:15:33 -08:00
|
|
|
JsepTransport* TransportController::GetJsepTransport(
|
2016-12-06 16:22:06 -08:00
|
|
|
const std::string& transport_name) {
|
|
|
|
|
auto it = transports_.find(transport_name);
|
|
|
|
|
return (it == transports_.end()) ? nullptr : it->second.get();
|
|
|
|
|
}
|
2016-12-06 15:28:55 -08:00
|
|
|
|
2016-12-06 16:22:06 -08:00
|
|
|
const TransportController::RefCountedChannel* TransportController::GetChannel_n(
|
|
|
|
|
const std::string& transport_name,
|
|
|
|
|
int component) const {
|
|
|
|
|
RTC_DCHECK(network_thread_->IsCurrent());
|
|
|
|
|
auto it = GetChannelIterator_n(transport_name, component);
|
2016-12-13 16:38:36 -08:00
|
|
|
return (it == channels_.end()) ? nullptr : *it;
|
2016-12-06 14:56:17 -08:00
|
|
|
}
|
|
|
|
|
|
2016-12-06 16:22:06 -08:00
|
|
|
TransportController::RefCountedChannel* TransportController::GetChannel_n(
|
|
|
|
|
const std::string& transport_name,
|
|
|
|
|
int component) {
|
|
|
|
|
RTC_DCHECK(network_thread_->IsCurrent());
|
|
|
|
|
auto it = GetChannelIterator_n(transport_name, component);
|
2016-12-13 16:38:36 -08:00
|
|
|
return (it == channels_.end()) ? nullptr : *it;
|
2016-12-06 16:22:06 -08:00
|
|
|
}
|
|
|
|
|
|
2016-12-10 13:15:33 -08:00
|
|
|
JsepTransport* TransportController::GetOrCreateJsepTransport(
|
2015-09-23 11:50:27 -07:00
|
|
|
const std::string& transport_name) {
|
2016-05-12 09:20:31 +02:00
|
|
|
RTC_DCHECK(network_thread_->IsCurrent());
|
2015-09-23 11:50:27 -07:00
|
|
|
|
2016-12-10 13:15:33 -08:00
|
|
|
JsepTransport* transport = GetJsepTransport(transport_name);
|
2016-12-06 16:22:06 -08:00
|
|
|
if (transport) {
|
|
|
|
|
return transport;
|
2015-09-23 11:50:27 -07:00
|
|
|
}
|
2016-12-06 16:22:06 -08:00
|
|
|
|
|
|
|
|
transport = new JsepTransport(transport_name, certificate_);
|
|
|
|
|
transports_[transport_name] = std::unique_ptr<JsepTransport>(transport);
|
|
|
|
|
return transport;
|
2015-09-23 11:50:27 -07:00
|
|
|
}
|
|
|
|
|
|
2016-12-06 16:22:06 -08:00
|
|
|
void TransportController::DestroyAllChannels_n() {
|
2016-05-12 09:20:31 +02:00
|
|
|
RTC_DCHECK(network_thread_->IsCurrent());
|
2015-09-23 11:50:27 -07:00
|
|
|
transports_.clear();
|
2017-10-19 13:15:17 +02:00
|
|
|
// TODO(nisse): If |channels_| were a vector of scoped_refptr, we
|
|
|
|
|
// wouldn't need this strange hack.
|
2016-12-13 16:38:36 -08:00
|
|
|
for (RefCountedChannel* channel : channels_) {
|
|
|
|
|
// Even though these objects are normally ref-counted, if
|
|
|
|
|
// TransportController is deleted while they still have references, just
|
|
|
|
|
// remove all references.
|
2017-10-19 13:15:17 +02:00
|
|
|
while (channel->Release() ==
|
|
|
|
|
rtc::RefCountReleaseStatus::kOtherRefsRemained) {
|
2016-12-13 16:38:36 -08:00
|
|
|
}
|
|
|
|
|
}
|
2016-12-06 16:22:06 -08:00
|
|
|
channels_.clear();
|
2015-09-23 11:50:27 -07:00
|
|
|
}
|
|
|
|
|
|
2016-05-12 09:20:31 +02:00
|
|
|
bool TransportController::SetSslMaxProtocolVersion_n(
|
2015-09-23 11:50:27 -07:00
|
|
|
rtc::SSLProtocolVersion version) {
|
2016-05-12 09:20:31 +02:00
|
|
|
RTC_DCHECK(network_thread_->IsCurrent());
|
2015-09-23 11:50:27 -07:00
|
|
|
|
|
|
|
|
// Max SSL version can only be set before transports are created.
|
|
|
|
|
if (!transports_.empty()) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ssl_max_version_ = version;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-12 09:20:31 +02:00
|
|
|
void TransportController::SetIceConfig_n(const IceConfig& config) {
|
|
|
|
|
RTC_DCHECK(network_thread_->IsCurrent());
|
2016-12-06 16:22:06 -08:00
|
|
|
|
2015-09-28 07:57:34 -07:00
|
|
|
ice_config_ = config;
|
2016-12-06 16:22:06 -08:00
|
|
|
for (auto& channel : channels_) {
|
2017-01-19 16:54:25 -08:00
|
|
|
channel->dtls()->ice_transport()->SetIceConfig(ice_config_);
|
2015-09-23 11:50:27 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-12 09:20:31 +02:00
|
|
|
void TransportController::SetIceRole_n(IceRole ice_role) {
|
|
|
|
|
RTC_DCHECK(network_thread_->IsCurrent());
|
2016-12-06 16:22:06 -08:00
|
|
|
|
2015-09-23 11:50:27 -07:00
|
|
|
ice_role_ = ice_role;
|
2016-12-06 16:22:06 -08:00
|
|
|
for (auto& channel : channels_) {
|
2017-01-19 16:54:25 -08:00
|
|
|
channel->dtls()->ice_transport()->SetIceRole(ice_role_);
|
2015-09-23 11:50:27 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-12 09:20:31 +02:00
|
|
|
bool TransportController::GetSslRole_n(const std::string& transport_name,
|
2016-12-06 16:22:06 -08:00
|
|
|
rtc::SSLRole* role) const {
|
2016-05-12 09:20:31 +02:00
|
|
|
RTC_DCHECK(network_thread_->IsCurrent());
|
2015-09-23 11:50:27 -07:00
|
|
|
|
2016-12-10 13:15:33 -08:00
|
|
|
const JsepTransport* t = GetJsepTransport(transport_name);
|
2016-01-08 15:35:57 -08:00
|
|
|
if (!t) {
|
2015-09-23 11:50:27 -07:00
|
|
|
return false;
|
|
|
|
|
}
|
2017-03-27 10:33:26 -07:00
|
|
|
rtc::Optional<rtc::SSLRole> current_role = t->GetSslRole();
|
|
|
|
|
if (!current_role) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
*role = *current_role;
|
2016-12-06 16:22:06 -08:00
|
|
|
return true;
|
2015-09-23 11:50:27 -07:00
|
|
|
}
|
|
|
|
|
|
2016-05-12 09:20:31 +02:00
|
|
|
bool TransportController::SetLocalCertificate_n(
|
2015-09-23 11:50:27 -07:00
|
|
|
const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) {
|
2016-05-12 09:20:31 +02:00
|
|
|
RTC_DCHECK(network_thread_->IsCurrent());
|
2015-09-23 11:50:27 -07:00
|
|
|
|
2016-12-06 16:22:06 -08:00
|
|
|
// Can't change a certificate, or set a null certificate.
|
|
|
|
|
if (certificate_ || !certificate) {
|
2015-09-23 11:50:27 -07:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
certificate_ = certificate;
|
|
|
|
|
|
2017-01-20 21:20:51 -08:00
|
|
|
// Set certificate for JsepTransport, which verifies it matches the
|
2017-09-19 13:47:59 -07:00
|
|
|
// fingerprint in SDP, and DTLS transport.
|
|
|
|
|
// Fallback from DTLS to SDES is not supported.
|
2016-12-06 16:22:06 -08:00
|
|
|
for (auto& kv : transports_) {
|
2015-09-23 11:50:27 -07:00
|
|
|
kv.second->SetLocalCertificate(certificate_);
|
|
|
|
|
}
|
2017-09-19 13:47:59 -07:00
|
|
|
for (auto& channel : channels_) {
|
|
|
|
|
bool set_cert_success = channel->dtls()->SetLocalCertificate(certificate_);
|
|
|
|
|
RTC_DCHECK(set_cert_success);
|
|
|
|
|
}
|
2015-09-23 11:50:27 -07:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-12 09:20:31 +02:00
|
|
|
bool TransportController::GetLocalCertificate_n(
|
2015-09-23 11:50:27 -07:00
|
|
|
const std::string& transport_name,
|
2016-12-06 16:22:06 -08:00
|
|
|
rtc::scoped_refptr<rtc::RTCCertificate>* certificate) const {
|
2016-05-12 09:20:31 +02:00
|
|
|
RTC_DCHECK(network_thread_->IsCurrent());
|
2015-09-23 11:50:27 -07:00
|
|
|
|
2016-12-10 13:15:33 -08:00
|
|
|
const JsepTransport* t = GetJsepTransport(transport_name);
|
2015-09-23 11:50:27 -07:00
|
|
|
if (!t) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return t->GetLocalCertificate(certificate);
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-26 03:13:22 -07:00
|
|
|
std::unique_ptr<rtc::SSLCertificate>
|
2016-05-12 09:20:31 +02:00
|
|
|
TransportController::GetRemoteSSLCertificate_n(
|
2016-12-06 16:22:06 -08:00
|
|
|
const std::string& transport_name) const {
|
2016-05-12 09:20:31 +02:00
|
|
|
RTC_DCHECK(network_thread_->IsCurrent());
|
2015-09-23 11:50:27 -07:00
|
|
|
|
2016-12-06 16:22:06 -08:00
|
|
|
// Get the certificate from the RTP channel's DTLS handshake. Should be
|
|
|
|
|
// identical to the RTCP channel's, since they were given the same remote
|
|
|
|
|
// fingerprint.
|
|
|
|
|
const RefCountedChannel* ch = GetChannel_n(transport_name, 1);
|
|
|
|
|
if (!ch) {
|
2016-04-06 05:15:06 -07:00
|
|
|
return nullptr;
|
2015-09-23 11:50:27 -07:00
|
|
|
}
|
2016-12-06 16:22:06 -08:00
|
|
|
return ch->dtls()->GetRemoteSSLCertificate();
|
2015-09-23 11:50:27 -07:00
|
|
|
}
|
|
|
|
|
|
2016-05-12 09:20:31 +02:00
|
|
|
bool TransportController::SetLocalTransportDescription_n(
|
2015-09-23 11:50:27 -07:00
|
|
|
const std::string& transport_name,
|
|
|
|
|
const TransportDescription& tdesc,
|
|
|
|
|
ContentAction action,
|
|
|
|
|
std::string* err) {
|
2016-05-12 09:20:31 +02:00
|
|
|
RTC_DCHECK(network_thread_->IsCurrent());
|
2015-09-23 11:50:27 -07:00
|
|
|
|
2016-12-10 13:15:33 -08:00
|
|
|
JsepTransport* transport = GetJsepTransport(transport_name);
|
2015-09-23 11:50:27 -07:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-15 17:48:13 -07:00
|
|
|
// Older versions of Chrome expect the ICE role to be re-determined when an
|
|
|
|
|
// ICE restart occurs, and also don't perform conflict resolution correctly,
|
2016-08-26 20:59:24 -07:00
|
|
|
// so for now we can't safely stop doing this, unless the application opts in
|
|
|
|
|
// by setting |redetermine_role_on_ice_restart_| to false.
|
2016-07-15 17:48:13 -07:00
|
|
|
// See: https://bugs.chromium.org/p/chromium/issues/detail?id=628676
|
|
|
|
|
// TODO(deadbeef): Remove this when these old versions of Chrome reach a low
|
|
|
|
|
// enough population.
|
2016-08-26 20:59:24 -07:00
|
|
|
if (redetermine_role_on_ice_restart_ && transport->local_description() &&
|
2016-07-15 17:48:13 -07:00
|
|
|
IceCredentialsChanged(transport->local_description()->ice_ufrag,
|
|
|
|
|
transport->local_description()->ice_pwd,
|
2017-04-20 00:57:25 -07:00
|
|
|
tdesc.ice_ufrag, tdesc.ice_pwd) &&
|
|
|
|
|
// Don't change the ICE role if the remote endpoint is ICE lite; we
|
|
|
|
|
// should always be controlling in that case.
|
|
|
|
|
(!transport->remote_description() ||
|
|
|
|
|
transport->remote_description()->ice_mode != ICEMODE_LITE)) {
|
2016-07-15 17:48:13 -07:00
|
|
|
IceRole new_ice_role =
|
|
|
|
|
(action == CA_OFFER) ? ICEROLE_CONTROLLING : ICEROLE_CONTROLLED;
|
|
|
|
|
SetIceRole(new_ice_role);
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-09 11:09:25 +01:00
|
|
|
RTC_LOG(LS_INFO) << "Set local transport description on " << transport_name;
|
2015-09-23 11:50:27 -07:00
|
|
|
return transport->SetLocalTransportDescription(tdesc, action, err);
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-12 09:20:31 +02:00
|
|
|
bool TransportController::SetRemoteTransportDescription_n(
|
2015-09-23 11:50:27 -07:00
|
|
|
const std::string& transport_name,
|
|
|
|
|
const TransportDescription& tdesc,
|
|
|
|
|
ContentAction action,
|
|
|
|
|
std::string* err) {
|
2016-05-12 09:20:31 +02:00
|
|
|
RTC_DCHECK(network_thread_->IsCurrent());
|
2015-09-23 11:50:27 -07:00
|
|
|
|
2016-12-06 16:22:06 -08:00
|
|
|
// If our role is ICEROLE_CONTROLLED and the remote endpoint supports only
|
|
|
|
|
// ice_lite, this local endpoint should take the CONTROLLING role.
|
|
|
|
|
// TODO(deadbeef): This is a session-level attribute, so it really shouldn't
|
|
|
|
|
// be in a TransportDescription in the first place...
|
|
|
|
|
if (ice_role_ == ICEROLE_CONTROLLED && tdesc.ice_mode == ICEMODE_LITE) {
|
|
|
|
|
SetIceRole_n(ICEROLE_CONTROLLING);
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-10 13:15:33 -08:00
|
|
|
JsepTransport* transport = GetJsepTransport(transport_name);
|
2015-09-23 11:50:27 -07:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-09 11:09:25 +01:00
|
|
|
RTC_LOG(LS_INFO) << "Set remote transport description on " << transport_name;
|
2015-09-23 11:50:27 -07:00
|
|
|
return transport->SetRemoteTransportDescription(tdesc, action, err);
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-12 09:20:31 +02:00
|
|
|
void TransportController::MaybeStartGathering_n() {
|
2016-12-06 16:22:06 -08:00
|
|
|
for (auto& channel : channels_) {
|
2017-01-19 16:54:25 -08:00
|
|
|
channel->dtls()->ice_transport()->MaybeStartGathering();
|
2015-09-23 11:50:27 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-12 09:20:31 +02:00
|
|
|
bool TransportController::AddRemoteCandidates_n(
|
2015-09-23 11:50:27 -07:00
|
|
|
const std::string& transport_name,
|
|
|
|
|
const Candidates& candidates,
|
|
|
|
|
std::string* err) {
|
2016-05-12 09:20:31 +02:00
|
|
|
RTC_DCHECK(network_thread_->IsCurrent());
|
2015-09-23 11:50:27 -07:00
|
|
|
|
2016-12-06 16:22:06 -08:00
|
|
|
// Verify each candidate before passing down to the transport layer.
|
|
|
|
|
if (!VerifyCandidates(candidates, err)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-10 13:15:33 -08:00
|
|
|
JsepTransport* transport = GetJsepTransport(transport_name);
|
2015-09-23 11:50:27 -07:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-06 16:22:06 -08:00
|
|
|
for (const Candidate& candidate : candidates) {
|
|
|
|
|
RefCountedChannel* channel =
|
|
|
|
|
GetChannel_n(transport_name, candidate.component());
|
|
|
|
|
if (!channel) {
|
|
|
|
|
*err = "Candidate has an unknown component: " + candidate.ToString() +
|
|
|
|
|
" for content: " + transport_name;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2017-01-19 16:54:25 -08:00
|
|
|
channel->dtls()->ice_transport()->AddRemoteCandidate(candidate);
|
2016-12-06 16:22:06 -08:00
|
|
|
}
|
|
|
|
|
return true;
|
2015-09-23 11:50:27 -07:00
|
|
|
}
|
|
|
|
|
|
2016-05-12 09:20:31 +02:00
|
|
|
bool TransportController::RemoveRemoteCandidates_n(const Candidates& candidates,
|
2016-03-14 11:59:18 -07:00
|
|
|
std::string* err) {
|
2016-05-12 09:20:31 +02:00
|
|
|
RTC_DCHECK(network_thread_->IsCurrent());
|
2016-12-06 16:22:06 -08:00
|
|
|
|
|
|
|
|
// Verify each candidate before passing down to the transport layer.
|
|
|
|
|
if (!VerifyCandidates(candidates, err)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-14 11:59:18 -07:00
|
|
|
std::map<std::string, Candidates> candidates_by_transport_name;
|
|
|
|
|
for (const Candidate& cand : candidates) {
|
2017-10-13 11:13:35 -07:00
|
|
|
if (!cand.transport_name().empty()) {
|
|
|
|
|
candidates_by_transport_name[cand.transport_name()].push_back(cand);
|
|
|
|
|
} else {
|
2017-11-09 11:09:25 +01:00
|
|
|
RTC_LOG(LS_ERROR) << "Not removing candidate because it does not have a "
|
|
|
|
|
"transport name set: "
|
|
|
|
|
<< cand.ToString();
|
2017-10-13 11:13:35 -07:00
|
|
|
}
|
2016-03-14 11:59:18 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool result = true;
|
2016-12-06 16:22:06 -08:00
|
|
|
for (const auto& kv : candidates_by_transport_name) {
|
|
|
|
|
const std::string& transport_name = kv.first;
|
|
|
|
|
const Candidates& candidates = kv.second;
|
2016-12-10 13:15:33 -08:00
|
|
|
JsepTransport* transport = GetJsepTransport(transport_name);
|
2016-03-14 11:59:18 -07:00
|
|
|
if (!transport) {
|
|
|
|
|
// If we didn't find a transport, that's not an error;
|
|
|
|
|
// it could have been deleted as a result of bundling.
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2016-12-06 16:22:06 -08:00
|
|
|
for (const Candidate& candidate : candidates) {
|
|
|
|
|
RefCountedChannel* channel =
|
|
|
|
|
GetChannel_n(transport_name, candidate.component());
|
|
|
|
|
if (channel) {
|
2017-01-19 16:54:25 -08:00
|
|
|
channel->dtls()->ice_transport()->RemoveRemoteCandidate(candidate);
|
2016-12-06 16:22:06 -08:00
|
|
|
}
|
|
|
|
|
}
|
2016-03-14 11:59:18 -07:00
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-12 09:20:31 +02:00
|
|
|
bool TransportController::ReadyForRemoteCandidates_n(
|
2016-12-06 16:22:06 -08:00
|
|
|
const std::string& transport_name) const {
|
2016-05-12 09:20:31 +02:00
|
|
|
RTC_DCHECK(network_thread_->IsCurrent());
|
2015-09-23 11:50:27 -07:00
|
|
|
|
2016-12-10 13:15:33 -08:00
|
|
|
const JsepTransport* transport = GetJsepTransport(transport_name);
|
2015-09-23 11:50:27 -07:00
|
|
|
if (!transport) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return transport->ready_for_remote_candidates();
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-12 09:20:31 +02:00
|
|
|
bool TransportController::GetStats_n(const std::string& transport_name,
|
2015-09-23 11:50:27 -07:00
|
|
|
TransportStats* stats) {
|
2016-05-12 09:20:31 +02:00
|
|
|
RTC_DCHECK(network_thread_->IsCurrent());
|
2015-09-23 11:50:27 -07:00
|
|
|
|
2016-12-10 13:15:33 -08:00
|
|
|
JsepTransport* transport = GetJsepTransport(transport_name);
|
2015-09-23 11:50:27 -07:00
|
|
|
if (!transport) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return transport->GetStats(stats);
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-06 16:22:06 -08:00
|
|
|
void TransportController::SetMetricsObserver_n(
|
|
|
|
|
webrtc::MetricsObserverInterface* metrics_observer) {
|
|
|
|
|
RTC_DCHECK(network_thread_->IsCurrent());
|
|
|
|
|
metrics_observer_ = metrics_observer;
|
|
|
|
|
for (auto& channel : channels_) {
|
2017-01-19 16:54:25 -08:00
|
|
|
channel->dtls()->ice_transport()->SetMetricsObserver(metrics_observer);
|
2016-12-06 16:22:06 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-25 10:50:32 -07:00
|
|
|
void TransportController::OnChannelWritableState_n(
|
2017-02-10 11:31:50 -08:00
|
|
|
rtc::PacketTransportInternal* transport) {
|
2016-05-12 09:20:31 +02:00
|
|
|
RTC_DCHECK(network_thread_->IsCurrent());
|
2017-11-13 13:26:07 -08:00
|
|
|
RTC_LOG(LS_INFO) << " Transport " << transport->transport_name()
|
2017-11-09 11:09:25 +01:00
|
|
|
<< " writability changed to " << transport->writable()
|
|
|
|
|
<< ".";
|
2016-05-12 09:20:31 +02:00
|
|
|
UpdateAggregateStates_n();
|
2015-09-23 11:50:27 -07:00
|
|
|
}
|
|
|
|
|
|
2016-11-01 01:47:41 -07:00
|
|
|
void TransportController::OnChannelReceivingState_n(
|
2017-02-10 11:31:50 -08:00
|
|
|
rtc::PacketTransportInternal* transport) {
|
2016-05-12 09:20:31 +02:00
|
|
|
RTC_DCHECK(network_thread_->IsCurrent());
|
|
|
|
|
UpdateAggregateStates_n();
|
2015-09-23 11:50:27 -07:00
|
|
|
}
|
|
|
|
|
|
2016-05-12 09:20:31 +02:00
|
|
|
void TransportController::OnChannelGatheringState_n(
|
2017-01-19 16:54:25 -08:00
|
|
|
IceTransportInternal* channel) {
|
2016-05-12 09:20:31 +02:00
|
|
|
RTC_DCHECK(network_thread_->IsCurrent());
|
|
|
|
|
UpdateAggregateStates_n();
|
2015-09-23 11:50:27 -07:00
|
|
|
}
|
|
|
|
|
|
2016-05-12 09:20:31 +02:00
|
|
|
void TransportController::OnChannelCandidateGathered_n(
|
2017-01-19 16:54:25 -08:00
|
|
|
IceTransportInternal* channel,
|
2015-09-30 10:32:59 -07:00
|
|
|
const Candidate& candidate) {
|
2016-05-12 09:20:31 +02:00
|
|
|
RTC_DCHECK(network_thread_->IsCurrent());
|
2015-09-23 11:50:27 -07:00
|
|
|
|
2015-09-30 10:32:59 -07:00
|
|
|
// We should never signal peer-reflexive candidates.
|
|
|
|
|
if (candidate.type() == PRFLX_PORT_TYPE) {
|
2017-01-12 02:24:27 -08:00
|
|
|
RTC_NOTREACHED();
|
2015-09-30 10:32:59 -07:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
std::vector<Candidate> candidates;
|
|
|
|
|
candidates.push_back(candidate);
|
|
|
|
|
CandidatesData* data =
|
|
|
|
|
new CandidatesData(channel->transport_name(), candidates);
|
2016-06-10 14:17:27 -07:00
|
|
|
signaling_thread_->Post(RTC_FROM_HERE, this, MSG_CANDIDATESGATHERED, data);
|
2015-09-23 11:50:27 -07:00
|
|
|
}
|
|
|
|
|
|
2016-05-12 09:20:31 +02:00
|
|
|
void TransportController::OnChannelCandidatesRemoved_n(
|
2017-01-19 16:54:25 -08:00
|
|
|
IceTransportInternal* channel,
|
2016-03-14 11:59:18 -07:00
|
|
|
const Candidates& candidates) {
|
|
|
|
|
invoker_.AsyncInvoke<void>(
|
2016-06-10 14:17:27 -07:00
|
|
|
RTC_FROM_HERE, signaling_thread_,
|
2016-03-14 11:59:18 -07:00
|
|
|
rtc::Bind(&TransportController::OnChannelCandidatesRemoved, this,
|
|
|
|
|
candidates));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TransportController::OnChannelCandidatesRemoved(
|
|
|
|
|
const Candidates& candidates) {
|
|
|
|
|
RTC_DCHECK(signaling_thread_->IsCurrent());
|
|
|
|
|
SignalCandidatesRemoved(candidates);
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-12 09:20:31 +02:00
|
|
|
void TransportController::OnChannelRoleConflict_n(
|
2017-01-19 16:54:25 -08:00
|
|
|
IceTransportInternal* channel) {
|
2016-05-12 09:20:31 +02:00
|
|
|
RTC_DCHECK(network_thread_->IsCurrent());
|
2016-05-27 13:34:37 -07:00
|
|
|
// Note: since the role conflict is handled entirely on the network thread,
|
|
|
|
|
// we don't need to worry about role conflicts occurring on two ports at once.
|
|
|
|
|
// The first one encountered should immediately reverse the role.
|
2015-09-23 11:50:27 -07:00
|
|
|
IceRole reversed_role = (ice_role_ == ICEROLE_CONTROLLING)
|
|
|
|
|
? ICEROLE_CONTROLLED
|
|
|
|
|
: ICEROLE_CONTROLLING;
|
2017-11-09 11:09:25 +01:00
|
|
|
RTC_LOG(LS_INFO) << "Got role conflict; switching to "
|
|
|
|
|
<< (reversed_role == ICEROLE_CONTROLLING ? "controlling"
|
|
|
|
|
: "controlled")
|
|
|
|
|
<< " role.";
|
2016-05-27 13:34:37 -07:00
|
|
|
SetIceRole_n(reversed_role);
|
2015-09-23 11:50:27 -07:00
|
|
|
}
|
|
|
|
|
|
2016-05-24 13:15:02 -07:00
|
|
|
void TransportController::OnChannelStateChanged_n(
|
2017-01-19 16:54:25 -08:00
|
|
|
IceTransportInternal* channel) {
|
2016-05-12 09:20:31 +02:00
|
|
|
RTC_DCHECK(network_thread_->IsCurrent());
|
2017-11-09 11:09:25 +01:00
|
|
|
RTC_LOG(LS_INFO) << channel->transport_name() << " TransportChannel "
|
|
|
|
|
<< channel->component()
|
|
|
|
|
<< " state changed. Check if state is complete.";
|
2016-05-12 09:20:31 +02:00
|
|
|
UpdateAggregateStates_n();
|
2015-09-30 10:32:59 -07:00
|
|
|
}
|
|
|
|
|
|
2016-05-12 09:20:31 +02:00
|
|
|
void TransportController::UpdateAggregateStates_n() {
|
|
|
|
|
RTC_DCHECK(network_thread_->IsCurrent());
|
2015-09-23 11:50:27 -07:00
|
|
|
|
|
|
|
|
IceConnectionState new_connection_state = kIceConnectionConnecting;
|
|
|
|
|
IceGatheringState new_gathering_state = kIceGatheringNew;
|
|
|
|
|
bool any_receiving = false;
|
|
|
|
|
bool any_failed = false;
|
2015-09-30 10:32:59 -07:00
|
|
|
bool all_connected = !channels_.empty();
|
|
|
|
|
bool all_completed = !channels_.empty();
|
2015-09-23 11:50:27 -07:00
|
|
|
bool any_gathering = false;
|
2015-09-30 10:32:59 -07:00
|
|
|
bool all_done_gathering = !channels_.empty();
|
|
|
|
|
for (const auto& channel : channels_) {
|
2016-12-13 16:38:36 -08:00
|
|
|
any_receiving = any_receiving || channel->dtls()->receiving();
|
2017-09-29 10:51:43 -07:00
|
|
|
any_failed = any_failed || channel->dtls()->ice_transport()->GetState() ==
|
|
|
|
|
IceTransportState::STATE_FAILED;
|
2016-12-13 16:38:36 -08:00
|
|
|
all_connected = all_connected && channel->dtls()->writable();
|
2015-09-30 10:32:59 -07:00
|
|
|
all_completed =
|
2016-12-13 16:38:36 -08:00
|
|
|
all_completed && channel->dtls()->writable() &&
|
2017-01-19 16:54:25 -08:00
|
|
|
channel->dtls()->ice_transport()->GetState() ==
|
|
|
|
|
IceTransportState::STATE_COMPLETED &&
|
|
|
|
|
channel->dtls()->ice_transport()->GetIceRole() == ICEROLE_CONTROLLING &&
|
|
|
|
|
channel->dtls()->ice_transport()->gathering_state() ==
|
|
|
|
|
kIceGatheringComplete;
|
2015-09-23 11:50:27 -07:00
|
|
|
any_gathering =
|
2017-01-19 16:54:25 -08:00
|
|
|
any_gathering ||
|
|
|
|
|
channel->dtls()->ice_transport()->gathering_state() != kIceGatheringNew;
|
|
|
|
|
all_done_gathering = all_done_gathering &&
|
|
|
|
|
channel->dtls()->ice_transport()->gathering_state() ==
|
|
|
|
|
kIceGatheringComplete;
|
2015-09-23 11:50:27 -07:00
|
|
|
}
|
|
|
|
|
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(
|
2016-06-10 14:17:27 -07:00
|
|
|
RTC_FROM_HERE, this, MSG_ICECONNECTIONSTATE,
|
2015-09-23 11:50:27 -07:00
|
|
|
new rtc::TypedMessageData<IceConnectionState>(new_connection_state));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (receiving_ != any_receiving) {
|
|
|
|
|
receiving_ = any_receiving;
|
2016-06-10 14:17:27 -07:00
|
|
|
signaling_thread_->Post(RTC_FROM_HERE, this, MSG_RECEIVING,
|
2015-09-23 11:50:27 -07:00
|
|
|
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(
|
2016-06-10 14:17:27 -07:00
|
|
|
RTC_FROM_HERE, this, MSG_ICEGATHERINGSTATE,
|
2015-09-23 11:50:27 -07:00
|
|
|
new rtc::TypedMessageData<IceGatheringState>(new_gathering_state));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-26 11:25:05 -07:00
|
|
|
void TransportController::OnDtlsHandshakeError(rtc::SSLHandshakeError error) {
|
|
|
|
|
SignalDtlsHandshakeError(error);
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-23 11:50:27 -07:00
|
|
|
} // namespace cricket
|