blob: 5235791792ef52e02282378c469b0798be2e53ed [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),
97 config_(config) {}
98
99JsepTransportController::~JsepTransportController() {
100 // Channel destructors may try to send packets, so this needs to happen on
101 // the network thread.
102 network_thread_->Invoke<void>(
103 RTC_FROM_HERE,
104 rtc::Bind(&JsepTransportController::DestroyAllJsepTransports_n, this));
105}
106
107RTCError JsepTransportController::SetLocalDescription(
108 SdpType type,
109 const cricket::SessionDescription* description) {
110 if (!network_thread_->IsCurrent()) {
111 return network_thread_->Invoke<RTCError>(
112 RTC_FROM_HERE, [=] { return SetLocalDescription(type, description); });
113 }
114
115 if (!initial_offerer_.has_value()) {
116 initial_offerer_.emplace(type == SdpType::kOffer);
117 if (*initial_offerer_) {
118 SetIceRole_n(cricket::ICEROLE_CONTROLLING);
119 } else {
120 SetIceRole_n(cricket::ICEROLE_CONTROLLED);
121 }
122 }
123 return ApplyDescription_n(/*local=*/true, type, description);
124}
125
126RTCError JsepTransportController::SetRemoteDescription(
127 SdpType type,
128 const cricket::SessionDescription* description) {
129 if (!network_thread_->IsCurrent()) {
130 return network_thread_->Invoke<RTCError>(
131 RTC_FROM_HERE, [=] { return SetRemoteDescription(type, description); });
132 }
133
134 return ApplyDescription_n(/*local=*/false, type, description);
135}
136
137RtpTransportInternal* JsepTransportController::GetRtpTransport(
138 const std::string& mid) const {
139 auto jsep_transport = GetJsepTransport(mid);
140 if (!jsep_transport) {
141 return nullptr;
142 }
143 return jsep_transport->rtp_transport();
144}
145
146cricket::DtlsTransportInternal* JsepTransportController::GetDtlsTransport(
147 const std::string& mid) const {
148 auto jsep_transport = GetJsepTransport(mid);
149 if (!jsep_transport) {
150 return nullptr;
151 }
152 return jsep_transport->rtp_dtls_transport();
153}
154
155cricket::DtlsTransportInternal* JsepTransportController::GetRtcpDtlsTransport(
156 const std::string& mid) const {
157 auto jsep_transport = GetJsepTransport(mid);
158 if (!jsep_transport) {
159 return nullptr;
160 }
161 return jsep_transport->rtcp_dtls_transport();
162}
163
164void JsepTransportController::SetIceConfig(const cricket::IceConfig& config) {
165 if (!network_thread_->IsCurrent()) {
166 network_thread_->Invoke<void>(RTC_FROM_HERE, [&] { SetIceConfig(config); });
167 return;
168 }
169
170 ice_config_ = config;
171 for (auto& dtls : GetDtlsTransports()) {
172 dtls->ice_transport()->SetIceConfig(ice_config_);
173 }
174}
175
176void JsepTransportController::SetNeedsIceRestartFlag() {
177 for (auto& kv : jsep_transports_by_mid_) {
178 kv.second->SetNeedsIceRestartFlag();
179 }
180}
181
182bool JsepTransportController::NeedsIceRestart(
183 const std::string& transport_name) const {
184 const cricket::JsepTransport2* transport = GetJsepTransport(transport_name);
185 if (!transport) {
186 return false;
187 }
188 return transport->needs_ice_restart();
189}
190
191rtc::Optional<rtc::SSLRole> JsepTransportController::GetDtlsRole(
192 const std::string& transport_name) const {
193 if (!network_thread_->IsCurrent()) {
194 return network_thread_->Invoke<rtc::Optional<rtc::SSLRole>>(
195 RTC_FROM_HERE, [&] { return GetDtlsRole(transport_name); });
196 }
197
198 const cricket::JsepTransport2* t = GetJsepTransport(transport_name);
199 if (!t) {
200 return rtc::Optional<rtc::SSLRole>();
201 }
202 return t->GetDtlsRole();
203}
204
205bool JsepTransportController::SetLocalCertificate(
206 const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) {
207 if (!network_thread_->IsCurrent()) {
208 return network_thread_->Invoke<bool>(
209 RTC_FROM_HERE, [&] { return SetLocalCertificate(certificate); });
210 }
211
212 // Can't change a certificate, or set a null certificate.
213 if (certificate_ || !certificate) {
214 return false;
215 }
216 certificate_ = certificate;
217
218 // Set certificate for JsepTransport, which verifies it matches the
219 // fingerprint in SDP, and DTLS transport.
220 // Fallback from DTLS to SDES is not supported.
221 for (auto& kv : jsep_transports_by_mid_) {
222 kv.second->SetLocalCertificate(certificate_);
223 }
224 for (auto& dtls : GetDtlsTransports()) {
225 bool set_cert_success = dtls->SetLocalCertificate(certificate_);
226 RTC_DCHECK(set_cert_success);
227 }
228 return true;
229}
230
231rtc::scoped_refptr<rtc::RTCCertificate>
232JsepTransportController::GetLocalCertificate(
233 const std::string& transport_name) const {
234 if (!network_thread_->IsCurrent()) {
235 return network_thread_->Invoke<rtc::scoped_refptr<rtc::RTCCertificate>>(
236 RTC_FROM_HERE, [&] { return GetLocalCertificate(transport_name); });
237 }
238
239 const cricket::JsepTransport2* t = GetJsepTransport(transport_name);
240 if (!t) {
241 return nullptr;
242 }
243 return t->GetLocalCertificate();
244}
245
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800246std::unique_ptr<rtc::SSLCertChain>
247JsepTransportController::GetRemoteSSLCertChain(
Zhi Huange818b6e2018-02-22 15:26:27 -0800248 const std::string& transport_name) const {
249 if (!network_thread_->IsCurrent()) {
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800250 return network_thread_->Invoke<std::unique_ptr<rtc::SSLCertChain>>(
251 RTC_FROM_HERE, [&] { return GetRemoteSSLCertChain(transport_name); });
Zhi Huange818b6e2018-02-22 15:26:27 -0800252 }
253
254 // Get the certificate from the RTP channel's DTLS handshake. Should be
255 // identical to the RTCP channel's, since they were given the same remote
256 // fingerprint.
257 auto dtls = GetDtlsTransport(transport_name);
258 if (!dtls) {
259 return nullptr;
260 }
261
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800262 return dtls->GetRemoteSSLCertChain();
Zhi Huange818b6e2018-02-22 15:26:27 -0800263}
264
265void JsepTransportController::MaybeStartGathering() {
266 if (!network_thread_->IsCurrent()) {
267 network_thread_->Invoke<void>(RTC_FROM_HERE,
268 [&] { MaybeStartGathering(); });
269 return;
270 }
271
272 for (auto& dtls : GetDtlsTransports()) {
273 dtls->ice_transport()->MaybeStartGathering();
274 }
275}
276
277RTCError JsepTransportController::AddRemoteCandidates(
278 const std::string& transport_name,
279 const cricket::Candidates& candidates) {
280 if (!network_thread_->IsCurrent()) {
281 return network_thread_->Invoke<RTCError>(RTC_FROM_HERE, [&] {
282 return AddRemoteCandidates(transport_name, candidates);
283 });
284 }
285
286 // Verify each candidate before passing down to the transport layer.
287 RTCError error = VerifyCandidates(candidates);
288 if (!error.ok()) {
289 return error;
290 }
291
292 cricket::JsepTransport2* jsep_transport = GetJsepTransport(transport_name);
293 if (!jsep_transport) {
294 return RTCError(RTCErrorType::INVALID_PARAMETER,
295 "The transport doesn't exist.");
296 }
297
298 return jsep_transport->AddRemoteCandidates(candidates);
299}
300
301RTCError JsepTransportController::RemoveRemoteCandidates(
302 const cricket::Candidates& candidates) {
303 if (!network_thread_->IsCurrent()) {
304 return network_thread_->Invoke<RTCError>(
305 RTC_FROM_HERE, [&] { return RemoveRemoteCandidates(candidates); });
306 }
307
308 // Verify each candidate before passing down to the transport layer.
309 RTCError error = VerifyCandidates(candidates);
310 if (!error.ok()) {
311 return error;
312 }
313
314 std::map<std::string, cricket::Candidates> candidates_by_transport_name;
315 for (const cricket::Candidate& cand : candidates) {
316 if (!cand.transport_name().empty()) {
317 candidates_by_transport_name[cand.transport_name()].push_back(cand);
318 } else {
319 RTC_LOG(LS_ERROR) << "Not removing candidate because it does not have a "
320 "transport name set: "
321 << cand.ToString();
322 }
323 }
324
325 for (const auto& kv : candidates_by_transport_name) {
326 const std::string& transport_name = kv.first;
327 const cricket::Candidates& candidates = kv.second;
328 cricket::JsepTransport2* jsep_transport = GetJsepTransport(transport_name);
329 if (!jsep_transport) {
330 return RTCError(RTCErrorType::INVALID_PARAMETER,
331 "The transport doesn't exist.");
332 }
333 for (const cricket::Candidate& candidate : candidates) {
334 auto dtls = candidate.component() == cricket::ICE_CANDIDATE_COMPONENT_RTP
335 ? jsep_transport->rtp_dtls_transport()
336 : jsep_transport->rtcp_dtls_transport();
337 if (dtls) {
338 dtls->ice_transport()->RemoveRemoteCandidate(candidate);
339 }
340 }
341 }
342 return RTCError::OK();
343}
344
345bool JsepTransportController::GetStats(const std::string& transport_name,
346 cricket::TransportStats* stats) {
347 if (!network_thread_->IsCurrent()) {
348 return network_thread_->Invoke<bool>(
349 RTC_FROM_HERE, [=] { return GetStats(transport_name, stats); });
350 }
351
352 cricket::JsepTransport2* transport = GetJsepTransport(transport_name);
353 if (!transport) {
354 return false;
355 }
356 return transport->GetStats(stats);
357}
358
359void JsepTransportController::SetMetricsObserver(
360 webrtc::MetricsObserverInterface* metrics_observer) {
361 if (!network_thread_->IsCurrent()) {
362 network_thread_->Invoke<void>(
363 RTC_FROM_HERE, [=] { SetMetricsObserver(metrics_observer); });
364 return;
365 }
366
367 metrics_observer_ = metrics_observer;
368 for (auto& dtls : GetDtlsTransports()) {
369 dtls->ice_transport()->SetMetricsObserver(metrics_observer);
370 }
371}
372
373std::unique_ptr<cricket::DtlsTransportInternal>
374JsepTransportController::CreateDtlsTransport(const std::string& transport_name,
375 bool rtcp) {
376 RTC_DCHECK(network_thread_->IsCurrent());
377 int component = rtcp ? cricket::ICE_CANDIDATE_COMPONENT_RTCP
378 : cricket::ICE_CANDIDATE_COMPONENT_RTP;
379
380 std::unique_ptr<cricket::DtlsTransportInternal> dtls;
381 if (config_.external_transport_factory) {
382 auto ice = config_.external_transport_factory->CreateIceTransport(
383 transport_name, component);
384 dtls = config_.external_transport_factory->CreateDtlsTransport(
385 std::move(ice), config_.crypto_options);
386 } else {
387 auto ice = rtc::MakeUnique<cricket::P2PTransportChannel>(
388 transport_name, component, port_allocator_);
389 dtls = rtc::MakeUnique<cricket::DtlsTransport>(std::move(ice),
390 config_.crypto_options);
391 }
392
393 RTC_DCHECK(dtls);
394 dtls->SetSslMaxProtocolVersion(config_.ssl_max_version);
395 dtls->ice_transport()->SetMetricsObserver(metrics_observer_);
396 dtls->ice_transport()->SetIceRole(ice_role_);
397 dtls->ice_transport()->SetIceTiebreaker(ice_tiebreaker_);
398 dtls->ice_transport()->SetIceConfig(ice_config_);
399 if (certificate_) {
400 bool set_cert_success = dtls->SetLocalCertificate(certificate_);
401 RTC_DCHECK(set_cert_success);
402 }
403
404 // Connect to signals offered by the DTLS and ICE transport.
405 dtls->SignalWritableState.connect(
406 this, &JsepTransportController::OnTransportWritableState_n);
407 dtls->SignalReceivingState.connect(
408 this, &JsepTransportController::OnTransportReceivingState_n);
409 dtls->SignalDtlsHandshakeError.connect(
410 this, &JsepTransportController::OnDtlsHandshakeError);
411 dtls->ice_transport()->SignalGatheringState.connect(
412 this, &JsepTransportController::OnTransportGatheringState_n);
413 dtls->ice_transport()->SignalCandidateGathered.connect(
414 this, &JsepTransportController::OnTransportCandidateGathered_n);
415 dtls->ice_transport()->SignalCandidatesRemoved.connect(
416 this, &JsepTransportController::OnTransportCandidatesRemoved_n);
417 dtls->ice_transport()->SignalRoleConflict.connect(
418 this, &JsepTransportController::OnTransportRoleConflict_n);
419 dtls->ice_transport()->SignalStateChanged.connect(
420 this, &JsepTransportController::OnTransportStateChanged_n);
421 return dtls;
422}
423
424std::unique_ptr<webrtc::RtpTransport>
425JsepTransportController::CreateUnencryptedRtpTransport(
426 const std::string& transport_name,
427 rtc::PacketTransportInternal* rtp_packet_transport,
428 rtc::PacketTransportInternal* rtcp_packet_transport) {
429 RTC_DCHECK(network_thread_->IsCurrent());
430 // TODO(zhihuang): Add support of unencrypted RTP for testing.
431 return nullptr;
432}
433
434std::unique_ptr<webrtc::SrtpTransport>
435JsepTransportController::CreateSdesTransport(
436 const std::string& transport_name,
437 rtc::PacketTransportInternal* rtp_packet_transport,
438 rtc::PacketTransportInternal* rtcp_packet_transport) {
439 RTC_DCHECK(network_thread_->IsCurrent());
440 bool rtcp_mux_enabled = rtcp_packet_transport == nullptr;
441 auto srtp_transport =
442 rtc::MakeUnique<webrtc::SrtpTransport>(rtcp_mux_enabled);
443 RTC_DCHECK(rtp_packet_transport);
444 srtp_transport->SetRtpPacketTransport(rtp_packet_transport);
445 if (rtcp_packet_transport) {
446 srtp_transport->SetRtcpPacketTransport(rtp_packet_transport);
447 }
448 if (config_.enable_external_auth) {
449 srtp_transport->EnableExternalAuth();
450 }
451 return srtp_transport;
452}
453
454std::unique_ptr<webrtc::DtlsSrtpTransport>
455JsepTransportController::CreateDtlsSrtpTransport(
456 const std::string& transport_name,
457 cricket::DtlsTransportInternal* rtp_dtls_transport,
458 cricket::DtlsTransportInternal* rtcp_dtls_transport) {
459 RTC_DCHECK(network_thread_->IsCurrent());
460 bool rtcp_mux_enabled = rtcp_dtls_transport == nullptr;
461 auto srtp_transport =
462 rtc::MakeUnique<webrtc::SrtpTransport>(rtcp_mux_enabled);
463 if (config_.enable_external_auth) {
464 srtp_transport->EnableExternalAuth();
465 }
466
467 auto dtls_srtp_transport =
468 rtc::MakeUnique<webrtc::DtlsSrtpTransport>(std::move(srtp_transport));
469
470 dtls_srtp_transport->SetDtlsTransports(rtp_dtls_transport,
471 rtcp_dtls_transport);
472 return dtls_srtp_transport;
473}
474
475std::vector<cricket::DtlsTransportInternal*>
476JsepTransportController::GetDtlsTransports() {
477 std::vector<cricket::DtlsTransportInternal*> dtls_transports;
478 for (auto it = jsep_transports_by_mid_.begin();
479 it != jsep_transports_by_mid_.end(); ++it) {
480 auto jsep_transport = it->second.get();
481 RTC_DCHECK(jsep_transport);
482 if (jsep_transport->rtp_dtls_transport()) {
483 dtls_transports.push_back(jsep_transport->rtp_dtls_transport());
484 }
485
486 if (jsep_transport->rtcp_dtls_transport()) {
487 dtls_transports.push_back(jsep_transport->rtcp_dtls_transport());
488 }
489 }
490 return dtls_transports;
491}
492
493void JsepTransportController::OnMessage(rtc::Message* pmsg) {
494 RTC_DCHECK(signaling_thread_->IsCurrent());
495
496 switch (pmsg->message_id) {
497 case MSG_ICECONNECTIONSTATE: {
498 rtc::TypedMessageData<cricket::IceConnectionState>* data =
499 static_cast<rtc::TypedMessageData<cricket::IceConnectionState>*>(
500 pmsg->pdata);
501 SignalIceConnectionState(data->data());
502 delete data;
503 break;
504 }
505 case MSG_ICEGATHERINGSTATE: {
506 rtc::TypedMessageData<cricket::IceGatheringState>* data =
507 static_cast<rtc::TypedMessageData<cricket::IceGatheringState>*>(
508 pmsg->pdata);
509 SignalIceGatheringState(data->data());
510 delete data;
511 break;
512 }
513 case MSG_ICECANDIDATESGATHERED: {
514 CandidatesData* data = static_cast<CandidatesData*>(pmsg->pdata);
515 SignalIceCandidatesGathered(data->transport_name, data->candidates);
516 delete data;
517 break;
518 }
519 default:
520 RTC_NOTREACHED();
521 }
522}
523
524RTCError JsepTransportController::ApplyDescription_n(
525 bool local,
526 SdpType type,
527 const cricket::SessionDescription* description) {
528 RTC_DCHECK(network_thread_->IsCurrent());
529 RTC_DCHECK(description);
530
531 if (local) {
532 local_desc_ = description;
533 } else {
534 remote_desc_ = description;
535 }
536
537 if (ShouldUpdateBundleGroup(type, description)) {
538 bundle_group_ = *description->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
539 }
540
541 std::vector<int> merged_encrypted_extension_ids;
542 if (bundle_group_) {
543 merged_encrypted_extension_ids =
544 MergeEncryptedHeaderExtensionIdsForBundle(description);
545 }
546
547 for (const cricket::ContentInfo& content_info : description->contents()) {
548 // Don't create transports for rejected m-lines and bundled m-lines."
549 if (content_info.rejected ||
550 (IsBundled(content_info.name) && content_info.name != *bundled_mid())) {
551 continue;
552 }
553 MaybeCreateJsepTransport(content_info.name, content_info);
554 }
555
556 RTC_DCHECK(description->contents().size() ==
557 description->transport_infos().size());
558 for (size_t i = 0; i < description->contents().size(); ++i) {
559 const cricket::ContentInfo& content_info = description->contents()[i];
560 const cricket::TransportInfo& transport_info =
561 description->transport_infos()[i];
562 if (content_info.rejected) {
563 HandleRejectedContent(content_info);
564 continue;
565 }
566
567 if (IsBundled(content_info.name) && content_info.name != *bundled_mid()) {
568 HandleBundledContent(content_info);
569 continue;
570 }
571
572 std::vector<int> extension_ids;
573 if (bundle_group_ && content_info.name == *bundled_mid()) {
574 extension_ids = merged_encrypted_extension_ids;
575 } else {
576 extension_ids = GetEncryptedHeaderExtensionIds(content_info);
577 }
578
579 cricket::JsepTransport2* transport = GetJsepTransport(content_info.name);
580 RTC_DCHECK(transport);
581
582 SetIceRole_n(DetermineIceRole(transport, transport_info, type, local));
583
584 RTCError error;
585 cricket::JsepTransportDescription jsep_description =
586 CreateJsepTransportDescription(content_info, transport_info,
587 extension_ids);
588 if (local) {
589 error =
590 transport->SetLocalJsepTransportDescription(jsep_description, type);
591 } else {
592 error =
593 transport->SetRemoteJsepTransportDescription(jsep_description, type);
594 }
595
596 if (!error.ok()) {
597 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
598 "Failed to apply the description for " +
599 content_info.name + ": " + error.message());
600 }
601 }
602 return RTCError::OK();
603}
604
605void JsepTransportController::HandleRejectedContent(
606 const cricket::ContentInfo& content_info) {
607 // If the content is rejected, let the
608 // BaseChannel/SctpTransport change the RtpTransport/DtlsTransport first,
609 // then destroy the cricket::JsepTransport2.
610 if (content_info.type == cricket::MediaProtocolType::kRtp) {
611 SignalRtpTransportChanged(content_info.name, nullptr);
612 } else {
613 SignalDtlsTransportChanged(content_info.name, nullptr);
614 }
615 // Remove the rejected content from the |bundle_group_|.
616 if (IsBundled(content_info.name)) {
617 bundle_group_->RemoveContentName(content_info.name);
618 }
619 MaybeDestroyJsepTransport(content_info.name);
620}
621
622void JsepTransportController::HandleBundledContent(
623 const cricket::ContentInfo& content_info) {
624 // If the content is bundled, let the
625 // BaseChannel/SctpTransport change the RtpTransport/DtlsTransport first,
626 // then destroy the cricket::JsepTransport2.
627 if (content_info.type == cricket::MediaProtocolType::kRtp) {
628 auto rtp_transport =
629 jsep_transports_by_mid_[*bundled_mid()]->rtp_transport();
630 SignalRtpTransportChanged(content_info.name, rtp_transport);
631 } else {
632 auto dtls_transport =
633 jsep_transports_by_mid_[*bundled_mid()]->rtp_dtls_transport();
634 SignalDtlsTransportChanged(content_info.name, dtls_transport);
635 }
636 MaybeDestroyJsepTransport(content_info.name);
637}
638
639cricket::JsepTransportDescription
640JsepTransportController::CreateJsepTransportDescription(
641 cricket::ContentInfo content_info,
642 cricket::TransportInfo transport_info,
643 const std::vector<int>& encrypted_extension_ids) {
644 const cricket::MediaContentDescription* content_desc =
645 static_cast<const cricket::MediaContentDescription*>(
646 content_info.description);
647 RTC_DCHECK(content_desc);
648 bool rtcp_mux_enabled = content_info.type == cricket::MediaProtocolType::kSctp
649 ? true
650 : content_desc->rtcp_mux();
651
652 return cricket::JsepTransportDescription(
653 rtcp_mux_enabled, content_desc->cryptos(), encrypted_extension_ids,
654 transport_info.description);
655}
656
657bool JsepTransportController::ShouldUpdateBundleGroup(
658 SdpType type,
659 const cricket::SessionDescription* description) {
660 if (config_.bundle_policy ==
661 PeerConnectionInterface::kBundlePolicyMaxBundle) {
662 return true;
663 }
664
665 if (type != SdpType::kAnswer) {
666 return false;
667 }
668
669 RTC_DCHECK(local_desc_ && remote_desc_);
670 const cricket::ContentGroup* local_bundle =
671 local_desc_->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
672 const cricket::ContentGroup* remote_bundle =
673 remote_desc_->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
674 return local_bundle && remote_bundle;
675}
676
677std::vector<int> JsepTransportController::GetEncryptedHeaderExtensionIds(
678 const cricket::ContentInfo& content_info) {
679 const cricket::MediaContentDescription* content_desc =
680 static_cast<const cricket::MediaContentDescription*>(
681 content_info.description);
682
683 if (!config_.crypto_options.enable_encrypted_rtp_header_extensions) {
684 return std::vector<int>();
685 }
686
687 std::vector<int> encrypted_header_extension_ids;
688 for (auto extension : content_desc->rtp_header_extensions()) {
689 if (!extension.encrypt) {
690 continue;
691 }
692 auto it = std::find(encrypted_header_extension_ids.begin(),
693 encrypted_header_extension_ids.end(), extension.id);
694 if (it == encrypted_header_extension_ids.end()) {
695 encrypted_header_extension_ids.push_back(extension.id);
696 }
697 }
698 return encrypted_header_extension_ids;
699}
700
701std::vector<int>
702JsepTransportController::MergeEncryptedHeaderExtensionIdsForBundle(
703 const cricket::SessionDescription* description) {
704 RTC_DCHECK(description);
705 RTC_DCHECK(bundle_group_);
706
707 std::vector<int> merged_ids;
708 // Union the encrypted header IDs in the group when bundle is enabled.
709 for (const cricket::ContentInfo& content_info : description->contents()) {
710 if (bundle_group_->HasContentName(content_info.name)) {
711 std::vector<int> extension_ids =
712 GetEncryptedHeaderExtensionIds(content_info);
713 for (int id : extension_ids) {
714 auto it = std::find(merged_ids.begin(), merged_ids.end(), id);
715 if (it == merged_ids.end()) {
716 merged_ids.push_back(id);
717 }
718 }
719 }
720 }
721 return merged_ids;
722}
723
724const cricket::JsepTransport2* JsepTransportController::GetJsepTransport(
725 const std::string& mid) const {
726 auto target_mid = mid;
727 if (IsBundled(mid)) {
728 target_mid = *bundled_mid();
729 }
730 auto it = jsep_transports_by_mid_.find(target_mid);
731 return (it == jsep_transports_by_mid_.end()) ? nullptr : it->second.get();
732}
733
734cricket::JsepTransport2* JsepTransportController::GetJsepTransport(
735 const std::string& mid) {
736 auto target_mid = mid;
737 if (IsBundled(mid)) {
738 target_mid = *bundled_mid();
739 }
740 auto it = jsep_transports_by_mid_.find(target_mid);
741 return (it == jsep_transports_by_mid_.end()) ? nullptr : it->second.get();
742}
743
744void JsepTransportController::MaybeCreateJsepTransport(
745 const std::string& mid,
746 const cricket::ContentInfo& content_info) {
747 RTC_DCHECK(network_thread_->IsCurrent());
748
749 cricket::JsepTransport2* transport = GetJsepTransport(mid);
750 if (transport) {
751 return;
752 }
753
754 const cricket::MediaContentDescription* content_desc =
755 static_cast<const cricket::MediaContentDescription*>(
756 content_info.description);
757 bool rtcp_mux_enabled =
758 content_desc->rtcp_mux() ||
759 config_.rtcp_mux_policy == PeerConnectionInterface::kRtcpMuxPolicyRequire;
760 std::unique_ptr<cricket::DtlsTransportInternal> rtp_dtls_transport =
761 CreateDtlsTransport(mid, /*rtcp = */ false);
762 std::unique_ptr<cricket::DtlsTransportInternal> rtcp_dtls_transport;
763 if (!rtcp_mux_enabled) {
764 rtcp_dtls_transport = CreateDtlsTransport(mid, /*rtcp = */ true);
765 }
766
767 std::unique_ptr<RtpTransport> unencrypted_rtp_transport;
768 std::unique_ptr<SrtpTransport> sdes_transport;
769 std::unique_ptr<DtlsSrtpTransport> dtls_srtp_transport;
770 if (config_.disable_encryption) {
771 unencrypted_rtp_transport = CreateUnencryptedRtpTransport(
772 mid, rtp_dtls_transport.get(), rtcp_dtls_transport.get());
773 } else if (!content_desc->cryptos().empty()) {
774 sdes_transport = CreateSdesTransport(mid, rtp_dtls_transport.get(),
775 rtcp_dtls_transport.get());
776 } else {
777 dtls_srtp_transport = CreateDtlsSrtpTransport(mid, rtp_dtls_transport.get(),
778 rtcp_dtls_transport.get());
779 }
780
781 std::unique_ptr<cricket::JsepTransport2> jsep_transport =
782 rtc::MakeUnique<cricket::JsepTransport2>(
783 mid, certificate_, std::move(unencrypted_rtp_transport),
784 std::move(sdes_transport), std::move(dtls_srtp_transport),
785 std::move(rtp_dtls_transport), std::move(rtcp_dtls_transport));
786 jsep_transport->SignalRtcpMuxActive.connect(
787 this, &JsepTransportController::UpdateAggregateStates_n);
788 jsep_transports_by_mid_[mid] = std::move(jsep_transport);
789 UpdateAggregateStates_n();
790}
791
792void JsepTransportController::MaybeDestroyJsepTransport(
793 const std::string& mid) {
794 jsep_transports_by_mid_.erase(mid);
795 UpdateAggregateStates_n();
796}
797
798void JsepTransportController::DestroyAllJsepTransports_n() {
799 RTC_DCHECK(network_thread_->IsCurrent());
800 jsep_transports_by_mid_.clear();
801}
802
803void JsepTransportController::SetIceRole_n(cricket::IceRole ice_role) {
804 RTC_DCHECK(network_thread_->IsCurrent());
805
806 ice_role_ = ice_role;
807 for (auto& dtls : GetDtlsTransports()) {
808 dtls->ice_transport()->SetIceRole(ice_role_);
809 }
810}
811
812cricket::IceRole JsepTransportController::DetermineIceRole(
813 cricket::JsepTransport2* jsep_transport,
814 const cricket::TransportInfo& transport_info,
815 SdpType type,
816 bool local) {
817 cricket::IceRole ice_role = ice_role_;
818 auto tdesc = transport_info.description;
819 if (local) {
820 // The initial offer side may use ICE Lite, in which case, per RFC5245
821 // Section 5.1.1, the answer side should take the controlling role if it is
822 // in the full ICE mode.
823 //
824 // When both sides use ICE Lite, the initial offer side must take the
825 // controlling role, and this is the default logic implemented in
826 // SetLocalDescription in JsepTransportController.
827 if (jsep_transport->remote_description() &&
828 jsep_transport->remote_description()->transport_desc.ice_mode ==
829 cricket::ICEMODE_LITE &&
830 ice_role_ == cricket::ICEROLE_CONTROLLED &&
831 tdesc.ice_mode == cricket::ICEMODE_FULL) {
832 ice_role = cricket::ICEROLE_CONTROLLING;
833 }
834
835 // Older versions of Chrome expect the ICE role to be re-determined when an
836 // ICE restart occurs, and also don't perform conflict resolution correctly,
837 // so for now we can't safely stop doing this, unless the application opts
838 // in by setting |config_.redetermine_role_on_ice_restart_| to false. See:
839 // https://bugs.chromium.org/p/chromium/issues/detail?id=628676
840 // TODO(deadbeef): Remove this when these old versions of Chrome reach a low
841 // enough population.
842 if (config_.redetermine_role_on_ice_restart &&
843 jsep_transport->local_description() &&
844 cricket::IceCredentialsChanged(
845 jsep_transport->local_description()->transport_desc.ice_ufrag,
846 jsep_transport->local_description()->transport_desc.ice_pwd,
847 tdesc.ice_ufrag, tdesc.ice_pwd) &&
848 // Don't change the ICE role if the remote endpoint is ICE lite; we
849 // should always be controlling in that case.
850 (!jsep_transport->remote_description() ||
851 jsep_transport->remote_description()->transport_desc.ice_mode !=
852 cricket::ICEMODE_LITE)) {
853 ice_role = (type == SdpType::kOffer) ? cricket::ICEROLE_CONTROLLING
854 : cricket::ICEROLE_CONTROLLED;
855 }
856 } else {
857 // If our role is cricket::ICEROLE_CONTROLLED and the remote endpoint
858 // supports only ice_lite, this local endpoint should take the CONTROLLING
859 // role.
860 // TODO(deadbeef): This is a session-level attribute, so it really shouldn't
861 // be in a TransportDescription in the first place...
862 if (ice_role_ == cricket::ICEROLE_CONTROLLED &&
863 tdesc.ice_mode == cricket::ICEMODE_LITE) {
864 ice_role = cricket::ICEROLE_CONTROLLING;
865 }
866
867 // If we use ICE Lite and the remote endpoint uses the full implementation
868 // of ICE, the local endpoint must take the controlled role, and the other
869 // side must be the controlling role.
870 if (jsep_transport->local_description() &&
871 jsep_transport->local_description()->transport_desc.ice_mode ==
872 cricket::ICEMODE_LITE &&
873 ice_role_ == cricket::ICEROLE_CONTROLLING &&
874 tdesc.ice_mode == cricket::ICEMODE_LITE) {
875 ice_role = cricket::ICEROLE_CONTROLLED;
876 }
877 }
878
879 return ice_role;
880}
881
882void JsepTransportController::OnTransportWritableState_n(
883 rtc::PacketTransportInternal* transport) {
884 RTC_DCHECK(network_thread_->IsCurrent());
885 RTC_LOG(LS_INFO) << " Transport " << transport->transport_name()
886 << " writability changed to " << transport->writable()
887 << ".";
888 UpdateAggregateStates_n();
889}
890
891void JsepTransportController::OnTransportReceivingState_n(
892 rtc::PacketTransportInternal* transport) {
893 RTC_DCHECK(network_thread_->IsCurrent());
894 UpdateAggregateStates_n();
895}
896
897void JsepTransportController::OnTransportGatheringState_n(
898 cricket::IceTransportInternal* transport) {
899 RTC_DCHECK(network_thread_->IsCurrent());
900 UpdateAggregateStates_n();
901}
902
903void JsepTransportController::OnTransportCandidateGathered_n(
904 cricket::IceTransportInternal* transport,
905 const cricket::Candidate& candidate) {
906 RTC_DCHECK(network_thread_->IsCurrent());
907
908 // We should never signal peer-reflexive candidates.
909 if (candidate.type() == cricket::PRFLX_PORT_TYPE) {
910 RTC_NOTREACHED();
911 return;
912 }
913 std::vector<cricket::Candidate> candidates;
914 candidates.push_back(candidate);
915 CandidatesData* data =
916 new CandidatesData(transport->transport_name(), candidates);
917 signaling_thread_->Post(RTC_FROM_HERE, this, MSG_ICECANDIDATESGATHERED, data);
918}
919
920void JsepTransportController::OnTransportCandidatesRemoved_n(
921 cricket::IceTransportInternal* transport,
922 const cricket::Candidates& candidates) {
923 invoker_.AsyncInvoke<void>(
924 RTC_FROM_HERE, signaling_thread_,
925 rtc::Bind(&JsepTransportController::OnTransportCandidatesRemoved, this,
926 candidates));
927}
928
929void JsepTransportController::OnTransportCandidatesRemoved(
930 const cricket::Candidates& candidates) {
931 RTC_DCHECK(signaling_thread_->IsCurrent());
932 SignalIceCandidatesRemoved(candidates);
933}
934
935void JsepTransportController::OnTransportRoleConflict_n(
936 cricket::IceTransportInternal* transport) {
937 RTC_DCHECK(network_thread_->IsCurrent());
938 // Note: since the role conflict is handled entirely on the network thread,
939 // we don't need to worry about role conflicts occurring on two ports at
940 // once. The first one encountered should immediately reverse the role.
941 cricket::IceRole reversed_role = (ice_role_ == cricket::ICEROLE_CONTROLLING)
942 ? cricket::ICEROLE_CONTROLLED
943 : cricket::ICEROLE_CONTROLLING;
944 RTC_LOG(LS_INFO) << "Got role conflict; switching to "
945 << (reversed_role == cricket::ICEROLE_CONTROLLING
946 ? "controlling"
947 : "controlled")
948 << " role.";
949 SetIceRole_n(reversed_role);
950}
951
952void JsepTransportController::OnTransportStateChanged_n(
953 cricket::IceTransportInternal* transport) {
954 RTC_DCHECK(network_thread_->IsCurrent());
955 RTC_LOG(LS_INFO) << transport->transport_name() << " Transport "
956 << transport->component()
957 << " state changed. Check if state is complete.";
958 UpdateAggregateStates_n();
959}
960
961void JsepTransportController::UpdateAggregateStates_n() {
962 RTC_DCHECK(network_thread_->IsCurrent());
963
964 auto dtls_transports = GetDtlsTransports();
965 cricket::IceConnectionState new_connection_state =
966 cricket::kIceConnectionConnecting;
967 cricket::IceGatheringState new_gathering_state = cricket::kIceGatheringNew;
968 bool any_failed = false;
969 bool all_connected = !dtls_transports.empty();
970 bool all_completed = !dtls_transports.empty();
971 bool any_gathering = false;
972 bool all_done_gathering = !dtls_transports.empty();
973 for (const auto& dtls : dtls_transports) {
974 any_failed = any_failed || dtls->ice_transport()->GetState() ==
975 cricket::IceTransportState::STATE_FAILED;
976 all_connected = all_connected && dtls->writable();
977 all_completed =
978 all_completed && dtls->writable() &&
979 dtls->ice_transport()->GetState() ==
980 cricket::IceTransportState::STATE_COMPLETED &&
981 dtls->ice_transport()->GetIceRole() == cricket::ICEROLE_CONTROLLING &&
982 dtls->ice_transport()->gathering_state() ==
983 cricket::kIceGatheringComplete;
984 any_gathering = any_gathering || dtls->ice_transport()->gathering_state() !=
985 cricket::kIceGatheringNew;
986 all_done_gathering =
987 all_done_gathering && dtls->ice_transport()->gathering_state() ==
988 cricket::kIceGatheringComplete;
989 }
990 if (any_failed) {
991 new_connection_state = cricket::kIceConnectionFailed;
992 } else if (all_completed) {
993 new_connection_state = cricket::kIceConnectionCompleted;
994 } else if (all_connected) {
995 new_connection_state = cricket::kIceConnectionConnected;
996 }
997 if (ice_connection_state_ != new_connection_state) {
998 ice_connection_state_ = new_connection_state;
999 signaling_thread_->Post(
1000 RTC_FROM_HERE, this, MSG_ICECONNECTIONSTATE,
1001 new rtc::TypedMessageData<cricket::IceConnectionState>(
1002 new_connection_state));
1003 }
1004
1005 if (all_done_gathering) {
1006 new_gathering_state = cricket::kIceGatheringComplete;
1007 } else if (any_gathering) {
1008 new_gathering_state = cricket::kIceGatheringGathering;
1009 }
1010 if (ice_gathering_state_ != new_gathering_state) {
1011 ice_gathering_state_ = new_gathering_state;
1012 signaling_thread_->Post(
1013 RTC_FROM_HERE, this, MSG_ICEGATHERINGSTATE,
1014 new rtc::TypedMessageData<cricket::IceGatheringState>(
1015 new_gathering_state));
1016 }
1017}
1018
1019void JsepTransportController::OnDtlsHandshakeError(
1020 rtc::SSLHandshakeError error) {
1021 SignalDtlsHandshakeError(error);
1022}
1023
1024} // namespace webrtc