blob: 80b723777d9f86c01c76e25ac0e28767d53ddfbf [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
17#include "p2p/base/port.h"
18#include "rtc_base/bind.h"
19#include "rtc_base/checks.h"
20#include "rtc_base/ptr_util.h"
21#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,
93 Config config)
94 : signaling_thread_(signaling_thread),
95 network_thread_(network_thread),
96 port_allocator_(port_allocator),
Zhi Huang365381f2018-04-13 16:44:34 -070097 config_(config) {
98 // The |transport_observer| is assumed to be non-null.
99 RTC_DCHECK(config_.transport_observer);
100}
Zhi Huange818b6e2018-02-22 15:26:27 -0800101
102JsepTransportController::~JsepTransportController() {
103 // Channel destructors may try to send packets, so this needs to happen on
104 // the network thread.
105 network_thread_->Invoke<void>(
106 RTC_FROM_HERE,
107 rtc::Bind(&JsepTransportController::DestroyAllJsepTransports_n, this));
108}
109
110RTCError JsepTransportController::SetLocalDescription(
111 SdpType type,
112 const cricket::SessionDescription* description) {
113 if (!network_thread_->IsCurrent()) {
114 return network_thread_->Invoke<RTCError>(
115 RTC_FROM_HERE, [=] { return SetLocalDescription(type, description); });
116 }
117
118 if (!initial_offerer_.has_value()) {
119 initial_offerer_.emplace(type == SdpType::kOffer);
120 if (*initial_offerer_) {
121 SetIceRole_n(cricket::ICEROLE_CONTROLLING);
122 } else {
123 SetIceRole_n(cricket::ICEROLE_CONTROLLED);
124 }
125 }
126 return ApplyDescription_n(/*local=*/true, type, description);
127}
128
129RTCError JsepTransportController::SetRemoteDescription(
130 SdpType type,
131 const cricket::SessionDescription* description) {
132 if (!network_thread_->IsCurrent()) {
133 return network_thread_->Invoke<RTCError>(
134 RTC_FROM_HERE, [=] { return SetRemoteDescription(type, description); });
135 }
136
137 return ApplyDescription_n(/*local=*/false, type, description);
138}
139
140RtpTransportInternal* JsepTransportController::GetRtpTransport(
141 const std::string& mid) const {
Zhi Huange830e682018-03-30 10:48:35 -0700142 auto jsep_transport = GetJsepTransportForMid(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -0800143 if (!jsep_transport) {
144 return nullptr;
145 }
146 return jsep_transport->rtp_transport();
147}
148
149cricket::DtlsTransportInternal* JsepTransportController::GetDtlsTransport(
150 const std::string& mid) const {
Zhi Huange830e682018-03-30 10:48:35 -0700151 auto jsep_transport = GetJsepTransportForMid(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -0800152 if (!jsep_transport) {
153 return nullptr;
154 }
155 return jsep_transport->rtp_dtls_transport();
156}
157
158cricket::DtlsTransportInternal* JsepTransportController::GetRtcpDtlsTransport(
159 const std::string& mid) const {
Zhi Huange830e682018-03-30 10:48:35 -0700160 auto jsep_transport = GetJsepTransportForMid(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -0800161 if (!jsep_transport) {
162 return nullptr;
163 }
164 return jsep_transport->rtcp_dtls_transport();
165}
166
167void JsepTransportController::SetIceConfig(const cricket::IceConfig& config) {
168 if (!network_thread_->IsCurrent()) {
169 network_thread_->Invoke<void>(RTC_FROM_HERE, [&] { SetIceConfig(config); });
170 return;
171 }
172
173 ice_config_ = config;
174 for (auto& dtls : GetDtlsTransports()) {
175 dtls->ice_transport()->SetIceConfig(ice_config_);
176 }
177}
178
179void JsepTransportController::SetNeedsIceRestartFlag() {
Zhi Huange830e682018-03-30 10:48:35 -0700180 for (auto& kv : jsep_transports_by_name_) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800181 kv.second->SetNeedsIceRestartFlag();
182 }
183}
184
185bool JsepTransportController::NeedsIceRestart(
186 const std::string& transport_name) const {
Zhi Huang365381f2018-04-13 16:44:34 -0700187 const cricket::JsepTransport* transport =
Zhi Huange830e682018-03-30 10:48:35 -0700188 GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800189 if (!transport) {
190 return false;
191 }
192 return transport->needs_ice_restart();
193}
194
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200195absl::optional<rtc::SSLRole> JsepTransportController::GetDtlsRole(
Zhi Huange830e682018-03-30 10:48:35 -0700196 const std::string& mid) const {
Zhi Huange818b6e2018-02-22 15:26:27 -0800197 if (!network_thread_->IsCurrent()) {
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200198 return network_thread_->Invoke<absl::optional<rtc::SSLRole>>(
Zhi Huange830e682018-03-30 10:48:35 -0700199 RTC_FROM_HERE, [&] { return GetDtlsRole(mid); });
Zhi Huange818b6e2018-02-22 15:26:27 -0800200 }
201
Zhi Huang365381f2018-04-13 16:44:34 -0700202 const cricket::JsepTransport* t = GetJsepTransportForMid(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -0800203 if (!t) {
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200204 return absl::optional<rtc::SSLRole>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800205 }
206 return t->GetDtlsRole();
207}
208
209bool JsepTransportController::SetLocalCertificate(
210 const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) {
211 if (!network_thread_->IsCurrent()) {
212 return network_thread_->Invoke<bool>(
213 RTC_FROM_HERE, [&] { return SetLocalCertificate(certificate); });
214 }
215
216 // Can't change a certificate, or set a null certificate.
217 if (certificate_ || !certificate) {
218 return false;
219 }
220 certificate_ = certificate;
221
222 // Set certificate for JsepTransport, which verifies it matches the
223 // fingerprint in SDP, and DTLS transport.
224 // Fallback from DTLS to SDES is not supported.
Zhi Huange830e682018-03-30 10:48:35 -0700225 for (auto& kv : jsep_transports_by_name_) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800226 kv.second->SetLocalCertificate(certificate_);
227 }
228 for (auto& dtls : GetDtlsTransports()) {
229 bool set_cert_success = dtls->SetLocalCertificate(certificate_);
230 RTC_DCHECK(set_cert_success);
231 }
232 return true;
233}
234
235rtc::scoped_refptr<rtc::RTCCertificate>
236JsepTransportController::GetLocalCertificate(
237 const std::string& transport_name) const {
238 if (!network_thread_->IsCurrent()) {
239 return network_thread_->Invoke<rtc::scoped_refptr<rtc::RTCCertificate>>(
240 RTC_FROM_HERE, [&] { return GetLocalCertificate(transport_name); });
241 }
242
Zhi Huang365381f2018-04-13 16:44:34 -0700243 const cricket::JsepTransport* t = GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800244 if (!t) {
245 return nullptr;
246 }
247 return t->GetLocalCertificate();
248}
249
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800250std::unique_ptr<rtc::SSLCertChain>
251JsepTransportController::GetRemoteSSLCertChain(
Zhi Huange818b6e2018-02-22 15:26:27 -0800252 const std::string& transport_name) const {
253 if (!network_thread_->IsCurrent()) {
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800254 return network_thread_->Invoke<std::unique_ptr<rtc::SSLCertChain>>(
255 RTC_FROM_HERE, [&] { return GetRemoteSSLCertChain(transport_name); });
Zhi Huange818b6e2018-02-22 15:26:27 -0800256 }
257
Zhi Huange830e682018-03-30 10:48:35 -0700258 // Get the certificate from the RTP transport's DTLS handshake. Should be
259 // identical to the RTCP transport's, since they were given the same remote
Zhi Huange818b6e2018-02-22 15:26:27 -0800260 // fingerprint.
Zhi Huange830e682018-03-30 10:48:35 -0700261 auto jsep_transport = GetJsepTransportByName(transport_name);
262 if (!jsep_transport) {
263 return nullptr;
264 }
265 auto dtls = jsep_transport->rtp_dtls_transport();
Zhi Huange818b6e2018-02-22 15:26:27 -0800266 if (!dtls) {
267 return nullptr;
268 }
269
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800270 return dtls->GetRemoteSSLCertChain();
Zhi Huange818b6e2018-02-22 15:26:27 -0800271}
272
273void JsepTransportController::MaybeStartGathering() {
274 if (!network_thread_->IsCurrent()) {
275 network_thread_->Invoke<void>(RTC_FROM_HERE,
276 [&] { MaybeStartGathering(); });
277 return;
278 }
279
280 for (auto& dtls : GetDtlsTransports()) {
281 dtls->ice_transport()->MaybeStartGathering();
282 }
283}
284
285RTCError JsepTransportController::AddRemoteCandidates(
286 const std::string& transport_name,
287 const cricket::Candidates& candidates) {
288 if (!network_thread_->IsCurrent()) {
289 return network_thread_->Invoke<RTCError>(RTC_FROM_HERE, [&] {
290 return AddRemoteCandidates(transport_name, candidates);
291 });
292 }
293
294 // Verify each candidate before passing down to the transport layer.
295 RTCError error = VerifyCandidates(candidates);
296 if (!error.ok()) {
297 return error;
298 }
Zhi Huange830e682018-03-30 10:48:35 -0700299 auto jsep_transport = GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800300 if (!jsep_transport) {
Zhi Huange830e682018-03-30 10:48:35 -0700301 RTC_LOG(LS_WARNING) << "Not adding candidate because the JsepTransport "
302 "doesn't exist. Ignore it.";
303 return RTCError::OK();
Zhi Huange818b6e2018-02-22 15:26:27 -0800304 }
Zhi Huange818b6e2018-02-22 15:26:27 -0800305 return jsep_transport->AddRemoteCandidates(candidates);
306}
307
308RTCError JsepTransportController::RemoveRemoteCandidates(
309 const cricket::Candidates& candidates) {
310 if (!network_thread_->IsCurrent()) {
311 return network_thread_->Invoke<RTCError>(
312 RTC_FROM_HERE, [&] { return RemoveRemoteCandidates(candidates); });
313 }
314
315 // Verify each candidate before passing down to the transport layer.
316 RTCError error = VerifyCandidates(candidates);
317 if (!error.ok()) {
318 return error;
319 }
320
321 std::map<std::string, cricket::Candidates> candidates_by_transport_name;
322 for (const cricket::Candidate& cand : candidates) {
323 if (!cand.transport_name().empty()) {
324 candidates_by_transport_name[cand.transport_name()].push_back(cand);
325 } else {
326 RTC_LOG(LS_ERROR) << "Not removing candidate because it does not have a "
327 "transport name set: "
328 << cand.ToString();
329 }
330 }
331
332 for (const auto& kv : candidates_by_transport_name) {
333 const std::string& transport_name = kv.first;
334 const cricket::Candidates& candidates = kv.second;
Zhi Huang365381f2018-04-13 16:44:34 -0700335 cricket::JsepTransport* jsep_transport =
Zhi Huange830e682018-03-30 10:48:35 -0700336 GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800337 if (!jsep_transport) {
Zhi Huange830e682018-03-30 10:48:35 -0700338 RTC_LOG(LS_WARNING)
339 << "Not removing candidate because the JsepTransport doesn't exist.";
340 continue;
Zhi Huange818b6e2018-02-22 15:26:27 -0800341 }
342 for (const cricket::Candidate& candidate : candidates) {
343 auto dtls = candidate.component() == cricket::ICE_CANDIDATE_COMPONENT_RTP
344 ? jsep_transport->rtp_dtls_transport()
345 : jsep_transport->rtcp_dtls_transport();
346 if (dtls) {
347 dtls->ice_transport()->RemoveRemoteCandidate(candidate);
348 }
349 }
350 }
351 return RTCError::OK();
352}
353
354bool JsepTransportController::GetStats(const std::string& transport_name,
355 cricket::TransportStats* stats) {
356 if (!network_thread_->IsCurrent()) {
357 return network_thread_->Invoke<bool>(
358 RTC_FROM_HERE, [=] { return GetStats(transport_name, stats); });
359 }
360
Zhi Huang365381f2018-04-13 16:44:34 -0700361 cricket::JsepTransport* transport = GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800362 if (!transport) {
363 return false;
364 }
365 return transport->GetStats(stats);
366}
367
368void JsepTransportController::SetMetricsObserver(
369 webrtc::MetricsObserverInterface* metrics_observer) {
370 if (!network_thread_->IsCurrent()) {
371 network_thread_->Invoke<void>(
372 RTC_FROM_HERE, [=] { SetMetricsObserver(metrics_observer); });
373 return;
374 }
375
376 metrics_observer_ = metrics_observer;
377 for (auto& dtls : GetDtlsTransports()) {
378 dtls->ice_transport()->SetMetricsObserver(metrics_observer);
379 }
380}
381
Zhi Huangb57e1692018-06-12 11:41:11 -0700382void JsepTransportController::SetActiveResetSrtpParams(
383 bool active_reset_srtp_params) {
384 if (!network_thread_->IsCurrent()) {
385 network_thread_->Invoke<void>(RTC_FROM_HERE, [=] {
386 SetActiveResetSrtpParams(active_reset_srtp_params);
387 });
388 return;
389 }
390
391 RTC_LOG(INFO)
392 << "Updating the active_reset_srtp_params for JsepTransportController: "
393 << active_reset_srtp_params;
394 config_.active_reset_srtp_params = active_reset_srtp_params;
395 for (auto& kv : jsep_transports_by_name_) {
396 kv.second->SetActiveResetSrtpParams(active_reset_srtp_params);
397 }
398}
399
Zhi Huange818b6e2018-02-22 15:26:27 -0800400std::unique_ptr<cricket::DtlsTransportInternal>
401JsepTransportController::CreateDtlsTransport(const std::string& transport_name,
402 bool rtcp) {
403 RTC_DCHECK(network_thread_->IsCurrent());
404 int component = rtcp ? cricket::ICE_CANDIDATE_COMPONENT_RTCP
405 : cricket::ICE_CANDIDATE_COMPONENT_RTP;
406
407 std::unique_ptr<cricket::DtlsTransportInternal> dtls;
408 if (config_.external_transport_factory) {
409 auto ice = config_.external_transport_factory->CreateIceTransport(
410 transport_name, component);
411 dtls = config_.external_transport_factory->CreateDtlsTransport(
412 std::move(ice), config_.crypto_options);
413 } else {
414 auto ice = rtc::MakeUnique<cricket::P2PTransportChannel>(
Qingsi Wang7685e862018-06-11 20:15:46 -0700415 transport_name, component, port_allocator_, config_.event_log);
Zhi Huange818b6e2018-02-22 15:26:27 -0800416 dtls = rtc::MakeUnique<cricket::DtlsTransport>(std::move(ice),
417 config_.crypto_options);
418 }
419
420 RTC_DCHECK(dtls);
421 dtls->SetSslMaxProtocolVersion(config_.ssl_max_version);
422 dtls->ice_transport()->SetMetricsObserver(metrics_observer_);
423 dtls->ice_transport()->SetIceRole(ice_role_);
424 dtls->ice_transport()->SetIceTiebreaker(ice_tiebreaker_);
425 dtls->ice_transport()->SetIceConfig(ice_config_);
426 if (certificate_) {
427 bool set_cert_success = dtls->SetLocalCertificate(certificate_);
428 RTC_DCHECK(set_cert_success);
429 }
430
431 // Connect to signals offered by the DTLS and ICE transport.
432 dtls->SignalWritableState.connect(
433 this, &JsepTransportController::OnTransportWritableState_n);
434 dtls->SignalReceivingState.connect(
435 this, &JsepTransportController::OnTransportReceivingState_n);
436 dtls->SignalDtlsHandshakeError.connect(
437 this, &JsepTransportController::OnDtlsHandshakeError);
438 dtls->ice_transport()->SignalGatheringState.connect(
439 this, &JsepTransportController::OnTransportGatheringState_n);
440 dtls->ice_transport()->SignalCandidateGathered.connect(
441 this, &JsepTransportController::OnTransportCandidateGathered_n);
442 dtls->ice_transport()->SignalCandidatesRemoved.connect(
443 this, &JsepTransportController::OnTransportCandidatesRemoved_n);
444 dtls->ice_transport()->SignalRoleConflict.connect(
445 this, &JsepTransportController::OnTransportRoleConflict_n);
446 dtls->ice_transport()->SignalStateChanged.connect(
447 this, &JsepTransportController::OnTransportStateChanged_n);
448 return dtls;
449}
450
451std::unique_ptr<webrtc::RtpTransport>
452JsepTransportController::CreateUnencryptedRtpTransport(
453 const std::string& transport_name,
454 rtc::PacketTransportInternal* rtp_packet_transport,
455 rtc::PacketTransportInternal* rtcp_packet_transport) {
456 RTC_DCHECK(network_thread_->IsCurrent());
Zhi Huange830e682018-03-30 10:48:35 -0700457 auto unencrypted_rtp_transport =
458 rtc::MakeUnique<RtpTransport>(rtcp_packet_transport == nullptr);
459 unencrypted_rtp_transport->SetRtpPacketTransport(rtp_packet_transport);
460 if (rtcp_packet_transport) {
461 unencrypted_rtp_transport->SetRtcpPacketTransport(rtcp_packet_transport);
462 }
463 return unencrypted_rtp_transport;
Zhi Huange818b6e2018-02-22 15:26:27 -0800464}
465
466std::unique_ptr<webrtc::SrtpTransport>
467JsepTransportController::CreateSdesTransport(
468 const std::string& transport_name,
Zhi Huange830e682018-03-30 10:48:35 -0700469 cricket::DtlsTransportInternal* rtp_dtls_transport,
470 cricket::DtlsTransportInternal* rtcp_dtls_transport) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800471 RTC_DCHECK(network_thread_->IsCurrent());
Zhi Huange818b6e2018-02-22 15:26:27 -0800472 auto srtp_transport =
Zhi Huange830e682018-03-30 10:48:35 -0700473 rtc::MakeUnique<webrtc::SrtpTransport>(rtcp_dtls_transport == nullptr);
474 RTC_DCHECK(rtp_dtls_transport);
475 srtp_transport->SetRtpPacketTransport(rtp_dtls_transport);
476 if (rtcp_dtls_transport) {
477 srtp_transport->SetRtcpPacketTransport(rtcp_dtls_transport);
Zhi Huange818b6e2018-02-22 15:26:27 -0800478 }
479 if (config_.enable_external_auth) {
480 srtp_transport->EnableExternalAuth();
481 }
482 return srtp_transport;
483}
484
485std::unique_ptr<webrtc::DtlsSrtpTransport>
486JsepTransportController::CreateDtlsSrtpTransport(
487 const std::string& transport_name,
488 cricket::DtlsTransportInternal* rtp_dtls_transport,
489 cricket::DtlsTransportInternal* rtcp_dtls_transport) {
490 RTC_DCHECK(network_thread_->IsCurrent());
Zhi Huang365381f2018-04-13 16:44:34 -0700491 auto dtls_srtp_transport = rtc::MakeUnique<webrtc::DtlsSrtpTransport>(
492 rtcp_dtls_transport == nullptr);
Zhi Huang27f3bf52018-03-26 21:37:23 -0700493 if (config_.enable_external_auth) {
Zhi Huang365381f2018-04-13 16:44:34 -0700494 dtls_srtp_transport->EnableExternalAuth();
Zhi Huang27f3bf52018-03-26 21:37:23 -0700495 }
Zhi Huang97d5e5b2018-03-27 00:09:01 +0000496
Zhi Huange818b6e2018-02-22 15:26:27 -0800497 dtls_srtp_transport->SetDtlsTransports(rtp_dtls_transport,
498 rtcp_dtls_transport);
Zhi Huangb57e1692018-06-12 11:41:11 -0700499 dtls_srtp_transport->SetActiveResetSrtpParams(
500 config_.active_reset_srtp_params);
Zhi Huange818b6e2018-02-22 15:26:27 -0800501 return dtls_srtp_transport;
502}
503
504std::vector<cricket::DtlsTransportInternal*>
505JsepTransportController::GetDtlsTransports() {
506 std::vector<cricket::DtlsTransportInternal*> dtls_transports;
Zhi Huange830e682018-03-30 10:48:35 -0700507 for (auto it = jsep_transports_by_name_.begin();
508 it != jsep_transports_by_name_.end(); ++it) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800509 auto jsep_transport = it->second.get();
510 RTC_DCHECK(jsep_transport);
511 if (jsep_transport->rtp_dtls_transport()) {
512 dtls_transports.push_back(jsep_transport->rtp_dtls_transport());
513 }
514
515 if (jsep_transport->rtcp_dtls_transport()) {
516 dtls_transports.push_back(jsep_transport->rtcp_dtls_transport());
517 }
518 }
519 return dtls_transports;
520}
521
522void JsepTransportController::OnMessage(rtc::Message* pmsg) {
523 RTC_DCHECK(signaling_thread_->IsCurrent());
524
525 switch (pmsg->message_id) {
526 case MSG_ICECONNECTIONSTATE: {
527 rtc::TypedMessageData<cricket::IceConnectionState>* data =
528 static_cast<rtc::TypedMessageData<cricket::IceConnectionState>*>(
529 pmsg->pdata);
530 SignalIceConnectionState(data->data());
531 delete data;
532 break;
533 }
534 case MSG_ICEGATHERINGSTATE: {
535 rtc::TypedMessageData<cricket::IceGatheringState>* data =
536 static_cast<rtc::TypedMessageData<cricket::IceGatheringState>*>(
537 pmsg->pdata);
538 SignalIceGatheringState(data->data());
539 delete data;
540 break;
541 }
542 case MSG_ICECANDIDATESGATHERED: {
543 CandidatesData* data = static_cast<CandidatesData*>(pmsg->pdata);
544 SignalIceCandidatesGathered(data->transport_name, data->candidates);
545 delete data;
546 break;
547 }
548 default:
549 RTC_NOTREACHED();
550 }
551}
552
553RTCError JsepTransportController::ApplyDescription_n(
554 bool local,
555 SdpType type,
556 const cricket::SessionDescription* description) {
557 RTC_DCHECK(network_thread_->IsCurrent());
558 RTC_DCHECK(description);
559
560 if (local) {
561 local_desc_ = description;
562 } else {
563 remote_desc_ = description;
564 }
565
Zhi Huange830e682018-03-30 10:48:35 -0700566 RTCError error;
Zhi Huangd2248f82018-04-10 14:41:03 -0700567 error = ValidateAndMaybeUpdateBundleGroup(local, type, description);
Zhi Huange830e682018-03-30 10:48:35 -0700568 if (!error.ok()) {
569 return error;
Zhi Huange818b6e2018-02-22 15:26:27 -0800570 }
571
572 std::vector<int> merged_encrypted_extension_ids;
573 if (bundle_group_) {
574 merged_encrypted_extension_ids =
575 MergeEncryptedHeaderExtensionIdsForBundle(description);
576 }
577
578 for (const cricket::ContentInfo& content_info : description->contents()) {
579 // Don't create transports for rejected m-lines and bundled m-lines."
580 if (content_info.rejected ||
581 (IsBundled(content_info.name) && content_info.name != *bundled_mid())) {
582 continue;
583 }
Zhi Huangd2248f82018-04-10 14:41:03 -0700584 error = MaybeCreateJsepTransport(content_info);
Zhi Huange830e682018-03-30 10:48:35 -0700585 if (!error.ok()) {
586 return error;
587 }
Zhi Huange818b6e2018-02-22 15:26:27 -0800588 }
589
590 RTC_DCHECK(description->contents().size() ==
591 description->transport_infos().size());
592 for (size_t i = 0; i < description->contents().size(); ++i) {
593 const cricket::ContentInfo& content_info = description->contents()[i];
594 const cricket::TransportInfo& transport_info =
595 description->transport_infos()[i];
596 if (content_info.rejected) {
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700597 HandleRejectedContent(content_info, description);
Zhi Huange818b6e2018-02-22 15:26:27 -0800598 continue;
599 }
600
601 if (IsBundled(content_info.name) && content_info.name != *bundled_mid()) {
Zhi Huang365381f2018-04-13 16:44:34 -0700602 if (!HandleBundledContent(content_info)) {
603 return RTCError(RTCErrorType::INVALID_PARAMETER,
604 "Failed to process the bundled m= section.");
605 }
Zhi Huange818b6e2018-02-22 15:26:27 -0800606 continue;
607 }
608
Zhi Huange830e682018-03-30 10:48:35 -0700609 error = ValidateContent(content_info);
610 if (!error.ok()) {
611 return error;
612 }
613
Zhi Huange818b6e2018-02-22 15:26:27 -0800614 std::vector<int> extension_ids;
Taylor Brandstetter0ab56512018-04-12 10:30:48 -0700615 if (bundled_mid() && content_info.name == *bundled_mid()) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800616 extension_ids = merged_encrypted_extension_ids;
617 } else {
618 extension_ids = GetEncryptedHeaderExtensionIds(content_info);
619 }
620
Zhi Huange830e682018-03-30 10:48:35 -0700621 int rtp_abs_sendtime_extn_id =
622 GetRtpAbsSendTimeHeaderExtensionId(content_info);
623
Zhi Huang365381f2018-04-13 16:44:34 -0700624 cricket::JsepTransport* transport =
Zhi Huange830e682018-03-30 10:48:35 -0700625 GetJsepTransportForMid(content_info.name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800626 RTC_DCHECK(transport);
627
628 SetIceRole_n(DetermineIceRole(transport, transport_info, type, local));
629
Zhi Huange818b6e2018-02-22 15:26:27 -0800630 cricket::JsepTransportDescription jsep_description =
631 CreateJsepTransportDescription(content_info, transport_info,
Zhi Huange830e682018-03-30 10:48:35 -0700632 extension_ids, rtp_abs_sendtime_extn_id);
Zhi Huange818b6e2018-02-22 15:26:27 -0800633 if (local) {
634 error =
635 transport->SetLocalJsepTransportDescription(jsep_description, type);
636 } else {
637 error =
638 transport->SetRemoteJsepTransportDescription(jsep_description, type);
639 }
640
641 if (!error.ok()) {
642 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
643 "Failed to apply the description for " +
644 content_info.name + ": " + error.message());
645 }
646 }
647 return RTCError::OK();
648}
649
Zhi Huangd2248f82018-04-10 14:41:03 -0700650RTCError JsepTransportController::ValidateAndMaybeUpdateBundleGroup(
651 bool local,
652 SdpType type,
Zhi Huange830e682018-03-30 10:48:35 -0700653 const cricket::SessionDescription* description) {
654 RTC_DCHECK(description);
Zhi Huangd2248f82018-04-10 14:41:03 -0700655 const cricket::ContentGroup* new_bundle_group =
656 description->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
657
658 // The BUNDLE group containing a MID that no m= section has is invalid.
659 if (new_bundle_group) {
660 for (auto content_name : new_bundle_group->content_names()) {
661 if (!description->GetContentByName(content_name)) {
662 return RTCError(RTCErrorType::INVALID_PARAMETER,
663 "The BUNDLE group contains MID:" + content_name +
664 " matching no m= section.");
665 }
666 }
667 }
668
669 if (type == SdpType::kAnswer) {
670 const cricket::ContentGroup* offered_bundle_group =
671 local ? remote_desc_->GetGroupByName(cricket::GROUP_TYPE_BUNDLE)
672 : local_desc_->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
673
674 if (new_bundle_group) {
675 // The BUNDLE group in answer should be a subset of offered group.
676 for (auto content_name : new_bundle_group->content_names()) {
677 if (!offered_bundle_group ||
678 !offered_bundle_group->HasContentName(content_name)) {
679 return RTCError(RTCErrorType::INVALID_PARAMETER,
680 "The BUNDLE group in answer contains a MID that was "
681 "not in the offered group.");
682 }
683 }
684 }
685
686 if (bundle_group_) {
687 for (auto content_name : bundle_group_->content_names()) {
688 // An answer that removes m= sections from pre-negotiated BUNDLE group
689 // without rejecting it, is invalid.
690 if (!new_bundle_group ||
691 !new_bundle_group->HasContentName(content_name)) {
692 auto* content_info = description->GetContentByName(content_name);
693 if (!content_info || !content_info->rejected) {
694 return RTCError(RTCErrorType::INVALID_PARAMETER,
695 "Answer cannot remove m= section " + content_name +
696 " from already-established BUNDLE group.");
697 }
698 }
699 }
700 }
701 }
702
703 if (config_.bundle_policy ==
704 PeerConnectionInterface::kBundlePolicyMaxBundle &&
705 !description->HasGroup(cricket::GROUP_TYPE_BUNDLE)) {
706 return RTCError(RTCErrorType::INVALID_PARAMETER,
707 "max-bundle is used but no bundle group found.");
708 }
709
710 if (ShouldUpdateBundleGroup(type, description)) {
Taylor Brandstetter0ab56512018-04-12 10:30:48 -0700711 const std::string* new_bundled_mid = new_bundle_group->FirstContentName();
712 if (bundled_mid() && new_bundled_mid &&
713 *bundled_mid() != *new_bundled_mid) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700714 return RTCError(RTCErrorType::UNSUPPORTED_OPERATION,
715 "Changing the negotiated BUNDLE-tag is not supported.");
716 }
717
718 bundle_group_ = *new_bundle_group;
719 }
Zhi Huange830e682018-03-30 10:48:35 -0700720
721 if (!bundled_mid()) {
722 return RTCError::OK();
723 }
724
725 auto bundled_content = description->GetContentByName(*bundled_mid());
726 if (!bundled_content) {
727 return RTCError(
728 RTCErrorType::INVALID_PARAMETER,
729 "An m= section associated with the BUNDLE-tag doesn't exist.");
730 }
731
732 // If the |bundled_content| is rejected, other contents in the bundle group
733 // should be rejected.
734 if (bundled_content->rejected) {
735 for (auto content_name : bundle_group_->content_names()) {
736 auto other_content = description->GetContentByName(content_name);
737 if (!other_content->rejected) {
738 return RTCError(
739 RTCErrorType::INVALID_PARAMETER,
740 "The m= section:" + content_name + " should be rejected.");
741 }
742 }
743 }
744
745 return RTCError::OK();
746}
747
748RTCError JsepTransportController::ValidateContent(
749 const cricket::ContentInfo& content_info) {
750 if (config_.rtcp_mux_policy ==
751 PeerConnectionInterface::kRtcpMuxPolicyRequire &&
752 content_info.type == cricket::MediaProtocolType::kRtp &&
753 !content_info.media_description()->rtcp_mux()) {
754 return RTCError(RTCErrorType::INVALID_PARAMETER,
755 "The m= section:" + content_info.name +
756 " is invalid. RTCP-MUX is not "
757 "enabled when it is required.");
758 }
759 return RTCError::OK();
760}
761
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700762void JsepTransportController::HandleRejectedContent(
Zhi Huangd2248f82018-04-10 14:41:03 -0700763 const cricket::ContentInfo& content_info,
764 const cricket::SessionDescription* description) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800765 // If the content is rejected, let the
766 // BaseChannel/SctpTransport change the RtpTransport/DtlsTransport first,
Zhi Huang365381f2018-04-13 16:44:34 -0700767 // then destroy the cricket::JsepTransport.
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700768 RemoveTransportForMid(content_info.name);
Zhi Huange830e682018-03-30 10:48:35 -0700769 if (content_info.name == bundled_mid()) {
770 for (auto content_name : bundle_group_->content_names()) {
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700771 RemoveTransportForMid(content_name);
Zhi Huange830e682018-03-30 10:48:35 -0700772 }
773 bundle_group_.reset();
774 } else if (IsBundled(content_info.name)) {
775 // Remove the rejected content from the |bundle_group_|.
Zhi Huange818b6e2018-02-22 15:26:27 -0800776 bundle_group_->RemoveContentName(content_info.name);
Zhi Huange830e682018-03-30 10:48:35 -0700777 // Reset the bundle group if nothing left.
778 if (!bundle_group_->FirstContentName()) {
779 bundle_group_.reset();
780 }
Zhi Huange818b6e2018-02-22 15:26:27 -0800781 }
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700782 MaybeDestroyJsepTransport(content_info.name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800783}
784
Zhi Huang365381f2018-04-13 16:44:34 -0700785bool JsepTransportController::HandleBundledContent(
Zhi Huange818b6e2018-02-22 15:26:27 -0800786 const cricket::ContentInfo& content_info) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700787 auto jsep_transport = GetJsepTransportByName(*bundled_mid());
788 RTC_DCHECK(jsep_transport);
Zhi Huange818b6e2018-02-22 15:26:27 -0800789 // If the content is bundled, let the
790 // BaseChannel/SctpTransport change the RtpTransport/DtlsTransport first,
Zhi Huang365381f2018-04-13 16:44:34 -0700791 // then destroy the cricket::JsepTransport.
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700792 if (SetTransportForMid(content_info.name, jsep_transport)) {
Zhi Huang365381f2018-04-13 16:44:34 -0700793 MaybeDestroyJsepTransport(content_info.name);
794 return true;
795 }
796 return false;
Zhi Huange818b6e2018-02-22 15:26:27 -0800797}
798
Zhi Huang365381f2018-04-13 16:44:34 -0700799bool JsepTransportController::SetTransportForMid(
Zhi Huangd2248f82018-04-10 14:41:03 -0700800 const std::string& mid,
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700801 cricket::JsepTransport* jsep_transport) {
Zhi Huang365381f2018-04-13 16:44:34 -0700802 RTC_DCHECK(jsep_transport);
Zhi Huangd2248f82018-04-10 14:41:03 -0700803 if (mid_to_transport_[mid] == jsep_transport) {
Zhi Huang365381f2018-04-13 16:44:34 -0700804 return true;
Zhi Huangd2248f82018-04-10 14:41:03 -0700805 }
806
807 mid_to_transport_[mid] = jsep_transport;
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700808 return config_.transport_observer->OnTransportChanged(
809 mid, jsep_transport->rtp_transport(),
810 jsep_transport->rtp_dtls_transport());
Zhi Huangd2248f82018-04-10 14:41:03 -0700811}
812
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700813void JsepTransportController::RemoveTransportForMid(const std::string& mid) {
814 bool ret =
815 config_.transport_observer->OnTransportChanged(mid, nullptr, nullptr);
816 // Calling OnTransportChanged with nullptr should always succeed, since it is
817 // only expected to fail when adding media to a transport (not removing).
818 RTC_DCHECK(ret);
Zhi Huangd2248f82018-04-10 14:41:03 -0700819 mid_to_transport_.erase(mid);
820}
821
Zhi Huange818b6e2018-02-22 15:26:27 -0800822cricket::JsepTransportDescription
823JsepTransportController::CreateJsepTransportDescription(
824 cricket::ContentInfo content_info,
825 cricket::TransportInfo transport_info,
Zhi Huange830e682018-03-30 10:48:35 -0700826 const std::vector<int>& encrypted_extension_ids,
827 int rtp_abs_sendtime_extn_id) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800828 const cricket::MediaContentDescription* content_desc =
829 static_cast<const cricket::MediaContentDescription*>(
830 content_info.description);
831 RTC_DCHECK(content_desc);
832 bool rtcp_mux_enabled = content_info.type == cricket::MediaProtocolType::kSctp
833 ? true
834 : content_desc->rtcp_mux();
835
836 return cricket::JsepTransportDescription(
837 rtcp_mux_enabled, content_desc->cryptos(), encrypted_extension_ids,
Zhi Huange830e682018-03-30 10:48:35 -0700838 rtp_abs_sendtime_extn_id, transport_info.description);
Zhi Huange818b6e2018-02-22 15:26:27 -0800839}
840
841bool JsepTransportController::ShouldUpdateBundleGroup(
842 SdpType type,
843 const cricket::SessionDescription* description) {
844 if (config_.bundle_policy ==
845 PeerConnectionInterface::kBundlePolicyMaxBundle) {
846 return true;
847 }
848
849 if (type != SdpType::kAnswer) {
850 return false;
851 }
852
853 RTC_DCHECK(local_desc_ && remote_desc_);
854 const cricket::ContentGroup* local_bundle =
855 local_desc_->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
856 const cricket::ContentGroup* remote_bundle =
857 remote_desc_->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
858 return local_bundle && remote_bundle;
859}
860
861std::vector<int> JsepTransportController::GetEncryptedHeaderExtensionIds(
862 const cricket::ContentInfo& content_info) {
863 const cricket::MediaContentDescription* content_desc =
864 static_cast<const cricket::MediaContentDescription*>(
865 content_info.description);
866
867 if (!config_.crypto_options.enable_encrypted_rtp_header_extensions) {
868 return std::vector<int>();
869 }
870
871 std::vector<int> encrypted_header_extension_ids;
872 for (auto extension : content_desc->rtp_header_extensions()) {
873 if (!extension.encrypt) {
874 continue;
875 }
876 auto it = std::find(encrypted_header_extension_ids.begin(),
877 encrypted_header_extension_ids.end(), extension.id);
878 if (it == encrypted_header_extension_ids.end()) {
879 encrypted_header_extension_ids.push_back(extension.id);
880 }
881 }
882 return encrypted_header_extension_ids;
883}
884
885std::vector<int>
886JsepTransportController::MergeEncryptedHeaderExtensionIdsForBundle(
887 const cricket::SessionDescription* description) {
888 RTC_DCHECK(description);
889 RTC_DCHECK(bundle_group_);
890
891 std::vector<int> merged_ids;
892 // Union the encrypted header IDs in the group when bundle is enabled.
893 for (const cricket::ContentInfo& content_info : description->contents()) {
894 if (bundle_group_->HasContentName(content_info.name)) {
895 std::vector<int> extension_ids =
896 GetEncryptedHeaderExtensionIds(content_info);
897 for (int id : extension_ids) {
898 auto it = std::find(merged_ids.begin(), merged_ids.end(), id);
899 if (it == merged_ids.end()) {
900 merged_ids.push_back(id);
901 }
902 }
903 }
904 }
905 return merged_ids;
906}
907
Zhi Huange830e682018-03-30 10:48:35 -0700908int JsepTransportController::GetRtpAbsSendTimeHeaderExtensionId(
Zhi Huange818b6e2018-02-22 15:26:27 -0800909 const cricket::ContentInfo& content_info) {
Zhi Huange830e682018-03-30 10:48:35 -0700910 if (!config_.enable_external_auth) {
911 return -1;
Zhi Huange818b6e2018-02-22 15:26:27 -0800912 }
913
914 const cricket::MediaContentDescription* content_desc =
915 static_cast<const cricket::MediaContentDescription*>(
916 content_info.description);
Zhi Huange830e682018-03-30 10:48:35 -0700917
918 const webrtc::RtpExtension* send_time_extension =
919 webrtc::RtpExtension::FindHeaderExtensionByUri(
920 content_desc->rtp_header_extensions(),
921 webrtc::RtpExtension::kAbsSendTimeUri);
922 return send_time_extension ? send_time_extension->id : -1;
923}
924
Zhi Huang365381f2018-04-13 16:44:34 -0700925const cricket::JsepTransport* JsepTransportController::GetJsepTransportForMid(
Zhi Huange830e682018-03-30 10:48:35 -0700926 const std::string& mid) const {
Zhi Huangd2248f82018-04-10 14:41:03 -0700927 auto it = mid_to_transport_.find(mid);
928 return it == mid_to_transport_.end() ? nullptr : it->second;
Zhi Huange830e682018-03-30 10:48:35 -0700929}
930
Zhi Huang365381f2018-04-13 16:44:34 -0700931cricket::JsepTransport* JsepTransportController::GetJsepTransportForMid(
Zhi Huange830e682018-03-30 10:48:35 -0700932 const std::string& mid) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700933 auto it = mid_to_transport_.find(mid);
934 return it == mid_to_transport_.end() ? nullptr : it->second;
Zhi Huange830e682018-03-30 10:48:35 -0700935}
936
Zhi Huang365381f2018-04-13 16:44:34 -0700937const cricket::JsepTransport* JsepTransportController::GetJsepTransportByName(
Zhi Huange830e682018-03-30 10:48:35 -0700938 const std::string& transport_name) const {
939 auto it = jsep_transports_by_name_.find(transport_name);
940 return (it == jsep_transports_by_name_.end()) ? nullptr : it->second.get();
941}
942
Zhi Huang365381f2018-04-13 16:44:34 -0700943cricket::JsepTransport* JsepTransportController::GetJsepTransportByName(
Zhi Huange830e682018-03-30 10:48:35 -0700944 const std::string& transport_name) {
945 auto it = jsep_transports_by_name_.find(transport_name);
946 return (it == jsep_transports_by_name_.end()) ? nullptr : it->second.get();
947}
948
949RTCError JsepTransportController::MaybeCreateJsepTransport(
Zhi Huange830e682018-03-30 10:48:35 -0700950 const cricket::ContentInfo& content_info) {
951 RTC_DCHECK(network_thread_->IsCurrent());
Zhi Huang365381f2018-04-13 16:44:34 -0700952 cricket::JsepTransport* transport = GetJsepTransportByName(content_info.name);
Zhi Huange830e682018-03-30 10:48:35 -0700953 if (transport) {
954 return RTCError::OK();
955 }
956
957 const cricket::MediaContentDescription* content_desc =
958 static_cast<const cricket::MediaContentDescription*>(
959 content_info.description);
960 if (certificate_ && !content_desc->cryptos().empty()) {
961 return RTCError(RTCErrorType::INVALID_PARAMETER,
962 "SDES and DTLS-SRTP cannot be enabled at the same time.");
963 }
964
Zhi Huange818b6e2018-02-22 15:26:27 -0800965 std::unique_ptr<cricket::DtlsTransportInternal> rtp_dtls_transport =
Zhi Huangd2248f82018-04-10 14:41:03 -0700966 CreateDtlsTransport(content_info.name, /*rtcp =*/false);
Zhi Huange818b6e2018-02-22 15:26:27 -0800967 std::unique_ptr<cricket::DtlsTransportInternal> rtcp_dtls_transport;
Zhi Huange830e682018-03-30 10:48:35 -0700968 if (config_.rtcp_mux_policy !=
969 PeerConnectionInterface::kRtcpMuxPolicyRequire &&
970 content_info.type == cricket::MediaProtocolType::kRtp) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700971 rtcp_dtls_transport =
972 CreateDtlsTransport(content_info.name, /*rtcp =*/true);
Zhi Huange818b6e2018-02-22 15:26:27 -0800973 }
974
975 std::unique_ptr<RtpTransport> unencrypted_rtp_transport;
976 std::unique_ptr<SrtpTransport> sdes_transport;
977 std::unique_ptr<DtlsSrtpTransport> dtls_srtp_transport;
978 if (config_.disable_encryption) {
979 unencrypted_rtp_transport = CreateUnencryptedRtpTransport(
Zhi Huangd2248f82018-04-10 14:41:03 -0700980 content_info.name, rtp_dtls_transport.get(), rtcp_dtls_transport.get());
Zhi Huange818b6e2018-02-22 15:26:27 -0800981 } else if (!content_desc->cryptos().empty()) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700982 sdes_transport = CreateSdesTransport(
983 content_info.name, rtp_dtls_transport.get(), rtcp_dtls_transport.get());
Zhi Huange818b6e2018-02-22 15:26:27 -0800984 } else {
Zhi Huangd2248f82018-04-10 14:41:03 -0700985 dtls_srtp_transport = CreateDtlsSrtpTransport(
986 content_info.name, rtp_dtls_transport.get(), rtcp_dtls_transport.get());
Zhi Huange818b6e2018-02-22 15:26:27 -0800987 }
988
Zhi Huang365381f2018-04-13 16:44:34 -0700989 std::unique_ptr<cricket::JsepTransport> jsep_transport =
990 rtc::MakeUnique<cricket::JsepTransport>(
Zhi Huangd2248f82018-04-10 14:41:03 -0700991 content_info.name, certificate_, std::move(unencrypted_rtp_transport),
Zhi Huange818b6e2018-02-22 15:26:27 -0800992 std::move(sdes_transport), std::move(dtls_srtp_transport),
993 std::move(rtp_dtls_transport), std::move(rtcp_dtls_transport));
994 jsep_transport->SignalRtcpMuxActive.connect(
995 this, &JsepTransportController::UpdateAggregateStates_n);
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700996 SetTransportForMid(content_info.name, jsep_transport.get());
Zhi Huange830e682018-03-30 10:48:35 -0700997
Zhi Huangd2248f82018-04-10 14:41:03 -0700998 jsep_transports_by_name_[content_info.name] = std::move(jsep_transport);
999 UpdateAggregateStates_n();
Zhi Huange830e682018-03-30 10:48:35 -07001000 return RTCError::OK();
Zhi Huange818b6e2018-02-22 15:26:27 -08001001}
1002
1003void JsepTransportController::MaybeDestroyJsepTransport(
1004 const std::string& mid) {
Zhi Huangd2248f82018-04-10 14:41:03 -07001005 auto jsep_transport = GetJsepTransportByName(mid);
1006 if (!jsep_transport) {
1007 return;
1008 }
1009
1010 // Don't destroy the JsepTransport if there are still media sections referring
1011 // to it.
1012 for (const auto& kv : mid_to_transport_) {
1013 if (kv.second == jsep_transport) {
1014 return;
1015 }
1016 }
Zhi Huange830e682018-03-30 10:48:35 -07001017 jsep_transports_by_name_.erase(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -08001018 UpdateAggregateStates_n();
1019}
1020
1021void JsepTransportController::DestroyAllJsepTransports_n() {
1022 RTC_DCHECK(network_thread_->IsCurrent());
Zhi Huange830e682018-03-30 10:48:35 -07001023 jsep_transports_by_name_.clear();
Zhi Huange818b6e2018-02-22 15:26:27 -08001024}
1025
1026void JsepTransportController::SetIceRole_n(cricket::IceRole ice_role) {
1027 RTC_DCHECK(network_thread_->IsCurrent());
1028
1029 ice_role_ = ice_role;
1030 for (auto& dtls : GetDtlsTransports()) {
1031 dtls->ice_transport()->SetIceRole(ice_role_);
1032 }
1033}
1034
1035cricket::IceRole JsepTransportController::DetermineIceRole(
Zhi Huang365381f2018-04-13 16:44:34 -07001036 cricket::JsepTransport* jsep_transport,
Zhi Huange818b6e2018-02-22 15:26:27 -08001037 const cricket::TransportInfo& transport_info,
1038 SdpType type,
1039 bool local) {
1040 cricket::IceRole ice_role = ice_role_;
1041 auto tdesc = transport_info.description;
1042 if (local) {
1043 // The initial offer side may use ICE Lite, in which case, per RFC5245
1044 // Section 5.1.1, the answer side should take the controlling role if it is
1045 // in the full ICE mode.
1046 //
1047 // When both sides use ICE Lite, the initial offer side must take the
1048 // controlling role, and this is the default logic implemented in
1049 // SetLocalDescription in JsepTransportController.
1050 if (jsep_transport->remote_description() &&
1051 jsep_transport->remote_description()->transport_desc.ice_mode ==
1052 cricket::ICEMODE_LITE &&
1053 ice_role_ == cricket::ICEROLE_CONTROLLED &&
1054 tdesc.ice_mode == cricket::ICEMODE_FULL) {
1055 ice_role = cricket::ICEROLE_CONTROLLING;
1056 }
1057
1058 // Older versions of Chrome expect the ICE role to be re-determined when an
1059 // ICE restart occurs, and also don't perform conflict resolution correctly,
1060 // so for now we can't safely stop doing this, unless the application opts
1061 // in by setting |config_.redetermine_role_on_ice_restart_| to false. See:
1062 // https://bugs.chromium.org/p/chromium/issues/detail?id=628676
1063 // TODO(deadbeef): Remove this when these old versions of Chrome reach a low
1064 // enough population.
1065 if (config_.redetermine_role_on_ice_restart &&
1066 jsep_transport->local_description() &&
1067 cricket::IceCredentialsChanged(
1068 jsep_transport->local_description()->transport_desc.ice_ufrag,
1069 jsep_transport->local_description()->transport_desc.ice_pwd,
1070 tdesc.ice_ufrag, tdesc.ice_pwd) &&
1071 // Don't change the ICE role if the remote endpoint is ICE lite; we
1072 // should always be controlling in that case.
1073 (!jsep_transport->remote_description() ||
1074 jsep_transport->remote_description()->transport_desc.ice_mode !=
1075 cricket::ICEMODE_LITE)) {
1076 ice_role = (type == SdpType::kOffer) ? cricket::ICEROLE_CONTROLLING
1077 : cricket::ICEROLE_CONTROLLED;
1078 }
1079 } else {
1080 // If our role is cricket::ICEROLE_CONTROLLED and the remote endpoint
1081 // supports only ice_lite, this local endpoint should take the CONTROLLING
1082 // role.
1083 // TODO(deadbeef): This is a session-level attribute, so it really shouldn't
1084 // be in a TransportDescription in the first place...
1085 if (ice_role_ == cricket::ICEROLE_CONTROLLED &&
1086 tdesc.ice_mode == cricket::ICEMODE_LITE) {
1087 ice_role = cricket::ICEROLE_CONTROLLING;
1088 }
1089
1090 // If we use ICE Lite and the remote endpoint uses the full implementation
1091 // of ICE, the local endpoint must take the controlled role, and the other
1092 // side must be the controlling role.
1093 if (jsep_transport->local_description() &&
1094 jsep_transport->local_description()->transport_desc.ice_mode ==
1095 cricket::ICEMODE_LITE &&
1096 ice_role_ == cricket::ICEROLE_CONTROLLING &&
Zhi Huange830e682018-03-30 10:48:35 -07001097 tdesc.ice_mode == cricket::ICEMODE_FULL) {
Zhi Huange818b6e2018-02-22 15:26:27 -08001098 ice_role = cricket::ICEROLE_CONTROLLED;
1099 }
1100 }
1101
1102 return ice_role;
1103}
1104
1105void JsepTransportController::OnTransportWritableState_n(
1106 rtc::PacketTransportInternal* transport) {
1107 RTC_DCHECK(network_thread_->IsCurrent());
1108 RTC_LOG(LS_INFO) << " Transport " << transport->transport_name()
1109 << " writability changed to " << transport->writable()
1110 << ".";
1111 UpdateAggregateStates_n();
1112}
1113
1114void JsepTransportController::OnTransportReceivingState_n(
1115 rtc::PacketTransportInternal* transport) {
1116 RTC_DCHECK(network_thread_->IsCurrent());
1117 UpdateAggregateStates_n();
1118}
1119
1120void JsepTransportController::OnTransportGatheringState_n(
1121 cricket::IceTransportInternal* transport) {
1122 RTC_DCHECK(network_thread_->IsCurrent());
1123 UpdateAggregateStates_n();
1124}
1125
1126void JsepTransportController::OnTransportCandidateGathered_n(
1127 cricket::IceTransportInternal* transport,
1128 const cricket::Candidate& candidate) {
1129 RTC_DCHECK(network_thread_->IsCurrent());
1130
1131 // We should never signal peer-reflexive candidates.
1132 if (candidate.type() == cricket::PRFLX_PORT_TYPE) {
1133 RTC_NOTREACHED();
1134 return;
1135 }
1136 std::vector<cricket::Candidate> candidates;
1137 candidates.push_back(candidate);
1138 CandidatesData* data =
1139 new CandidatesData(transport->transport_name(), candidates);
1140 signaling_thread_->Post(RTC_FROM_HERE, this, MSG_ICECANDIDATESGATHERED, data);
1141}
1142
1143void JsepTransportController::OnTransportCandidatesRemoved_n(
1144 cricket::IceTransportInternal* transport,
1145 const cricket::Candidates& candidates) {
1146 invoker_.AsyncInvoke<void>(
1147 RTC_FROM_HERE, signaling_thread_,
1148 rtc::Bind(&JsepTransportController::OnTransportCandidatesRemoved, this,
1149 candidates));
1150}
1151
1152void JsepTransportController::OnTransportCandidatesRemoved(
1153 const cricket::Candidates& candidates) {
1154 RTC_DCHECK(signaling_thread_->IsCurrent());
1155 SignalIceCandidatesRemoved(candidates);
1156}
1157
1158void JsepTransportController::OnTransportRoleConflict_n(
1159 cricket::IceTransportInternal* transport) {
1160 RTC_DCHECK(network_thread_->IsCurrent());
1161 // Note: since the role conflict is handled entirely on the network thread,
1162 // we don't need to worry about role conflicts occurring on two ports at
1163 // once. The first one encountered should immediately reverse the role.
1164 cricket::IceRole reversed_role = (ice_role_ == cricket::ICEROLE_CONTROLLING)
1165 ? cricket::ICEROLE_CONTROLLED
1166 : cricket::ICEROLE_CONTROLLING;
1167 RTC_LOG(LS_INFO) << "Got role conflict; switching to "
1168 << (reversed_role == cricket::ICEROLE_CONTROLLING
1169 ? "controlling"
1170 : "controlled")
1171 << " role.";
1172 SetIceRole_n(reversed_role);
1173}
1174
1175void JsepTransportController::OnTransportStateChanged_n(
1176 cricket::IceTransportInternal* transport) {
1177 RTC_DCHECK(network_thread_->IsCurrent());
1178 RTC_LOG(LS_INFO) << transport->transport_name() << " Transport "
1179 << transport->component()
1180 << " state changed. Check if state is complete.";
1181 UpdateAggregateStates_n();
1182}
1183
1184void JsepTransportController::UpdateAggregateStates_n() {
1185 RTC_DCHECK(network_thread_->IsCurrent());
1186
1187 auto dtls_transports = GetDtlsTransports();
1188 cricket::IceConnectionState new_connection_state =
1189 cricket::kIceConnectionConnecting;
1190 cricket::IceGatheringState new_gathering_state = cricket::kIceGatheringNew;
1191 bool any_failed = false;
1192 bool all_connected = !dtls_transports.empty();
1193 bool all_completed = !dtls_transports.empty();
1194 bool any_gathering = false;
1195 bool all_done_gathering = !dtls_transports.empty();
1196 for (const auto& dtls : dtls_transports) {
1197 any_failed = any_failed || dtls->ice_transport()->GetState() ==
1198 cricket::IceTransportState::STATE_FAILED;
1199 all_connected = all_connected && dtls->writable();
1200 all_completed =
1201 all_completed && dtls->writable() &&
1202 dtls->ice_transport()->GetState() ==
1203 cricket::IceTransportState::STATE_COMPLETED &&
1204 dtls->ice_transport()->GetIceRole() == cricket::ICEROLE_CONTROLLING &&
1205 dtls->ice_transport()->gathering_state() ==
1206 cricket::kIceGatheringComplete;
1207 any_gathering = any_gathering || dtls->ice_transport()->gathering_state() !=
1208 cricket::kIceGatheringNew;
1209 all_done_gathering =
1210 all_done_gathering && dtls->ice_transport()->gathering_state() ==
1211 cricket::kIceGatheringComplete;
1212 }
1213 if (any_failed) {
1214 new_connection_state = cricket::kIceConnectionFailed;
1215 } else if (all_completed) {
1216 new_connection_state = cricket::kIceConnectionCompleted;
1217 } else if (all_connected) {
1218 new_connection_state = cricket::kIceConnectionConnected;
1219 }
1220 if (ice_connection_state_ != new_connection_state) {
1221 ice_connection_state_ = new_connection_state;
1222 signaling_thread_->Post(
1223 RTC_FROM_HERE, this, MSG_ICECONNECTIONSTATE,
1224 new rtc::TypedMessageData<cricket::IceConnectionState>(
1225 new_connection_state));
1226 }
1227
1228 if (all_done_gathering) {
1229 new_gathering_state = cricket::kIceGatheringComplete;
1230 } else if (any_gathering) {
1231 new_gathering_state = cricket::kIceGatheringGathering;
1232 }
1233 if (ice_gathering_state_ != new_gathering_state) {
1234 ice_gathering_state_ = new_gathering_state;
1235 signaling_thread_->Post(
1236 RTC_FROM_HERE, this, MSG_ICEGATHERINGSTATE,
1237 new rtc::TypedMessageData<cricket::IceGatheringState>(
1238 new_gathering_state));
1239 }
1240}
1241
1242void JsepTransportController::OnDtlsHandshakeError(
1243 rtc::SSLHandshakeError error) {
1244 SignalDtlsHandshakeError(error);
1245}
1246
1247} // namespace webrtc