blob: 1375ab0e59a00d060f00290dfecc9c250ce8d880 [file] [log] [blame]
Zhi Huange818b6e2018-02-22 15:26:27 -08001/*
2 * Copyright 2017 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "pc/jseptransportcontroller.h"
12
13#include <algorithm>
14#include <memory>
15#include <utility>
16
Karl Wiberg918f50c2018-07-05 11:40:33 +020017#include "absl/memory/memory.h"
Zhi Huange818b6e2018-02-22 15:26:27 -080018#include "p2p/base/port.h"
19#include "rtc_base/bind.h"
20#include "rtc_base/checks.h"
Zhi Huange818b6e2018-02-22 15:26:27 -080021#include "rtc_base/thread.h"
22
23using webrtc::SdpType;
24
25namespace {
26
27enum {
28 MSG_ICECONNECTIONSTATE,
29 MSG_ICEGATHERINGSTATE,
30 MSG_ICECANDIDATESGATHERED,
31};
32
33struct CandidatesData : public rtc::MessageData {
34 CandidatesData(const std::string& transport_name,
35 const cricket::Candidates& candidates)
36 : transport_name(transport_name), candidates(candidates) {}
37
38 std::string transport_name;
39 cricket::Candidates candidates;
40};
41
42webrtc::RTCError VerifyCandidate(const cricket::Candidate& cand) {
43 // No address zero.
44 if (cand.address().IsNil() || cand.address().IsAnyIP()) {
45 return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
46 "candidate has address of zero");
47 }
48
49 // Disallow all ports below 1024, except for 80 and 443 on public addresses.
50 int port = cand.address().port();
51 if (cand.protocol() == cricket::TCP_PROTOCOL_NAME &&
52 (cand.tcptype() == cricket::TCPTYPE_ACTIVE_STR || port == 0)) {
53 // Expected for active-only candidates per
54 // http://tools.ietf.org/html/rfc6544#section-4.5 so no error.
55 // Libjingle clients emit port 0, in "active" mode.
56 return webrtc::RTCError::OK();
57 }
58 if (port < 1024) {
59 if ((port != 80) && (port != 443)) {
60 return webrtc::RTCError(
61 webrtc::RTCErrorType::INVALID_PARAMETER,
62 "candidate has port below 1024, but not 80 or 443");
63 }
64
65 if (cand.address().IsPrivateIP()) {
66 return webrtc::RTCError(
67 webrtc::RTCErrorType::INVALID_PARAMETER,
68 "candidate has port of 80 or 443 with private IP address");
69 }
70 }
71
72 return webrtc::RTCError::OK();
73}
74
75webrtc::RTCError VerifyCandidates(const cricket::Candidates& candidates) {
76 for (const cricket::Candidate& candidate : candidates) {
77 webrtc::RTCError error = VerifyCandidate(candidate);
78 if (!error.ok()) {
79 return error;
80 }
81 }
82 return webrtc::RTCError::OK();
83}
84
85} // namespace
86
87namespace webrtc {
88
89JsepTransportController::JsepTransportController(
90 rtc::Thread* signaling_thread,
91 rtc::Thread* network_thread,
92 cricket::PortAllocator* port_allocator,
Zach Steine20867f2018-08-02 13:20:15 -070093 AsyncResolverFactory* async_resolver_factory,
Zhi Huange818b6e2018-02-22 15:26:27 -080094 Config config)
95 : signaling_thread_(signaling_thread),
96 network_thread_(network_thread),
97 port_allocator_(port_allocator),
Zach Steine20867f2018-08-02 13:20:15 -070098 async_resolver_factory_(async_resolver_factory),
Zhi Huang365381f2018-04-13 16:44:34 -070099 config_(config) {
100 // The |transport_observer| is assumed to be non-null.
101 RTC_DCHECK(config_.transport_observer);
102}
Zhi Huange818b6e2018-02-22 15:26:27 -0800103
104JsepTransportController::~JsepTransportController() {
105 // Channel destructors may try to send packets, so this needs to happen on
106 // the network thread.
107 network_thread_->Invoke<void>(
108 RTC_FROM_HERE,
109 rtc::Bind(&JsepTransportController::DestroyAllJsepTransports_n, this));
110}
111
112RTCError JsepTransportController::SetLocalDescription(
113 SdpType type,
114 const cricket::SessionDescription* description) {
115 if (!network_thread_->IsCurrent()) {
116 return network_thread_->Invoke<RTCError>(
117 RTC_FROM_HERE, [=] { return SetLocalDescription(type, description); });
118 }
119
120 if (!initial_offerer_.has_value()) {
121 initial_offerer_.emplace(type == SdpType::kOffer);
122 if (*initial_offerer_) {
123 SetIceRole_n(cricket::ICEROLE_CONTROLLING);
124 } else {
125 SetIceRole_n(cricket::ICEROLE_CONTROLLED);
126 }
127 }
128 return ApplyDescription_n(/*local=*/true, type, description);
129}
130
131RTCError JsepTransportController::SetRemoteDescription(
132 SdpType type,
133 const cricket::SessionDescription* description) {
134 if (!network_thread_->IsCurrent()) {
135 return network_thread_->Invoke<RTCError>(
136 RTC_FROM_HERE, [=] { return SetRemoteDescription(type, description); });
137 }
138
139 return ApplyDescription_n(/*local=*/false, type, description);
140}
141
142RtpTransportInternal* JsepTransportController::GetRtpTransport(
143 const std::string& mid) const {
Zhi Huange830e682018-03-30 10:48:35 -0700144 auto jsep_transport = GetJsepTransportForMid(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -0800145 if (!jsep_transport) {
146 return nullptr;
147 }
148 return jsep_transport->rtp_transport();
149}
150
151cricket::DtlsTransportInternal* JsepTransportController::GetDtlsTransport(
152 const std::string& mid) const {
Zhi Huange830e682018-03-30 10:48:35 -0700153 auto jsep_transport = GetJsepTransportForMid(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -0800154 if (!jsep_transport) {
155 return nullptr;
156 }
157 return jsep_transport->rtp_dtls_transport();
158}
159
160cricket::DtlsTransportInternal* JsepTransportController::GetRtcpDtlsTransport(
161 const std::string& mid) const {
Zhi Huange830e682018-03-30 10:48:35 -0700162 auto jsep_transport = GetJsepTransportForMid(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -0800163 if (!jsep_transport) {
164 return nullptr;
165 }
166 return jsep_transport->rtcp_dtls_transport();
167}
168
169void JsepTransportController::SetIceConfig(const cricket::IceConfig& config) {
170 if (!network_thread_->IsCurrent()) {
171 network_thread_->Invoke<void>(RTC_FROM_HERE, [&] { SetIceConfig(config); });
172 return;
173 }
174
175 ice_config_ = config;
176 for (auto& dtls : GetDtlsTransports()) {
177 dtls->ice_transport()->SetIceConfig(ice_config_);
178 }
179}
180
181void JsepTransportController::SetNeedsIceRestartFlag() {
Zhi Huange830e682018-03-30 10:48:35 -0700182 for (auto& kv : jsep_transports_by_name_) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800183 kv.second->SetNeedsIceRestartFlag();
184 }
185}
186
187bool JsepTransportController::NeedsIceRestart(
188 const std::string& transport_name) const {
Zhi Huang365381f2018-04-13 16:44:34 -0700189 const cricket::JsepTransport* transport =
Zhi Huange830e682018-03-30 10:48:35 -0700190 GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800191 if (!transport) {
192 return false;
193 }
194 return transport->needs_ice_restart();
195}
196
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200197absl::optional<rtc::SSLRole> JsepTransportController::GetDtlsRole(
Zhi Huange830e682018-03-30 10:48:35 -0700198 const std::string& mid) const {
Zhi Huange818b6e2018-02-22 15:26:27 -0800199 if (!network_thread_->IsCurrent()) {
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200200 return network_thread_->Invoke<absl::optional<rtc::SSLRole>>(
Zhi Huange830e682018-03-30 10:48:35 -0700201 RTC_FROM_HERE, [&] { return GetDtlsRole(mid); });
Zhi Huange818b6e2018-02-22 15:26:27 -0800202 }
203
Zhi Huang365381f2018-04-13 16:44:34 -0700204 const cricket::JsepTransport* t = GetJsepTransportForMid(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -0800205 if (!t) {
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200206 return absl::optional<rtc::SSLRole>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800207 }
208 return t->GetDtlsRole();
209}
210
211bool JsepTransportController::SetLocalCertificate(
212 const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) {
213 if (!network_thread_->IsCurrent()) {
214 return network_thread_->Invoke<bool>(
215 RTC_FROM_HERE, [&] { return SetLocalCertificate(certificate); });
216 }
217
218 // Can't change a certificate, or set a null certificate.
219 if (certificate_ || !certificate) {
220 return false;
221 }
222 certificate_ = certificate;
223
224 // Set certificate for JsepTransport, which verifies it matches the
225 // fingerprint in SDP, and DTLS transport.
226 // Fallback from DTLS to SDES is not supported.
Zhi Huange830e682018-03-30 10:48:35 -0700227 for (auto& kv : jsep_transports_by_name_) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800228 kv.second->SetLocalCertificate(certificate_);
229 }
230 for (auto& dtls : GetDtlsTransports()) {
231 bool set_cert_success = dtls->SetLocalCertificate(certificate_);
232 RTC_DCHECK(set_cert_success);
233 }
234 return true;
235}
236
237rtc::scoped_refptr<rtc::RTCCertificate>
238JsepTransportController::GetLocalCertificate(
239 const std::string& transport_name) const {
240 if (!network_thread_->IsCurrent()) {
241 return network_thread_->Invoke<rtc::scoped_refptr<rtc::RTCCertificate>>(
242 RTC_FROM_HERE, [&] { return GetLocalCertificate(transport_name); });
243 }
244
Zhi Huang365381f2018-04-13 16:44:34 -0700245 const cricket::JsepTransport* t = GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800246 if (!t) {
247 return nullptr;
248 }
249 return t->GetLocalCertificate();
250}
251
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800252std::unique_ptr<rtc::SSLCertChain>
253JsepTransportController::GetRemoteSSLCertChain(
Zhi Huange818b6e2018-02-22 15:26:27 -0800254 const std::string& transport_name) const {
255 if (!network_thread_->IsCurrent()) {
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800256 return network_thread_->Invoke<std::unique_ptr<rtc::SSLCertChain>>(
257 RTC_FROM_HERE, [&] { return GetRemoteSSLCertChain(transport_name); });
Zhi Huange818b6e2018-02-22 15:26:27 -0800258 }
259
Zhi Huange830e682018-03-30 10:48:35 -0700260 // Get the certificate from the RTP transport's DTLS handshake. Should be
261 // identical to the RTCP transport's, since they were given the same remote
Zhi Huange818b6e2018-02-22 15:26:27 -0800262 // fingerprint.
Zhi Huange830e682018-03-30 10:48:35 -0700263 auto jsep_transport = GetJsepTransportByName(transport_name);
264 if (!jsep_transport) {
265 return nullptr;
266 }
267 auto dtls = jsep_transport->rtp_dtls_transport();
Zhi Huange818b6e2018-02-22 15:26:27 -0800268 if (!dtls) {
269 return nullptr;
270 }
271
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800272 return dtls->GetRemoteSSLCertChain();
Zhi Huange818b6e2018-02-22 15:26:27 -0800273}
274
275void JsepTransportController::MaybeStartGathering() {
276 if (!network_thread_->IsCurrent()) {
277 network_thread_->Invoke<void>(RTC_FROM_HERE,
278 [&] { MaybeStartGathering(); });
279 return;
280 }
281
282 for (auto& dtls : GetDtlsTransports()) {
283 dtls->ice_transport()->MaybeStartGathering();
284 }
285}
286
287RTCError JsepTransportController::AddRemoteCandidates(
288 const std::string& transport_name,
289 const cricket::Candidates& candidates) {
290 if (!network_thread_->IsCurrent()) {
291 return network_thread_->Invoke<RTCError>(RTC_FROM_HERE, [&] {
292 return AddRemoteCandidates(transport_name, candidates);
293 });
294 }
295
296 // Verify each candidate before passing down to the transport layer.
297 RTCError error = VerifyCandidates(candidates);
298 if (!error.ok()) {
299 return error;
300 }
Zhi Huange830e682018-03-30 10:48:35 -0700301 auto jsep_transport = GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800302 if (!jsep_transport) {
Zhi Huange830e682018-03-30 10:48:35 -0700303 RTC_LOG(LS_WARNING) << "Not adding candidate because the JsepTransport "
304 "doesn't exist. Ignore it.";
305 return RTCError::OK();
Zhi Huange818b6e2018-02-22 15:26:27 -0800306 }
Zhi Huange818b6e2018-02-22 15:26:27 -0800307 return jsep_transport->AddRemoteCandidates(candidates);
308}
309
310RTCError JsepTransportController::RemoveRemoteCandidates(
311 const cricket::Candidates& candidates) {
312 if (!network_thread_->IsCurrent()) {
313 return network_thread_->Invoke<RTCError>(
314 RTC_FROM_HERE, [&] { return RemoveRemoteCandidates(candidates); });
315 }
316
317 // Verify each candidate before passing down to the transport layer.
318 RTCError error = VerifyCandidates(candidates);
319 if (!error.ok()) {
320 return error;
321 }
322
323 std::map<std::string, cricket::Candidates> candidates_by_transport_name;
324 for (const cricket::Candidate& cand : candidates) {
325 if (!cand.transport_name().empty()) {
326 candidates_by_transport_name[cand.transport_name()].push_back(cand);
327 } else {
328 RTC_LOG(LS_ERROR) << "Not removing candidate because it does not have a "
329 "transport name set: "
330 << cand.ToString();
331 }
332 }
333
334 for (const auto& kv : candidates_by_transport_name) {
335 const std::string& transport_name = kv.first;
336 const cricket::Candidates& candidates = kv.second;
Zhi Huang365381f2018-04-13 16:44:34 -0700337 cricket::JsepTransport* jsep_transport =
Zhi Huange830e682018-03-30 10:48:35 -0700338 GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800339 if (!jsep_transport) {
Zhi Huange830e682018-03-30 10:48:35 -0700340 RTC_LOG(LS_WARNING)
341 << "Not removing candidate because the JsepTransport doesn't exist.";
342 continue;
Zhi Huange818b6e2018-02-22 15:26:27 -0800343 }
344 for (const cricket::Candidate& candidate : candidates) {
345 auto dtls = candidate.component() == cricket::ICE_CANDIDATE_COMPONENT_RTP
346 ? jsep_transport->rtp_dtls_transport()
347 : jsep_transport->rtcp_dtls_transport();
348 if (dtls) {
349 dtls->ice_transport()->RemoveRemoteCandidate(candidate);
350 }
351 }
352 }
353 return RTCError::OK();
354}
355
356bool JsepTransportController::GetStats(const std::string& transport_name,
357 cricket::TransportStats* stats) {
358 if (!network_thread_->IsCurrent()) {
359 return network_thread_->Invoke<bool>(
360 RTC_FROM_HERE, [=] { return GetStats(transport_name, stats); });
361 }
362
Zhi Huang365381f2018-04-13 16:44:34 -0700363 cricket::JsepTransport* transport = GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800364 if (!transport) {
365 return false;
366 }
367 return transport->GetStats(stats);
368}
369
Zhi Huangb57e1692018-06-12 11:41:11 -0700370void JsepTransportController::SetActiveResetSrtpParams(
371 bool active_reset_srtp_params) {
372 if (!network_thread_->IsCurrent()) {
373 network_thread_->Invoke<void>(RTC_FROM_HERE, [=] {
374 SetActiveResetSrtpParams(active_reset_srtp_params);
375 });
376 return;
377 }
378
379 RTC_LOG(INFO)
380 << "Updating the active_reset_srtp_params for JsepTransportController: "
381 << active_reset_srtp_params;
382 config_.active_reset_srtp_params = active_reset_srtp_params;
383 for (auto& kv : jsep_transports_by_name_) {
384 kv.second->SetActiveResetSrtpParams(active_reset_srtp_params);
385 }
386}
387
Zhi Huange818b6e2018-02-22 15:26:27 -0800388std::unique_ptr<cricket::DtlsTransportInternal>
389JsepTransportController::CreateDtlsTransport(const std::string& transport_name,
390 bool rtcp) {
391 RTC_DCHECK(network_thread_->IsCurrent());
392 int component = rtcp ? cricket::ICE_CANDIDATE_COMPONENT_RTCP
393 : cricket::ICE_CANDIDATE_COMPONENT_RTP;
394
395 std::unique_ptr<cricket::DtlsTransportInternal> dtls;
396 if (config_.external_transport_factory) {
397 auto ice = config_.external_transport_factory->CreateIceTransport(
398 transport_name, component);
399 dtls = config_.external_transport_factory->CreateDtlsTransport(
400 std::move(ice), config_.crypto_options);
401 } else {
Karl Wiberg918f50c2018-07-05 11:40:33 +0200402 auto ice = absl::make_unique<cricket::P2PTransportChannel>(
Zach Steine20867f2018-08-02 13:20:15 -0700403 transport_name, component, port_allocator_, async_resolver_factory_,
404 config_.event_log);
Karl Wiberg918f50c2018-07-05 11:40:33 +0200405 dtls = absl::make_unique<cricket::DtlsTransport>(std::move(ice),
406 config_.crypto_options);
Zhi Huange818b6e2018-02-22 15:26:27 -0800407 }
408
409 RTC_DCHECK(dtls);
410 dtls->SetSslMaxProtocolVersion(config_.ssl_max_version);
Zhi Huange818b6e2018-02-22 15:26:27 -0800411 dtls->ice_transport()->SetIceRole(ice_role_);
412 dtls->ice_transport()->SetIceTiebreaker(ice_tiebreaker_);
413 dtls->ice_transport()->SetIceConfig(ice_config_);
414 if (certificate_) {
415 bool set_cert_success = dtls->SetLocalCertificate(certificate_);
416 RTC_DCHECK(set_cert_success);
417 }
418
419 // Connect to signals offered by the DTLS and ICE transport.
420 dtls->SignalWritableState.connect(
421 this, &JsepTransportController::OnTransportWritableState_n);
422 dtls->SignalReceivingState.connect(
423 this, &JsepTransportController::OnTransportReceivingState_n);
424 dtls->SignalDtlsHandshakeError.connect(
425 this, &JsepTransportController::OnDtlsHandshakeError);
426 dtls->ice_transport()->SignalGatheringState.connect(
427 this, &JsepTransportController::OnTransportGatheringState_n);
428 dtls->ice_transport()->SignalCandidateGathered.connect(
429 this, &JsepTransportController::OnTransportCandidateGathered_n);
430 dtls->ice_transport()->SignalCandidatesRemoved.connect(
431 this, &JsepTransportController::OnTransportCandidatesRemoved_n);
432 dtls->ice_transport()->SignalRoleConflict.connect(
433 this, &JsepTransportController::OnTransportRoleConflict_n);
434 dtls->ice_transport()->SignalStateChanged.connect(
435 this, &JsepTransportController::OnTransportStateChanged_n);
436 return dtls;
437}
438
439std::unique_ptr<webrtc::RtpTransport>
440JsepTransportController::CreateUnencryptedRtpTransport(
441 const std::string& transport_name,
442 rtc::PacketTransportInternal* rtp_packet_transport,
443 rtc::PacketTransportInternal* rtcp_packet_transport) {
444 RTC_DCHECK(network_thread_->IsCurrent());
Zhi Huange830e682018-03-30 10:48:35 -0700445 auto unencrypted_rtp_transport =
Karl Wiberg918f50c2018-07-05 11:40:33 +0200446 absl::make_unique<RtpTransport>(rtcp_packet_transport == nullptr);
Zhi Huange830e682018-03-30 10:48:35 -0700447 unencrypted_rtp_transport->SetRtpPacketTransport(rtp_packet_transport);
448 if (rtcp_packet_transport) {
449 unencrypted_rtp_transport->SetRtcpPacketTransport(rtcp_packet_transport);
450 }
451 return unencrypted_rtp_transport;
Zhi Huange818b6e2018-02-22 15:26:27 -0800452}
453
454std::unique_ptr<webrtc::SrtpTransport>
455JsepTransportController::CreateSdesTransport(
456 const std::string& transport_name,
Zhi Huange830e682018-03-30 10:48:35 -0700457 cricket::DtlsTransportInternal* rtp_dtls_transport,
458 cricket::DtlsTransportInternal* rtcp_dtls_transport) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800459 RTC_DCHECK(network_thread_->IsCurrent());
Zhi Huange818b6e2018-02-22 15:26:27 -0800460 auto srtp_transport =
Karl Wiberg918f50c2018-07-05 11:40:33 +0200461 absl::make_unique<webrtc::SrtpTransport>(rtcp_dtls_transport == nullptr);
Zhi Huange830e682018-03-30 10:48:35 -0700462 RTC_DCHECK(rtp_dtls_transport);
463 srtp_transport->SetRtpPacketTransport(rtp_dtls_transport);
464 if (rtcp_dtls_transport) {
465 srtp_transport->SetRtcpPacketTransport(rtcp_dtls_transport);
Zhi Huange818b6e2018-02-22 15:26:27 -0800466 }
467 if (config_.enable_external_auth) {
468 srtp_transport->EnableExternalAuth();
469 }
470 return srtp_transport;
471}
472
473std::unique_ptr<webrtc::DtlsSrtpTransport>
474JsepTransportController::CreateDtlsSrtpTransport(
475 const std::string& transport_name,
476 cricket::DtlsTransportInternal* rtp_dtls_transport,
477 cricket::DtlsTransportInternal* rtcp_dtls_transport) {
478 RTC_DCHECK(network_thread_->IsCurrent());
Karl Wiberg918f50c2018-07-05 11:40:33 +0200479 auto dtls_srtp_transport = absl::make_unique<webrtc::DtlsSrtpTransport>(
Zhi Huang365381f2018-04-13 16:44:34 -0700480 rtcp_dtls_transport == nullptr);
Zhi Huang27f3bf52018-03-26 21:37:23 -0700481 if (config_.enable_external_auth) {
Zhi Huang365381f2018-04-13 16:44:34 -0700482 dtls_srtp_transport->EnableExternalAuth();
Zhi Huang27f3bf52018-03-26 21:37:23 -0700483 }
Zhi Huang97d5e5b2018-03-27 00:09:01 +0000484
Zhi Huange818b6e2018-02-22 15:26:27 -0800485 dtls_srtp_transport->SetDtlsTransports(rtp_dtls_transport,
486 rtcp_dtls_transport);
Zhi Huangb57e1692018-06-12 11:41:11 -0700487 dtls_srtp_transport->SetActiveResetSrtpParams(
488 config_.active_reset_srtp_params);
Zhi Huange818b6e2018-02-22 15:26:27 -0800489 return dtls_srtp_transport;
490}
491
492std::vector<cricket::DtlsTransportInternal*>
493JsepTransportController::GetDtlsTransports() {
494 std::vector<cricket::DtlsTransportInternal*> dtls_transports;
Zhi Huange830e682018-03-30 10:48:35 -0700495 for (auto it = jsep_transports_by_name_.begin();
496 it != jsep_transports_by_name_.end(); ++it) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800497 auto jsep_transport = it->second.get();
498 RTC_DCHECK(jsep_transport);
499 if (jsep_transport->rtp_dtls_transport()) {
500 dtls_transports.push_back(jsep_transport->rtp_dtls_transport());
501 }
502
503 if (jsep_transport->rtcp_dtls_transport()) {
504 dtls_transports.push_back(jsep_transport->rtcp_dtls_transport());
505 }
506 }
507 return dtls_transports;
508}
509
510void JsepTransportController::OnMessage(rtc::Message* pmsg) {
511 RTC_DCHECK(signaling_thread_->IsCurrent());
512
513 switch (pmsg->message_id) {
514 case MSG_ICECONNECTIONSTATE: {
515 rtc::TypedMessageData<cricket::IceConnectionState>* data =
516 static_cast<rtc::TypedMessageData<cricket::IceConnectionState>*>(
517 pmsg->pdata);
518 SignalIceConnectionState(data->data());
519 delete data;
520 break;
521 }
522 case MSG_ICEGATHERINGSTATE: {
523 rtc::TypedMessageData<cricket::IceGatheringState>* data =
524 static_cast<rtc::TypedMessageData<cricket::IceGatheringState>*>(
525 pmsg->pdata);
526 SignalIceGatheringState(data->data());
527 delete data;
528 break;
529 }
530 case MSG_ICECANDIDATESGATHERED: {
531 CandidatesData* data = static_cast<CandidatesData*>(pmsg->pdata);
532 SignalIceCandidatesGathered(data->transport_name, data->candidates);
533 delete data;
534 break;
535 }
536 default:
537 RTC_NOTREACHED();
538 }
539}
540
541RTCError JsepTransportController::ApplyDescription_n(
542 bool local,
543 SdpType type,
544 const cricket::SessionDescription* description) {
545 RTC_DCHECK(network_thread_->IsCurrent());
546 RTC_DCHECK(description);
547
548 if (local) {
549 local_desc_ = description;
550 } else {
551 remote_desc_ = description;
552 }
553
Zhi Huange830e682018-03-30 10:48:35 -0700554 RTCError error;
Zhi Huangd2248f82018-04-10 14:41:03 -0700555 error = ValidateAndMaybeUpdateBundleGroup(local, type, description);
Zhi Huange830e682018-03-30 10:48:35 -0700556 if (!error.ok()) {
557 return error;
Zhi Huange818b6e2018-02-22 15:26:27 -0800558 }
559
560 std::vector<int> merged_encrypted_extension_ids;
561 if (bundle_group_) {
562 merged_encrypted_extension_ids =
563 MergeEncryptedHeaderExtensionIdsForBundle(description);
564 }
565
566 for (const cricket::ContentInfo& content_info : description->contents()) {
567 // Don't create transports for rejected m-lines and bundled m-lines."
568 if (content_info.rejected ||
569 (IsBundled(content_info.name) && content_info.name != *bundled_mid())) {
570 continue;
571 }
Zhi Huangd2248f82018-04-10 14:41:03 -0700572 error = MaybeCreateJsepTransport(content_info);
Zhi Huange830e682018-03-30 10:48:35 -0700573 if (!error.ok()) {
574 return error;
575 }
Zhi Huange818b6e2018-02-22 15:26:27 -0800576 }
577
578 RTC_DCHECK(description->contents().size() ==
579 description->transport_infos().size());
580 for (size_t i = 0; i < description->contents().size(); ++i) {
581 const cricket::ContentInfo& content_info = description->contents()[i];
582 const cricket::TransportInfo& transport_info =
583 description->transport_infos()[i];
584 if (content_info.rejected) {
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700585 HandleRejectedContent(content_info, description);
Zhi Huange818b6e2018-02-22 15:26:27 -0800586 continue;
587 }
588
589 if (IsBundled(content_info.name) && content_info.name != *bundled_mid()) {
Zhi Huang365381f2018-04-13 16:44:34 -0700590 if (!HandleBundledContent(content_info)) {
591 return RTCError(RTCErrorType::INVALID_PARAMETER,
592 "Failed to process the bundled m= section.");
593 }
Zhi Huange818b6e2018-02-22 15:26:27 -0800594 continue;
595 }
596
Zhi Huange830e682018-03-30 10:48:35 -0700597 error = ValidateContent(content_info);
598 if (!error.ok()) {
599 return error;
600 }
601
Zhi Huange818b6e2018-02-22 15:26:27 -0800602 std::vector<int> extension_ids;
Taylor Brandstetter0ab56512018-04-12 10:30:48 -0700603 if (bundled_mid() && content_info.name == *bundled_mid()) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800604 extension_ids = merged_encrypted_extension_ids;
605 } else {
606 extension_ids = GetEncryptedHeaderExtensionIds(content_info);
607 }
608
Zhi Huange830e682018-03-30 10:48:35 -0700609 int rtp_abs_sendtime_extn_id =
610 GetRtpAbsSendTimeHeaderExtensionId(content_info);
611
Zhi Huang365381f2018-04-13 16:44:34 -0700612 cricket::JsepTransport* transport =
Zhi Huange830e682018-03-30 10:48:35 -0700613 GetJsepTransportForMid(content_info.name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800614 RTC_DCHECK(transport);
615
616 SetIceRole_n(DetermineIceRole(transport, transport_info, type, local));
617
Zhi Huange818b6e2018-02-22 15:26:27 -0800618 cricket::JsepTransportDescription jsep_description =
619 CreateJsepTransportDescription(content_info, transport_info,
Zhi Huange830e682018-03-30 10:48:35 -0700620 extension_ids, rtp_abs_sendtime_extn_id);
Zhi Huange818b6e2018-02-22 15:26:27 -0800621 if (local) {
622 error =
623 transport->SetLocalJsepTransportDescription(jsep_description, type);
624 } else {
625 error =
626 transport->SetRemoteJsepTransportDescription(jsep_description, type);
627 }
628
629 if (!error.ok()) {
630 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
631 "Failed to apply the description for " +
632 content_info.name + ": " + error.message());
633 }
634 }
635 return RTCError::OK();
636}
637
Zhi Huangd2248f82018-04-10 14:41:03 -0700638RTCError JsepTransportController::ValidateAndMaybeUpdateBundleGroup(
639 bool local,
640 SdpType type,
Zhi Huange830e682018-03-30 10:48:35 -0700641 const cricket::SessionDescription* description) {
642 RTC_DCHECK(description);
Zhi Huangd2248f82018-04-10 14:41:03 -0700643 const cricket::ContentGroup* new_bundle_group =
644 description->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
645
646 // The BUNDLE group containing a MID that no m= section has is invalid.
647 if (new_bundle_group) {
648 for (auto content_name : new_bundle_group->content_names()) {
649 if (!description->GetContentByName(content_name)) {
650 return RTCError(RTCErrorType::INVALID_PARAMETER,
651 "The BUNDLE group contains MID:" + content_name +
652 " matching no m= section.");
653 }
654 }
655 }
656
657 if (type == SdpType::kAnswer) {
658 const cricket::ContentGroup* offered_bundle_group =
659 local ? remote_desc_->GetGroupByName(cricket::GROUP_TYPE_BUNDLE)
660 : local_desc_->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
661
662 if (new_bundle_group) {
663 // The BUNDLE group in answer should be a subset of offered group.
664 for (auto content_name : new_bundle_group->content_names()) {
665 if (!offered_bundle_group ||
666 !offered_bundle_group->HasContentName(content_name)) {
667 return RTCError(RTCErrorType::INVALID_PARAMETER,
668 "The BUNDLE group in answer contains a MID that was "
669 "not in the offered group.");
670 }
671 }
672 }
673
674 if (bundle_group_) {
675 for (auto content_name : bundle_group_->content_names()) {
676 // An answer that removes m= sections from pre-negotiated BUNDLE group
677 // without rejecting it, is invalid.
678 if (!new_bundle_group ||
679 !new_bundle_group->HasContentName(content_name)) {
680 auto* content_info = description->GetContentByName(content_name);
681 if (!content_info || !content_info->rejected) {
682 return RTCError(RTCErrorType::INVALID_PARAMETER,
683 "Answer cannot remove m= section " + content_name +
684 " from already-established BUNDLE group.");
685 }
686 }
687 }
688 }
689 }
690
691 if (config_.bundle_policy ==
692 PeerConnectionInterface::kBundlePolicyMaxBundle &&
693 !description->HasGroup(cricket::GROUP_TYPE_BUNDLE)) {
694 return RTCError(RTCErrorType::INVALID_PARAMETER,
695 "max-bundle is used but no bundle group found.");
696 }
697
698 if (ShouldUpdateBundleGroup(type, description)) {
Taylor Brandstetter0ab56512018-04-12 10:30:48 -0700699 const std::string* new_bundled_mid = new_bundle_group->FirstContentName();
700 if (bundled_mid() && new_bundled_mid &&
701 *bundled_mid() != *new_bundled_mid) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700702 return RTCError(RTCErrorType::UNSUPPORTED_OPERATION,
703 "Changing the negotiated BUNDLE-tag is not supported.");
704 }
705
706 bundle_group_ = *new_bundle_group;
707 }
Zhi Huange830e682018-03-30 10:48:35 -0700708
709 if (!bundled_mid()) {
710 return RTCError::OK();
711 }
712
713 auto bundled_content = description->GetContentByName(*bundled_mid());
714 if (!bundled_content) {
715 return RTCError(
716 RTCErrorType::INVALID_PARAMETER,
717 "An m= section associated with the BUNDLE-tag doesn't exist.");
718 }
719
720 // If the |bundled_content| is rejected, other contents in the bundle group
721 // should be rejected.
722 if (bundled_content->rejected) {
723 for (auto content_name : bundle_group_->content_names()) {
724 auto other_content = description->GetContentByName(content_name);
725 if (!other_content->rejected) {
726 return RTCError(
727 RTCErrorType::INVALID_PARAMETER,
728 "The m= section:" + content_name + " should be rejected.");
729 }
730 }
731 }
732
733 return RTCError::OK();
734}
735
736RTCError JsepTransportController::ValidateContent(
737 const cricket::ContentInfo& content_info) {
738 if (config_.rtcp_mux_policy ==
739 PeerConnectionInterface::kRtcpMuxPolicyRequire &&
740 content_info.type == cricket::MediaProtocolType::kRtp &&
741 !content_info.media_description()->rtcp_mux()) {
742 return RTCError(RTCErrorType::INVALID_PARAMETER,
743 "The m= section:" + content_info.name +
744 " is invalid. RTCP-MUX is not "
745 "enabled when it is required.");
746 }
747 return RTCError::OK();
748}
749
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700750void JsepTransportController::HandleRejectedContent(
Zhi Huangd2248f82018-04-10 14:41:03 -0700751 const cricket::ContentInfo& content_info,
752 const cricket::SessionDescription* description) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800753 // If the content is rejected, let the
754 // BaseChannel/SctpTransport change the RtpTransport/DtlsTransport first,
Zhi Huang365381f2018-04-13 16:44:34 -0700755 // then destroy the cricket::JsepTransport.
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700756 RemoveTransportForMid(content_info.name);
Zhi Huange830e682018-03-30 10:48:35 -0700757 if (content_info.name == bundled_mid()) {
758 for (auto content_name : bundle_group_->content_names()) {
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700759 RemoveTransportForMid(content_name);
Zhi Huange830e682018-03-30 10:48:35 -0700760 }
761 bundle_group_.reset();
762 } else if (IsBundled(content_info.name)) {
763 // Remove the rejected content from the |bundle_group_|.
Zhi Huange818b6e2018-02-22 15:26:27 -0800764 bundle_group_->RemoveContentName(content_info.name);
Zhi Huange830e682018-03-30 10:48:35 -0700765 // Reset the bundle group if nothing left.
766 if (!bundle_group_->FirstContentName()) {
767 bundle_group_.reset();
768 }
Zhi Huange818b6e2018-02-22 15:26:27 -0800769 }
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700770 MaybeDestroyJsepTransport(content_info.name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800771}
772
Zhi Huang365381f2018-04-13 16:44:34 -0700773bool JsepTransportController::HandleBundledContent(
Zhi Huange818b6e2018-02-22 15:26:27 -0800774 const cricket::ContentInfo& content_info) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700775 auto jsep_transport = GetJsepTransportByName(*bundled_mid());
776 RTC_DCHECK(jsep_transport);
Zhi Huange818b6e2018-02-22 15:26:27 -0800777 // If the content is bundled, let the
778 // BaseChannel/SctpTransport change the RtpTransport/DtlsTransport first,
Zhi Huang365381f2018-04-13 16:44:34 -0700779 // then destroy the cricket::JsepTransport.
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700780 if (SetTransportForMid(content_info.name, jsep_transport)) {
Zhi Huang365381f2018-04-13 16:44:34 -0700781 MaybeDestroyJsepTransport(content_info.name);
782 return true;
783 }
784 return false;
Zhi Huange818b6e2018-02-22 15:26:27 -0800785}
786
Zhi Huang365381f2018-04-13 16:44:34 -0700787bool JsepTransportController::SetTransportForMid(
Zhi Huangd2248f82018-04-10 14:41:03 -0700788 const std::string& mid,
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700789 cricket::JsepTransport* jsep_transport) {
Zhi Huang365381f2018-04-13 16:44:34 -0700790 RTC_DCHECK(jsep_transport);
Zhi Huangd2248f82018-04-10 14:41:03 -0700791 if (mid_to_transport_[mid] == jsep_transport) {
Zhi Huang365381f2018-04-13 16:44:34 -0700792 return true;
Zhi Huangd2248f82018-04-10 14:41:03 -0700793 }
794
795 mid_to_transport_[mid] = jsep_transport;
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700796 return config_.transport_observer->OnTransportChanged(
797 mid, jsep_transport->rtp_transport(),
798 jsep_transport->rtp_dtls_transport());
Zhi Huangd2248f82018-04-10 14:41:03 -0700799}
800
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700801void JsepTransportController::RemoveTransportForMid(const std::string& mid) {
802 bool ret =
803 config_.transport_observer->OnTransportChanged(mid, nullptr, nullptr);
804 // Calling OnTransportChanged with nullptr should always succeed, since it is
805 // only expected to fail when adding media to a transport (not removing).
806 RTC_DCHECK(ret);
Zhi Huangd2248f82018-04-10 14:41:03 -0700807 mid_to_transport_.erase(mid);
808}
809
Zhi Huange818b6e2018-02-22 15:26:27 -0800810cricket::JsepTransportDescription
811JsepTransportController::CreateJsepTransportDescription(
812 cricket::ContentInfo content_info,
813 cricket::TransportInfo transport_info,
Zhi Huange830e682018-03-30 10:48:35 -0700814 const std::vector<int>& encrypted_extension_ids,
815 int rtp_abs_sendtime_extn_id) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800816 const cricket::MediaContentDescription* content_desc =
817 static_cast<const cricket::MediaContentDescription*>(
818 content_info.description);
819 RTC_DCHECK(content_desc);
820 bool rtcp_mux_enabled = content_info.type == cricket::MediaProtocolType::kSctp
821 ? true
822 : content_desc->rtcp_mux();
823
824 return cricket::JsepTransportDescription(
825 rtcp_mux_enabled, content_desc->cryptos(), encrypted_extension_ids,
Zhi Huange830e682018-03-30 10:48:35 -0700826 rtp_abs_sendtime_extn_id, transport_info.description);
Zhi Huange818b6e2018-02-22 15:26:27 -0800827}
828
829bool JsepTransportController::ShouldUpdateBundleGroup(
830 SdpType type,
831 const cricket::SessionDescription* description) {
832 if (config_.bundle_policy ==
833 PeerConnectionInterface::kBundlePolicyMaxBundle) {
834 return true;
835 }
836
837 if (type != SdpType::kAnswer) {
838 return false;
839 }
840
841 RTC_DCHECK(local_desc_ && remote_desc_);
842 const cricket::ContentGroup* local_bundle =
843 local_desc_->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
844 const cricket::ContentGroup* remote_bundle =
845 remote_desc_->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
846 return local_bundle && remote_bundle;
847}
848
849std::vector<int> JsepTransportController::GetEncryptedHeaderExtensionIds(
850 const cricket::ContentInfo& content_info) {
851 const cricket::MediaContentDescription* content_desc =
852 static_cast<const cricket::MediaContentDescription*>(
853 content_info.description);
854
855 if (!config_.crypto_options.enable_encrypted_rtp_header_extensions) {
856 return std::vector<int>();
857 }
858
859 std::vector<int> encrypted_header_extension_ids;
860 for (auto extension : content_desc->rtp_header_extensions()) {
861 if (!extension.encrypt) {
862 continue;
863 }
864 auto it = std::find(encrypted_header_extension_ids.begin(),
865 encrypted_header_extension_ids.end(), extension.id);
866 if (it == encrypted_header_extension_ids.end()) {
867 encrypted_header_extension_ids.push_back(extension.id);
868 }
869 }
870 return encrypted_header_extension_ids;
871}
872
873std::vector<int>
874JsepTransportController::MergeEncryptedHeaderExtensionIdsForBundle(
875 const cricket::SessionDescription* description) {
876 RTC_DCHECK(description);
877 RTC_DCHECK(bundle_group_);
878
879 std::vector<int> merged_ids;
880 // Union the encrypted header IDs in the group when bundle is enabled.
881 for (const cricket::ContentInfo& content_info : description->contents()) {
882 if (bundle_group_->HasContentName(content_info.name)) {
883 std::vector<int> extension_ids =
884 GetEncryptedHeaderExtensionIds(content_info);
885 for (int id : extension_ids) {
886 auto it = std::find(merged_ids.begin(), merged_ids.end(), id);
887 if (it == merged_ids.end()) {
888 merged_ids.push_back(id);
889 }
890 }
891 }
892 }
893 return merged_ids;
894}
895
Zhi Huange830e682018-03-30 10:48:35 -0700896int JsepTransportController::GetRtpAbsSendTimeHeaderExtensionId(
Zhi Huange818b6e2018-02-22 15:26:27 -0800897 const cricket::ContentInfo& content_info) {
Zhi Huange830e682018-03-30 10:48:35 -0700898 if (!config_.enable_external_auth) {
899 return -1;
Zhi Huange818b6e2018-02-22 15:26:27 -0800900 }
901
902 const cricket::MediaContentDescription* content_desc =
903 static_cast<const cricket::MediaContentDescription*>(
904 content_info.description);
Zhi Huange830e682018-03-30 10:48:35 -0700905
906 const webrtc::RtpExtension* send_time_extension =
907 webrtc::RtpExtension::FindHeaderExtensionByUri(
908 content_desc->rtp_header_extensions(),
909 webrtc::RtpExtension::kAbsSendTimeUri);
910 return send_time_extension ? send_time_extension->id : -1;
911}
912
Zhi Huang365381f2018-04-13 16:44:34 -0700913const cricket::JsepTransport* JsepTransportController::GetJsepTransportForMid(
Zhi Huange830e682018-03-30 10:48:35 -0700914 const std::string& mid) const {
Zhi Huangd2248f82018-04-10 14:41:03 -0700915 auto it = mid_to_transport_.find(mid);
916 return it == mid_to_transport_.end() ? nullptr : it->second;
Zhi Huange830e682018-03-30 10:48:35 -0700917}
918
Zhi Huang365381f2018-04-13 16:44:34 -0700919cricket::JsepTransport* JsepTransportController::GetJsepTransportForMid(
Zhi Huange830e682018-03-30 10:48:35 -0700920 const std::string& mid) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700921 auto it = mid_to_transport_.find(mid);
922 return it == mid_to_transport_.end() ? nullptr : it->second;
Zhi Huange830e682018-03-30 10:48:35 -0700923}
924
Zhi Huang365381f2018-04-13 16:44:34 -0700925const cricket::JsepTransport* JsepTransportController::GetJsepTransportByName(
Zhi Huange830e682018-03-30 10:48:35 -0700926 const std::string& transport_name) const {
927 auto it = jsep_transports_by_name_.find(transport_name);
928 return (it == jsep_transports_by_name_.end()) ? nullptr : it->second.get();
929}
930
Zhi Huang365381f2018-04-13 16:44:34 -0700931cricket::JsepTransport* JsepTransportController::GetJsepTransportByName(
Zhi Huange830e682018-03-30 10:48:35 -0700932 const std::string& transport_name) {
933 auto it = jsep_transports_by_name_.find(transport_name);
934 return (it == jsep_transports_by_name_.end()) ? nullptr : it->second.get();
935}
936
937RTCError JsepTransportController::MaybeCreateJsepTransport(
Zhi Huange830e682018-03-30 10:48:35 -0700938 const cricket::ContentInfo& content_info) {
939 RTC_DCHECK(network_thread_->IsCurrent());
Zhi Huang365381f2018-04-13 16:44:34 -0700940 cricket::JsepTransport* transport = GetJsepTransportByName(content_info.name);
Zhi Huange830e682018-03-30 10:48:35 -0700941 if (transport) {
942 return RTCError::OK();
943 }
944
945 const cricket::MediaContentDescription* content_desc =
946 static_cast<const cricket::MediaContentDescription*>(
947 content_info.description);
948 if (certificate_ && !content_desc->cryptos().empty()) {
949 return RTCError(RTCErrorType::INVALID_PARAMETER,
950 "SDES and DTLS-SRTP cannot be enabled at the same time.");
951 }
952
Zhi Huange818b6e2018-02-22 15:26:27 -0800953 std::unique_ptr<cricket::DtlsTransportInternal> rtp_dtls_transport =
Zhi Huangd2248f82018-04-10 14:41:03 -0700954 CreateDtlsTransport(content_info.name, /*rtcp =*/false);
Zhi Huange818b6e2018-02-22 15:26:27 -0800955 std::unique_ptr<cricket::DtlsTransportInternal> rtcp_dtls_transport;
Zhi Huange830e682018-03-30 10:48:35 -0700956 if (config_.rtcp_mux_policy !=
957 PeerConnectionInterface::kRtcpMuxPolicyRequire &&
958 content_info.type == cricket::MediaProtocolType::kRtp) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700959 rtcp_dtls_transport =
960 CreateDtlsTransport(content_info.name, /*rtcp =*/true);
Zhi Huange818b6e2018-02-22 15:26:27 -0800961 }
962
963 std::unique_ptr<RtpTransport> unencrypted_rtp_transport;
964 std::unique_ptr<SrtpTransport> sdes_transport;
965 std::unique_ptr<DtlsSrtpTransport> dtls_srtp_transport;
966 if (config_.disable_encryption) {
967 unencrypted_rtp_transport = CreateUnencryptedRtpTransport(
Zhi Huangd2248f82018-04-10 14:41:03 -0700968 content_info.name, rtp_dtls_transport.get(), rtcp_dtls_transport.get());
Zhi Huange818b6e2018-02-22 15:26:27 -0800969 } else if (!content_desc->cryptos().empty()) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700970 sdes_transport = CreateSdesTransport(
971 content_info.name, rtp_dtls_transport.get(), rtcp_dtls_transport.get());
Zhi Huange818b6e2018-02-22 15:26:27 -0800972 } else {
Zhi Huangd2248f82018-04-10 14:41:03 -0700973 dtls_srtp_transport = CreateDtlsSrtpTransport(
974 content_info.name, rtp_dtls_transport.get(), rtcp_dtls_transport.get());
Zhi Huange818b6e2018-02-22 15:26:27 -0800975 }
976
Zhi Huang365381f2018-04-13 16:44:34 -0700977 std::unique_ptr<cricket::JsepTransport> jsep_transport =
Karl Wiberg918f50c2018-07-05 11:40:33 +0200978 absl::make_unique<cricket::JsepTransport>(
Zhi Huangd2248f82018-04-10 14:41:03 -0700979 content_info.name, certificate_, std::move(unencrypted_rtp_transport),
Zhi Huange818b6e2018-02-22 15:26:27 -0800980 std::move(sdes_transport), std::move(dtls_srtp_transport),
981 std::move(rtp_dtls_transport), std::move(rtcp_dtls_transport));
982 jsep_transport->SignalRtcpMuxActive.connect(
983 this, &JsepTransportController::UpdateAggregateStates_n);
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700984 SetTransportForMid(content_info.name, jsep_transport.get());
Zhi Huange830e682018-03-30 10:48:35 -0700985
Zhi Huangd2248f82018-04-10 14:41:03 -0700986 jsep_transports_by_name_[content_info.name] = std::move(jsep_transport);
987 UpdateAggregateStates_n();
Zhi Huange830e682018-03-30 10:48:35 -0700988 return RTCError::OK();
Zhi Huange818b6e2018-02-22 15:26:27 -0800989}
990
991void JsepTransportController::MaybeDestroyJsepTransport(
992 const std::string& mid) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700993 auto jsep_transport = GetJsepTransportByName(mid);
994 if (!jsep_transport) {
995 return;
996 }
997
998 // Don't destroy the JsepTransport if there are still media sections referring
999 // to it.
1000 for (const auto& kv : mid_to_transport_) {
1001 if (kv.second == jsep_transport) {
1002 return;
1003 }
1004 }
Zhi Huange830e682018-03-30 10:48:35 -07001005 jsep_transports_by_name_.erase(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -08001006 UpdateAggregateStates_n();
1007}
1008
1009void JsepTransportController::DestroyAllJsepTransports_n() {
1010 RTC_DCHECK(network_thread_->IsCurrent());
Zhi Huange830e682018-03-30 10:48:35 -07001011 jsep_transports_by_name_.clear();
Zhi Huange818b6e2018-02-22 15:26:27 -08001012}
1013
1014void JsepTransportController::SetIceRole_n(cricket::IceRole ice_role) {
1015 RTC_DCHECK(network_thread_->IsCurrent());
1016
1017 ice_role_ = ice_role;
1018 for (auto& dtls : GetDtlsTransports()) {
1019 dtls->ice_transport()->SetIceRole(ice_role_);
1020 }
1021}
1022
1023cricket::IceRole JsepTransportController::DetermineIceRole(
Zhi Huang365381f2018-04-13 16:44:34 -07001024 cricket::JsepTransport* jsep_transport,
Zhi Huange818b6e2018-02-22 15:26:27 -08001025 const cricket::TransportInfo& transport_info,
1026 SdpType type,
1027 bool local) {
1028 cricket::IceRole ice_role = ice_role_;
1029 auto tdesc = transport_info.description;
1030 if (local) {
1031 // The initial offer side may use ICE Lite, in which case, per RFC5245
1032 // Section 5.1.1, the answer side should take the controlling role if it is
1033 // in the full ICE mode.
1034 //
1035 // When both sides use ICE Lite, the initial offer side must take the
1036 // controlling role, and this is the default logic implemented in
1037 // SetLocalDescription in JsepTransportController.
1038 if (jsep_transport->remote_description() &&
1039 jsep_transport->remote_description()->transport_desc.ice_mode ==
1040 cricket::ICEMODE_LITE &&
1041 ice_role_ == cricket::ICEROLE_CONTROLLED &&
1042 tdesc.ice_mode == cricket::ICEMODE_FULL) {
1043 ice_role = cricket::ICEROLE_CONTROLLING;
1044 }
1045
1046 // Older versions of Chrome expect the ICE role to be re-determined when an
1047 // ICE restart occurs, and also don't perform conflict resolution correctly,
1048 // so for now we can't safely stop doing this, unless the application opts
1049 // in by setting |config_.redetermine_role_on_ice_restart_| to false. See:
1050 // https://bugs.chromium.org/p/chromium/issues/detail?id=628676
1051 // TODO(deadbeef): Remove this when these old versions of Chrome reach a low
1052 // enough population.
1053 if (config_.redetermine_role_on_ice_restart &&
1054 jsep_transport->local_description() &&
1055 cricket::IceCredentialsChanged(
1056 jsep_transport->local_description()->transport_desc.ice_ufrag,
1057 jsep_transport->local_description()->transport_desc.ice_pwd,
1058 tdesc.ice_ufrag, tdesc.ice_pwd) &&
1059 // Don't change the ICE role if the remote endpoint is ICE lite; we
1060 // should always be controlling in that case.
1061 (!jsep_transport->remote_description() ||
1062 jsep_transport->remote_description()->transport_desc.ice_mode !=
1063 cricket::ICEMODE_LITE)) {
1064 ice_role = (type == SdpType::kOffer) ? cricket::ICEROLE_CONTROLLING
1065 : cricket::ICEROLE_CONTROLLED;
1066 }
1067 } else {
1068 // If our role is cricket::ICEROLE_CONTROLLED and the remote endpoint
1069 // supports only ice_lite, this local endpoint should take the CONTROLLING
1070 // role.
1071 // TODO(deadbeef): This is a session-level attribute, so it really shouldn't
1072 // be in a TransportDescription in the first place...
1073 if (ice_role_ == cricket::ICEROLE_CONTROLLED &&
1074 tdesc.ice_mode == cricket::ICEMODE_LITE) {
1075 ice_role = cricket::ICEROLE_CONTROLLING;
1076 }
1077
1078 // If we use ICE Lite and the remote endpoint uses the full implementation
1079 // of ICE, the local endpoint must take the controlled role, and the other
1080 // side must be the controlling role.
1081 if (jsep_transport->local_description() &&
1082 jsep_transport->local_description()->transport_desc.ice_mode ==
1083 cricket::ICEMODE_LITE &&
1084 ice_role_ == cricket::ICEROLE_CONTROLLING &&
Zhi Huange830e682018-03-30 10:48:35 -07001085 tdesc.ice_mode == cricket::ICEMODE_FULL) {
Zhi Huange818b6e2018-02-22 15:26:27 -08001086 ice_role = cricket::ICEROLE_CONTROLLED;
1087 }
1088 }
1089
1090 return ice_role;
1091}
1092
1093void JsepTransportController::OnTransportWritableState_n(
1094 rtc::PacketTransportInternal* transport) {
1095 RTC_DCHECK(network_thread_->IsCurrent());
1096 RTC_LOG(LS_INFO) << " Transport " << transport->transport_name()
1097 << " writability changed to " << transport->writable()
1098 << ".";
1099 UpdateAggregateStates_n();
1100}
1101
1102void JsepTransportController::OnTransportReceivingState_n(
1103 rtc::PacketTransportInternal* transport) {
1104 RTC_DCHECK(network_thread_->IsCurrent());
1105 UpdateAggregateStates_n();
1106}
1107
1108void JsepTransportController::OnTransportGatheringState_n(
1109 cricket::IceTransportInternal* transport) {
1110 RTC_DCHECK(network_thread_->IsCurrent());
1111 UpdateAggregateStates_n();
1112}
1113
1114void JsepTransportController::OnTransportCandidateGathered_n(
1115 cricket::IceTransportInternal* transport,
1116 const cricket::Candidate& candidate) {
1117 RTC_DCHECK(network_thread_->IsCurrent());
1118
1119 // We should never signal peer-reflexive candidates.
1120 if (candidate.type() == cricket::PRFLX_PORT_TYPE) {
1121 RTC_NOTREACHED();
1122 return;
1123 }
1124 std::vector<cricket::Candidate> candidates;
1125 candidates.push_back(candidate);
1126 CandidatesData* data =
1127 new CandidatesData(transport->transport_name(), candidates);
1128 signaling_thread_->Post(RTC_FROM_HERE, this, MSG_ICECANDIDATESGATHERED, data);
1129}
1130
1131void JsepTransportController::OnTransportCandidatesRemoved_n(
1132 cricket::IceTransportInternal* transport,
1133 const cricket::Candidates& candidates) {
1134 invoker_.AsyncInvoke<void>(
1135 RTC_FROM_HERE, signaling_thread_,
1136 rtc::Bind(&JsepTransportController::OnTransportCandidatesRemoved, this,
1137 candidates));
1138}
1139
1140void JsepTransportController::OnTransportCandidatesRemoved(
1141 const cricket::Candidates& candidates) {
1142 RTC_DCHECK(signaling_thread_->IsCurrent());
1143 SignalIceCandidatesRemoved(candidates);
1144}
1145
1146void JsepTransportController::OnTransportRoleConflict_n(
1147 cricket::IceTransportInternal* transport) {
1148 RTC_DCHECK(network_thread_->IsCurrent());
1149 // Note: since the role conflict is handled entirely on the network thread,
1150 // we don't need to worry about role conflicts occurring on two ports at
1151 // once. The first one encountered should immediately reverse the role.
1152 cricket::IceRole reversed_role = (ice_role_ == cricket::ICEROLE_CONTROLLING)
1153 ? cricket::ICEROLE_CONTROLLED
1154 : cricket::ICEROLE_CONTROLLING;
1155 RTC_LOG(LS_INFO) << "Got role conflict; switching to "
1156 << (reversed_role == cricket::ICEROLE_CONTROLLING
1157 ? "controlling"
1158 : "controlled")
1159 << " role.";
1160 SetIceRole_n(reversed_role);
1161}
1162
1163void JsepTransportController::OnTransportStateChanged_n(
1164 cricket::IceTransportInternal* transport) {
1165 RTC_DCHECK(network_thread_->IsCurrent());
1166 RTC_LOG(LS_INFO) << transport->transport_name() << " Transport "
1167 << transport->component()
1168 << " state changed. Check if state is complete.";
1169 UpdateAggregateStates_n();
1170}
1171
1172void JsepTransportController::UpdateAggregateStates_n() {
1173 RTC_DCHECK(network_thread_->IsCurrent());
1174
1175 auto dtls_transports = GetDtlsTransports();
1176 cricket::IceConnectionState new_connection_state =
1177 cricket::kIceConnectionConnecting;
1178 cricket::IceGatheringState new_gathering_state = cricket::kIceGatheringNew;
1179 bool any_failed = false;
1180 bool all_connected = !dtls_transports.empty();
1181 bool all_completed = !dtls_transports.empty();
1182 bool any_gathering = false;
1183 bool all_done_gathering = !dtls_transports.empty();
1184 for (const auto& dtls : dtls_transports) {
1185 any_failed = any_failed || dtls->ice_transport()->GetState() ==
1186 cricket::IceTransportState::STATE_FAILED;
1187 all_connected = all_connected && dtls->writable();
1188 all_completed =
1189 all_completed && dtls->writable() &&
1190 dtls->ice_transport()->GetState() ==
1191 cricket::IceTransportState::STATE_COMPLETED &&
1192 dtls->ice_transport()->GetIceRole() == cricket::ICEROLE_CONTROLLING &&
1193 dtls->ice_transport()->gathering_state() ==
1194 cricket::kIceGatheringComplete;
1195 any_gathering = any_gathering || dtls->ice_transport()->gathering_state() !=
1196 cricket::kIceGatheringNew;
1197 all_done_gathering =
1198 all_done_gathering && dtls->ice_transport()->gathering_state() ==
1199 cricket::kIceGatheringComplete;
1200 }
1201 if (any_failed) {
1202 new_connection_state = cricket::kIceConnectionFailed;
1203 } else if (all_completed) {
1204 new_connection_state = cricket::kIceConnectionCompleted;
1205 } else if (all_connected) {
1206 new_connection_state = cricket::kIceConnectionConnected;
1207 }
1208 if (ice_connection_state_ != new_connection_state) {
1209 ice_connection_state_ = new_connection_state;
1210 signaling_thread_->Post(
1211 RTC_FROM_HERE, this, MSG_ICECONNECTIONSTATE,
1212 new rtc::TypedMessageData<cricket::IceConnectionState>(
1213 new_connection_state));
1214 }
1215
1216 if (all_done_gathering) {
1217 new_gathering_state = cricket::kIceGatheringComplete;
1218 } else if (any_gathering) {
1219 new_gathering_state = cricket::kIceGatheringGathering;
1220 }
1221 if (ice_gathering_state_ != new_gathering_state) {
1222 ice_gathering_state_ = new_gathering_state;
1223 signaling_thread_->Post(
1224 RTC_FROM_HERE, this, MSG_ICEGATHERINGSTATE,
1225 new rtc::TypedMessageData<cricket::IceGatheringState>(
1226 new_gathering_state));
1227 }
1228}
1229
1230void JsepTransportController::OnDtlsHandshakeError(
1231 rtc::SSLHandshakeError error) {
1232 SignalDtlsHandshakeError(error);
1233}
1234
1235} // namespace webrtc