1 /*
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/jsep_transport_controller.h"
12
13 #include <stddef.h>
14
15 #include <algorithm>
16 #include <memory>
17 #include <utility>
18
19 #include "absl/algorithm/container.h"
20 #include "api/rtp_parameters.h"
21 #include "api/sequence_checker.h"
22 #include "api/transport/enums.h"
23 #include "media/sctp/sctp_transport_internal.h"
24 #include "p2p/base/dtls_transport.h"
25 #include "p2p/base/ice_transport_internal.h"
26 #include "p2p/base/p2p_constants.h"
27 #include "p2p/base/port.h"
28 #include "rtc_base/checks.h"
29 #include "rtc_base/location.h"
30 #include "rtc_base/logging.h"
31 #include "rtc_base/net_helper.h"
32 #include "rtc_base/socket_address.h"
33 #include "rtc_base/thread.h"
34
35 using webrtc::SdpType;
36
37 namespace webrtc {
38
JsepTransportController(rtc::Thread * network_thread,cricket::PortAllocator * port_allocator,AsyncResolverFactory * async_resolver_factory,Config config)39 JsepTransportController::JsepTransportController(
40 rtc::Thread* network_thread,
41 cricket::PortAllocator* port_allocator,
42 AsyncResolverFactory* async_resolver_factory,
43 Config config)
44 : network_thread_(network_thread),
45 port_allocator_(port_allocator),
46 async_resolver_factory_(async_resolver_factory),
47 config_(config),
48 active_reset_srtp_params_(config.active_reset_srtp_params) {
49 // The |transport_observer| is assumed to be non-null.
50 RTC_DCHECK(config_.transport_observer);
51 RTC_DCHECK(config_.rtcp_handler);
52 RTC_DCHECK(config_.ice_transport_factory);
53 RTC_DCHECK(config_.on_dtls_handshake_error_);
54 }
55
~JsepTransportController()56 JsepTransportController::~JsepTransportController() {
57 // Channel destructors may try to send packets, so this needs to happen on
58 // the network thread.
59 RTC_DCHECK_RUN_ON(network_thread_);
60 DestroyAllJsepTransports_n();
61 }
62
SetLocalDescription(SdpType type,const cricket::SessionDescription * description)63 RTCError JsepTransportController::SetLocalDescription(
64 SdpType type,
65 const cricket::SessionDescription* description) {
66 if (!network_thread_->IsCurrent()) {
67 return network_thread_->Invoke<RTCError>(
68 RTC_FROM_HERE, [=] { return SetLocalDescription(type, description); });
69 }
70
71 RTC_DCHECK_RUN_ON(network_thread_);
72 if (!initial_offerer_.has_value()) {
73 initial_offerer_.emplace(type == SdpType::kOffer);
74 if (*initial_offerer_) {
75 SetIceRole_n(cricket::ICEROLE_CONTROLLING);
76 } else {
77 SetIceRole_n(cricket::ICEROLE_CONTROLLED);
78 }
79 }
80 return ApplyDescription_n(/*local=*/true, type, description);
81 }
82
SetRemoteDescription(SdpType type,const cricket::SessionDescription * description)83 RTCError JsepTransportController::SetRemoteDescription(
84 SdpType type,
85 const cricket::SessionDescription* description) {
86 if (!network_thread_->IsCurrent()) {
87 return network_thread_->Invoke<RTCError>(
88 RTC_FROM_HERE, [=] { return SetRemoteDescription(type, description); });
89 }
90
91 RTC_DCHECK_RUN_ON(network_thread_);
92 return ApplyDescription_n(/*local=*/false, type, description);
93 }
94
GetRtpTransport(const std::string & mid) const95 RtpTransportInternal* JsepTransportController::GetRtpTransport(
96 const std::string& mid) const {
97 RTC_DCHECK_RUN_ON(network_thread_);
98 auto jsep_transport = GetJsepTransportForMid(mid);
99 if (!jsep_transport) {
100 return nullptr;
101 }
102 return jsep_transport->rtp_transport();
103 }
104
GetDataChannelTransport(const std::string & mid) const105 DataChannelTransportInterface* JsepTransportController::GetDataChannelTransport(
106 const std::string& mid) const {
107 RTC_DCHECK_RUN_ON(network_thread_);
108 auto jsep_transport = GetJsepTransportForMid(mid);
109 if (!jsep_transport) {
110 return nullptr;
111 }
112 return jsep_transport->data_channel_transport();
113 }
114
GetDtlsTransport(const std::string & mid)115 cricket::DtlsTransportInternal* JsepTransportController::GetDtlsTransport(
116 const std::string& mid) {
117 RTC_DCHECK_RUN_ON(network_thread_);
118 auto jsep_transport = GetJsepTransportForMid(mid);
119 if (!jsep_transport) {
120 return nullptr;
121 }
122 return jsep_transport->rtp_dtls_transport();
123 }
124
125 const cricket::DtlsTransportInternal*
GetRtcpDtlsTransport(const std::string & mid) const126 JsepTransportController::GetRtcpDtlsTransport(const std::string& mid) const {
127 RTC_DCHECK_RUN_ON(network_thread_);
128 auto jsep_transport = GetJsepTransportForMid(mid);
129 if (!jsep_transport) {
130 return nullptr;
131 }
132 return jsep_transport->rtcp_dtls_transport();
133 }
134
135 rtc::scoped_refptr<webrtc::DtlsTransport>
LookupDtlsTransportByMid(const std::string & mid)136 JsepTransportController::LookupDtlsTransportByMid(const std::string& mid) {
137 RTC_DCHECK_RUN_ON(network_thread_);
138 auto jsep_transport = GetJsepTransportForMid(mid);
139 if (!jsep_transport) {
140 return nullptr;
141 }
142 return jsep_transport->RtpDtlsTransport();
143 }
144
GetSctpTransport(const std::string & mid) const145 rtc::scoped_refptr<SctpTransport> JsepTransportController::GetSctpTransport(
146 const std::string& mid) const {
147 RTC_DCHECK_RUN_ON(network_thread_);
148 auto jsep_transport = GetJsepTransportForMid(mid);
149 if (!jsep_transport) {
150 return nullptr;
151 }
152 return jsep_transport->SctpTransport();
153 }
154
SetIceConfig(const cricket::IceConfig & config)155 void JsepTransportController::SetIceConfig(const cricket::IceConfig& config) {
156 if (!network_thread_->IsCurrent()) {
157 network_thread_->Invoke<void>(RTC_FROM_HERE, [&] { SetIceConfig(config); });
158 return;
159 }
160
161 ice_config_ = config;
162 for (auto& dtls : GetDtlsTransports()) {
163 dtls->ice_transport()->SetIceConfig(ice_config_);
164 }
165 }
166
SetNeedsIceRestartFlag()167 void JsepTransportController::SetNeedsIceRestartFlag() {
168 RTC_DCHECK_RUN_ON(network_thread_);
169 for (auto& kv : jsep_transports_by_name_) {
170 kv.second->SetNeedsIceRestartFlag();
171 }
172 }
173
NeedsIceRestart(const std::string & transport_name) const174 bool JsepTransportController::NeedsIceRestart(
175 const std::string& transport_name) const {
176 RTC_DCHECK_RUN_ON(network_thread_);
177
178 const cricket::JsepTransport* transport =
179 GetJsepTransportByName(transport_name);
180 if (!transport) {
181 return false;
182 }
183 return transport->needs_ice_restart();
184 }
185
GetDtlsRole(const std::string & mid) const186 absl::optional<rtc::SSLRole> JsepTransportController::GetDtlsRole(
187 const std::string& mid) const {
188 // TODO(tommi): Remove this hop. Currently it's called from the signaling
189 // thread during negotiations, potentially multiple times.
190 // WebRtcSessionDescriptionFactory::InternalCreateAnswer is one example.
191 if (!network_thread_->IsCurrent()) {
192 return network_thread_->Invoke<absl::optional<rtc::SSLRole>>(
193 RTC_FROM_HERE, [&] { return GetDtlsRole(mid); });
194 }
195
196 RTC_DCHECK_RUN_ON(network_thread_);
197
198 const cricket::JsepTransport* t = GetJsepTransportForMid(mid);
199 if (!t) {
200 return absl::optional<rtc::SSLRole>();
201 }
202 return t->GetDtlsRole();
203 }
204
SetLocalCertificate(const rtc::scoped_refptr<rtc::RTCCertificate> & certificate)205 bool 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 RTC_DCHECK_RUN_ON(network_thread_);
213
214 // Can't change a certificate, or set a null certificate.
215 if (certificate_ || !certificate) {
216 return false;
217 }
218 certificate_ = certificate;
219
220 // Set certificate for JsepTransport, which verifies it matches the
221 // fingerprint in SDP, and DTLS transport.
222 // Fallback from DTLS to SDES is not supported.
223 for (auto& kv : jsep_transports_by_name_) {
224 kv.second->SetLocalCertificate(certificate_);
225 }
226 for (auto& dtls : GetDtlsTransports()) {
227 bool set_cert_success = dtls->SetLocalCertificate(certificate_);
228 RTC_DCHECK(set_cert_success);
229 }
230 return true;
231 }
232
233 rtc::scoped_refptr<rtc::RTCCertificate>
GetLocalCertificate(const std::string & transport_name) const234 JsepTransportController::GetLocalCertificate(
235 const std::string& transport_name) const {
236 if (!network_thread_->IsCurrent()) {
237 return network_thread_->Invoke<rtc::scoped_refptr<rtc::RTCCertificate>>(
238 RTC_FROM_HERE, [&] { return GetLocalCertificate(transport_name); });
239 }
240
241 RTC_DCHECK_RUN_ON(network_thread_);
242
243 const cricket::JsepTransport* t = GetJsepTransportByName(transport_name);
244 if (!t) {
245 return nullptr;
246 }
247 return t->GetLocalCertificate();
248 }
249
250 std::unique_ptr<rtc::SSLCertChain>
GetRemoteSSLCertChain(const std::string & transport_name) const251 JsepTransportController::GetRemoteSSLCertChain(
252 const std::string& transport_name) const {
253 if (!network_thread_->IsCurrent()) {
254 return network_thread_->Invoke<std::unique_ptr<rtc::SSLCertChain>>(
255 RTC_FROM_HERE, [&] { return GetRemoteSSLCertChain(transport_name); });
256 }
257 RTC_DCHECK_RUN_ON(network_thread_);
258
259 // Get the certificate from the RTP transport's DTLS handshake. Should be
260 // identical to the RTCP transport's, since they were given the same remote
261 // fingerprint.
262 auto jsep_transport = GetJsepTransportByName(transport_name);
263 if (!jsep_transport) {
264 return nullptr;
265 }
266 auto dtls = jsep_transport->rtp_dtls_transport();
267 if (!dtls) {
268 return nullptr;
269 }
270
271 return dtls->GetRemoteSSLCertChain();
272 }
273
MaybeStartGathering()274 void JsepTransportController::MaybeStartGathering() {
275 if (!network_thread_->IsCurrent()) {
276 network_thread_->Invoke<void>(RTC_FROM_HERE,
277 [&] { MaybeStartGathering(); });
278 return;
279 }
280
281 for (auto& dtls : GetDtlsTransports()) {
282 dtls->ice_transport()->MaybeStartGathering();
283 }
284 }
285
AddRemoteCandidates(const std::string & transport_name,const cricket::Candidates & candidates)286 RTCError JsepTransportController::AddRemoteCandidates(
287 const std::string& transport_name,
288 const cricket::Candidates& candidates) {
289 RTC_DCHECK_RUN_ON(network_thread_);
290 RTC_DCHECK(VerifyCandidates(candidates).ok());
291 auto jsep_transport = GetJsepTransportByName(transport_name);
292 if (!jsep_transport) {
293 RTC_LOG(LS_WARNING) << "Not adding candidate because the JsepTransport "
294 "doesn't exist. Ignore it.";
295 return RTCError::OK();
296 }
297 return jsep_transport->AddRemoteCandidates(candidates);
298 }
299
RemoveRemoteCandidates(const cricket::Candidates & candidates)300 RTCError JsepTransportController::RemoveRemoteCandidates(
301 const cricket::Candidates& candidates) {
302 if (!network_thread_->IsCurrent()) {
303 return network_thread_->Invoke<RTCError>(
304 RTC_FROM_HERE, [&] { return RemoveRemoteCandidates(candidates); });
305 }
306
307 RTC_DCHECK_RUN_ON(network_thread_);
308
309 // Verify each candidate before passing down to the transport layer.
310 RTCError error = VerifyCandidates(candidates);
311 if (!error.ok()) {
312 return error;
313 }
314
315 std::map<std::string, cricket::Candidates> candidates_by_transport_name;
316 for (const cricket::Candidate& cand : candidates) {
317 if (!cand.transport_name().empty()) {
318 candidates_by_transport_name[cand.transport_name()].push_back(cand);
319 } else {
320 RTC_LOG(LS_ERROR) << "Not removing candidate because it does not have a "
321 "transport name set: "
322 << cand.ToSensitiveString();
323 }
324 }
325
326 for (const auto& kv : candidates_by_transport_name) {
327 const std::string& transport_name = kv.first;
328 const cricket::Candidates& candidates = kv.second;
329 cricket::JsepTransport* jsep_transport =
330 GetJsepTransportByName(transport_name);
331 if (!jsep_transport) {
332 RTC_LOG(LS_WARNING)
333 << "Not removing candidate because the JsepTransport doesn't exist.";
334 continue;
335 }
336 for (const cricket::Candidate& candidate : candidates) {
337 cricket::DtlsTransportInternal* dtls =
338 candidate.component() == cricket::ICE_CANDIDATE_COMPONENT_RTP
339 ? jsep_transport->rtp_dtls_transport()
340 : jsep_transport->rtcp_dtls_transport();
341 if (dtls) {
342 dtls->ice_transport()->RemoveRemoteCandidate(candidate);
343 }
344 }
345 }
346 return RTCError::OK();
347 }
348
GetStats(const std::string & transport_name,cricket::TransportStats * stats)349 bool JsepTransportController::GetStats(const std::string& transport_name,
350 cricket::TransportStats* stats) {
351 RTC_DCHECK_RUN_ON(network_thread_);
352
353 cricket::JsepTransport* transport = GetJsepTransportByName(transport_name);
354 if (!transport) {
355 return false;
356 }
357 return transport->GetStats(stats);
358 }
359
SetActiveResetSrtpParams(bool active_reset_srtp_params)360 void JsepTransportController::SetActiveResetSrtpParams(
361 bool active_reset_srtp_params) {
362 if (!network_thread_->IsCurrent()) {
363 network_thread_->Invoke<void>(RTC_FROM_HERE, [=] {
364 SetActiveResetSrtpParams(active_reset_srtp_params);
365 });
366 return;
367 }
368 RTC_DCHECK_RUN_ON(network_thread_);
369 RTC_LOG(INFO)
370 << "Updating the active_reset_srtp_params for JsepTransportController: "
371 << active_reset_srtp_params;
372 active_reset_srtp_params_ = active_reset_srtp_params;
373 for (auto& kv : jsep_transports_by_name_) {
374 kv.second->SetActiveResetSrtpParams(active_reset_srtp_params);
375 }
376 }
377
RollbackTransports()378 void JsepTransportController::RollbackTransports() {
379 if (!network_thread_->IsCurrent()) {
380 network_thread_->Invoke<void>(RTC_FROM_HERE, [=] { RollbackTransports(); });
381 return;
382 }
383 RTC_DCHECK_RUN_ON(network_thread_);
384 for (auto&& mid : pending_mids_) {
385 RemoveTransportForMid(mid);
386 }
387 for (auto&& mid : pending_mids_) {
388 MaybeDestroyJsepTransport(mid);
389 }
390 pending_mids_.clear();
391 }
392
393 rtc::scoped_refptr<webrtc::IceTransportInterface>
CreateIceTransport(const std::string & transport_name,bool rtcp)394 JsepTransportController::CreateIceTransport(const std::string& transport_name,
395 bool rtcp) {
396 int component = rtcp ? cricket::ICE_CANDIDATE_COMPONENT_RTCP
397 : cricket::ICE_CANDIDATE_COMPONENT_RTP;
398
399 IceTransportInit init;
400 init.set_port_allocator(port_allocator_);
401 init.set_async_resolver_factory(async_resolver_factory_);
402 init.set_event_log(config_.event_log);
403 return config_.ice_transport_factory->CreateIceTransport(
404 transport_name, component, std::move(init));
405 }
406
407 std::unique_ptr<cricket::DtlsTransportInternal>
CreateDtlsTransport(const cricket::ContentInfo & content_info,cricket::IceTransportInternal * ice)408 JsepTransportController::CreateDtlsTransport(
409 const cricket::ContentInfo& content_info,
410 cricket::IceTransportInternal* ice) {
411 RTC_DCHECK_RUN_ON(network_thread_);
412
413 std::unique_ptr<cricket::DtlsTransportInternal> dtls;
414
415 if (config_.dtls_transport_factory) {
416 dtls = config_.dtls_transport_factory->CreateDtlsTransport(
417 ice, config_.crypto_options, config_.ssl_max_version);
418 } else {
419 dtls = std::make_unique<cricket::DtlsTransport>(ice, config_.crypto_options,
420 config_.event_log,
421 config_.ssl_max_version);
422 }
423
424 RTC_DCHECK(dtls);
425 dtls->ice_transport()->SetIceRole(ice_role_);
426 dtls->ice_transport()->SetIceTiebreaker(ice_tiebreaker_);
427 dtls->ice_transport()->SetIceConfig(ice_config_);
428 if (certificate_) {
429 bool set_cert_success = dtls->SetLocalCertificate(certificate_);
430 RTC_DCHECK(set_cert_success);
431 }
432
433 // Connect to signals offered by the DTLS and ICE transport.
434 dtls->SignalWritableState.connect(
435 this, &JsepTransportController::OnTransportWritableState_n);
436 dtls->SignalReceivingState.connect(
437 this, &JsepTransportController::OnTransportReceivingState_n);
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()->SignalCandidateError.connect(
443 this, &JsepTransportController::OnTransportCandidateError_n);
444 dtls->ice_transport()->SignalCandidatesRemoved.connect(
445 this, &JsepTransportController::OnTransportCandidatesRemoved_n);
446 dtls->ice_transport()->SignalRoleConflict.connect(
447 this, &JsepTransportController::OnTransportRoleConflict_n);
448 dtls->ice_transport()->SignalStateChanged.connect(
449 this, &JsepTransportController::OnTransportStateChanged_n);
450 dtls->ice_transport()->SignalIceTransportStateChanged.connect(
451 this, &JsepTransportController::OnTransportStateChanged_n);
452 dtls->ice_transport()->SignalCandidatePairChanged.connect(
453 this, &JsepTransportController::OnTransportCandidatePairChanged_n);
454
455 dtls->SubscribeDtlsHandshakeError(
456 [this](rtc::SSLHandshakeError error) { OnDtlsHandshakeError(error); });
457 return dtls;
458 }
459
460 std::unique_ptr<webrtc::RtpTransport>
CreateUnencryptedRtpTransport(const std::string & transport_name,rtc::PacketTransportInternal * rtp_packet_transport,rtc::PacketTransportInternal * rtcp_packet_transport)461 JsepTransportController::CreateUnencryptedRtpTransport(
462 const std::string& transport_name,
463 rtc::PacketTransportInternal* rtp_packet_transport,
464 rtc::PacketTransportInternal* rtcp_packet_transport) {
465 RTC_DCHECK_RUN_ON(network_thread_);
466 auto unencrypted_rtp_transport =
467 std::make_unique<RtpTransport>(rtcp_packet_transport == nullptr);
468 unencrypted_rtp_transport->SetRtpPacketTransport(rtp_packet_transport);
469 if (rtcp_packet_transport) {
470 unencrypted_rtp_transport->SetRtcpPacketTransport(rtcp_packet_transport);
471 }
472 return unencrypted_rtp_transport;
473 }
474
475 std::unique_ptr<webrtc::SrtpTransport>
CreateSdesTransport(const std::string & transport_name,cricket::DtlsTransportInternal * rtp_dtls_transport,cricket::DtlsTransportInternal * rtcp_dtls_transport)476 JsepTransportController::CreateSdesTransport(
477 const std::string& transport_name,
478 cricket::DtlsTransportInternal* rtp_dtls_transport,
479 cricket::DtlsTransportInternal* rtcp_dtls_transport) {
480 RTC_DCHECK_RUN_ON(network_thread_);
481 auto srtp_transport =
482 std::make_unique<webrtc::SrtpTransport>(rtcp_dtls_transport == nullptr);
483 RTC_DCHECK(rtp_dtls_transport);
484 srtp_transport->SetRtpPacketTransport(rtp_dtls_transport);
485 if (rtcp_dtls_transport) {
486 srtp_transport->SetRtcpPacketTransport(rtcp_dtls_transport);
487 }
488 if (config_.enable_external_auth) {
489 srtp_transport->EnableExternalAuth();
490 }
491 return srtp_transport;
492 }
493
494 std::unique_ptr<webrtc::DtlsSrtpTransport>
CreateDtlsSrtpTransport(const std::string & transport_name,cricket::DtlsTransportInternal * rtp_dtls_transport,cricket::DtlsTransportInternal * rtcp_dtls_transport)495 JsepTransportController::CreateDtlsSrtpTransport(
496 const std::string& transport_name,
497 cricket::DtlsTransportInternal* rtp_dtls_transport,
498 cricket::DtlsTransportInternal* rtcp_dtls_transport) {
499 RTC_DCHECK_RUN_ON(network_thread_);
500 auto dtls_srtp_transport = std::make_unique<webrtc::DtlsSrtpTransport>(
501 rtcp_dtls_transport == nullptr);
502 if (config_.enable_external_auth) {
503 dtls_srtp_transport->EnableExternalAuth();
504 }
505
506 dtls_srtp_transport->SetDtlsTransports(rtp_dtls_transport,
507 rtcp_dtls_transport);
508 dtls_srtp_transport->SetActiveResetSrtpParams(active_reset_srtp_params_);
509 // Capturing this in the callback because JsepTransportController will always
510 // outlive the DtlsSrtpTransport.
511 dtls_srtp_transport->SetOnDtlsStateChange([this]() {
512 RTC_DCHECK_RUN_ON(this->network_thread_);
513 this->UpdateAggregateStates_n();
514 });
515 return dtls_srtp_transport;
516 }
517
518 std::vector<cricket::DtlsTransportInternal*>
GetDtlsTransports()519 JsepTransportController::GetDtlsTransports() {
520 RTC_DCHECK_RUN_ON(network_thread_);
521 std::vector<cricket::DtlsTransportInternal*> dtls_transports;
522 for (auto it = jsep_transports_by_name_.begin();
523 it != jsep_transports_by_name_.end(); ++it) {
524 auto jsep_transport = it->second.get();
525 RTC_DCHECK(jsep_transport);
526 if (jsep_transport->rtp_dtls_transport()) {
527 dtls_transports.push_back(jsep_transport->rtp_dtls_transport());
528 }
529
530 if (jsep_transport->rtcp_dtls_transport()) {
531 dtls_transports.push_back(jsep_transport->rtcp_dtls_transport());
532 }
533 }
534 return dtls_transports;
535 }
536
ApplyDescription_n(bool local,SdpType type,const cricket::SessionDescription * description)537 RTCError JsepTransportController::ApplyDescription_n(
538 bool local,
539 SdpType type,
540 const cricket::SessionDescription* description) {
541 RTC_DCHECK(description);
542
543 if (local) {
544 local_desc_ = description;
545 } else {
546 remote_desc_ = description;
547 }
548
549 RTCError error;
550 error = ValidateAndMaybeUpdateBundleGroup(local, type, description);
551 if (!error.ok()) {
552 return error;
553 }
554
555 std::vector<int> merged_encrypted_extension_ids;
556 if (bundle_group_) {
557 merged_encrypted_extension_ids =
558 MergeEncryptedHeaderExtensionIdsForBundle(description);
559 }
560
561 for (const cricket::ContentInfo& content_info : description->contents()) {
562 // Don't create transports for rejected m-lines and bundled m-lines."
563 if (content_info.rejected ||
564 (IsBundled(content_info.name) && content_info.name != *bundled_mid())) {
565 continue;
566 }
567 error = MaybeCreateJsepTransport(local, content_info, *description);
568 if (!error.ok()) {
569 return error;
570 }
571 }
572
573 RTC_DCHECK(description->contents().size() ==
574 description->transport_infos().size());
575 for (size_t i = 0; i < description->contents().size(); ++i) {
576 const cricket::ContentInfo& content_info = description->contents()[i];
577 const cricket::TransportInfo& transport_info =
578 description->transport_infos()[i];
579 if (content_info.rejected) {
580 HandleRejectedContent(content_info, description);
581 continue;
582 }
583
584 if (IsBundled(content_info.name) && content_info.name != *bundled_mid()) {
585 if (!HandleBundledContent(content_info)) {
586 return RTCError(RTCErrorType::INVALID_PARAMETER,
587 "Failed to process the bundled m= section with mid='" +
588 content_info.name + "'.");
589 }
590 continue;
591 }
592
593 error = ValidateContent(content_info);
594 if (!error.ok()) {
595 return error;
596 }
597
598 std::vector<int> extension_ids;
599 if (bundled_mid() && content_info.name == *bundled_mid()) {
600 extension_ids = merged_encrypted_extension_ids;
601 } else {
602 extension_ids = GetEncryptedHeaderExtensionIds(content_info);
603 }
604
605 int rtp_abs_sendtime_extn_id =
606 GetRtpAbsSendTimeHeaderExtensionId(content_info);
607
608 cricket::JsepTransport* transport =
609 GetJsepTransportForMid(content_info.name);
610 RTC_DCHECK(transport);
611
612 SetIceRole_n(DetermineIceRole(transport, transport_info, type, local));
613
614 cricket::JsepTransportDescription jsep_description =
615 CreateJsepTransportDescription(content_info, transport_info,
616 extension_ids, rtp_abs_sendtime_extn_id);
617 if (local) {
618 error =
619 transport->SetLocalJsepTransportDescription(jsep_description, type);
620 } else {
621 error =
622 transport->SetRemoteJsepTransportDescription(jsep_description, type);
623 }
624
625 if (!error.ok()) {
626 LOG_AND_RETURN_ERROR(
627 RTCErrorType::INVALID_PARAMETER,
628 "Failed to apply the description for m= section with mid='" +
629 content_info.name + "': " + error.message());
630 }
631 }
632 if (type == SdpType::kAnswer) {
633 pending_mids_.clear();
634 }
635 return RTCError::OK();
636 }
637
ValidateAndMaybeUpdateBundleGroup(bool local,SdpType type,const cricket::SessionDescription * description)638 RTCError JsepTransportController::ValidateAndMaybeUpdateBundleGroup(
639 bool local,
640 SdpType type,
641 const cricket::SessionDescription* description) {
642 RTC_DCHECK(description);
643 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 (const std::string& 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 (const std::string& content_name :
665 new_bundle_group->content_names()) {
666 if (!offered_bundle_group ||
667 !offered_bundle_group->HasContentName(content_name)) {
668 return RTCError(RTCErrorType::INVALID_PARAMETER,
669 "The BUNDLE group in answer contains a MID='" +
670 content_name +
671 "' that was "
672 "not in the offered group.");
673 }
674 }
675 }
676
677 if (bundle_group_) {
678 for (const std::string& content_name : bundle_group_->content_names()) {
679 // An answer that removes m= sections from pre-negotiated BUNDLE group
680 // without rejecting it, is invalid.
681 if (!new_bundle_group ||
682 !new_bundle_group->HasContentName(content_name)) {
683 auto* content_info = description->GetContentByName(content_name);
684 if (!content_info || !content_info->rejected) {
685 return RTCError(RTCErrorType::INVALID_PARAMETER,
686 "Answer cannot remove m= section with mid='" +
687 content_name +
688 "' from already-established BUNDLE group.");
689 }
690 }
691 }
692 }
693 }
694
695 if (config_.bundle_policy ==
696 PeerConnectionInterface::kBundlePolicyMaxBundle &&
697 !description->HasGroup(cricket::GROUP_TYPE_BUNDLE)) {
698 return RTCError(RTCErrorType::INVALID_PARAMETER,
699 "max-bundle is used but no bundle group found.");
700 }
701
702 if (ShouldUpdateBundleGroup(type, description)) {
703 bundle_group_ = *new_bundle_group;
704 }
705
706 if (!bundled_mid()) {
707 return RTCError::OK();
708 }
709
710 auto bundled_content = description->GetContentByName(*bundled_mid());
711 if (!bundled_content) {
712 return RTCError(
713 RTCErrorType::INVALID_PARAMETER,
714 "An m= section associated with the BUNDLE-tag doesn't exist.");
715 }
716
717 // If the |bundled_content| is rejected, other contents in the bundle group
718 // should be rejected.
719 if (bundled_content->rejected) {
720 for (const auto& content_name : bundle_group_->content_names()) {
721 auto other_content = description->GetContentByName(content_name);
722 if (!other_content->rejected) {
723 return RTCError(RTCErrorType::INVALID_PARAMETER,
724 "The m= section with mid='" + content_name +
725 "' should be rejected.");
726 }
727 }
728 }
729
730 return RTCError::OK();
731 }
732
ValidateContent(const cricket::ContentInfo & content_info)733 RTCError JsepTransportController::ValidateContent(
734 const cricket::ContentInfo& content_info) {
735 if (config_.rtcp_mux_policy ==
736 PeerConnectionInterface::kRtcpMuxPolicyRequire &&
737 content_info.type == cricket::MediaProtocolType::kRtp &&
738 !content_info.media_description()->rtcp_mux()) {
739 return RTCError(RTCErrorType::INVALID_PARAMETER,
740 "The m= section with mid='" + content_info.name +
741 "' is invalid. RTCP-MUX is not "
742 "enabled when it is required.");
743 }
744 return RTCError::OK();
745 }
746
HandleRejectedContent(const cricket::ContentInfo & content_info,const cricket::SessionDescription * description)747 void JsepTransportController::HandleRejectedContent(
748 const cricket::ContentInfo& content_info,
749 const cricket::SessionDescription* description) {
750 // If the content is rejected, let the
751 // BaseChannel/SctpTransport change the RtpTransport/DtlsTransport first,
752 // then destroy the cricket::JsepTransport.
753 RemoveTransportForMid(content_info.name);
754 if (content_info.name == bundled_mid()) {
755 for (const auto& content_name : bundle_group_->content_names()) {
756 RemoveTransportForMid(content_name);
757 }
758 bundle_group_.reset();
759 } else if (IsBundled(content_info.name)) {
760 // Remove the rejected content from the |bundle_group_|.
761 bundle_group_->RemoveContentName(content_info.name);
762 // Reset the bundle group if nothing left.
763 if (!bundle_group_->FirstContentName()) {
764 bundle_group_.reset();
765 }
766 }
767 MaybeDestroyJsepTransport(content_info.name);
768 }
769
HandleBundledContent(const cricket::ContentInfo & content_info)770 bool JsepTransportController::HandleBundledContent(
771 const cricket::ContentInfo& content_info) {
772 auto jsep_transport = GetJsepTransportByName(*bundled_mid());
773 RTC_DCHECK(jsep_transport);
774 // If the content is bundled, let the
775 // BaseChannel/SctpTransport change the RtpTransport/DtlsTransport first,
776 // then destroy the cricket::JsepTransport.
777 if (SetTransportForMid(content_info.name, jsep_transport)) {
778 // TODO(bugs.webrtc.org/9719) For media transport this is far from ideal,
779 // because it means that we first create media transport and start
780 // connecting it, and then we destroy it. We will need to address it before
781 // video path is enabled.
782 MaybeDestroyJsepTransport(content_info.name);
783 return true;
784 }
785 return false;
786 }
787
SetTransportForMid(const std::string & mid,cricket::JsepTransport * jsep_transport)788 bool JsepTransportController::SetTransportForMid(
789 const std::string& mid,
790 cricket::JsepTransport* jsep_transport) {
791 RTC_DCHECK_RUN_ON(network_thread_);
792 RTC_DCHECK(jsep_transport);
793
794 auto it = mid_to_transport_.find(mid);
795 if (it != mid_to_transport_.end() && it->second == jsep_transport)
796 return true;
797
798 pending_mids_.push_back(mid);
799
800 if (it == mid_to_transport_.end()) {
801 mid_to_transport_.insert(std::make_pair(mid, jsep_transport));
802 } else {
803 it->second = jsep_transport;
804 }
805
806 return config_.transport_observer->OnTransportChanged(
807 mid, jsep_transport->rtp_transport(), jsep_transport->RtpDtlsTransport(),
808 jsep_transport->data_channel_transport());
809 }
810
RemoveTransportForMid(const std::string & mid)811 void JsepTransportController::RemoveTransportForMid(const std::string& mid) {
812 RTC_DCHECK_RUN_ON(network_thread_);
813 bool ret = config_.transport_observer->OnTransportChanged(mid, nullptr,
814 nullptr, nullptr);
815 // Calling OnTransportChanged with nullptr should always succeed, since it is
816 // only expected to fail when adding media to a transport (not removing).
817 RTC_DCHECK(ret);
818
819 mid_to_transport_.erase(mid);
820 }
821
822 cricket::JsepTransportDescription
CreateJsepTransportDescription(const cricket::ContentInfo & content_info,const cricket::TransportInfo & transport_info,const std::vector<int> & encrypted_extension_ids,int rtp_abs_sendtime_extn_id)823 JsepTransportController::CreateJsepTransportDescription(
824 const cricket::ContentInfo& content_info,
825 const cricket::TransportInfo& transport_info,
826 const std::vector<int>& encrypted_extension_ids,
827 int rtp_abs_sendtime_extn_id) {
828 const cricket::MediaContentDescription* content_desc =
829 content_info.media_description();
830 RTC_DCHECK(content_desc);
831 bool rtcp_mux_enabled = content_info.type == cricket::MediaProtocolType::kSctp
832 ? true
833 : content_desc->rtcp_mux();
834
835 return cricket::JsepTransportDescription(
836 rtcp_mux_enabled, content_desc->cryptos(), encrypted_extension_ids,
837 rtp_abs_sendtime_extn_id, transport_info.description);
838 }
839
ShouldUpdateBundleGroup(SdpType type,const cricket::SessionDescription * description)840 bool JsepTransportController::ShouldUpdateBundleGroup(
841 SdpType type,
842 const cricket::SessionDescription* description) {
843 if (config_.bundle_policy ==
844 PeerConnectionInterface::kBundlePolicyMaxBundle) {
845 return true;
846 }
847
848 if (type != SdpType::kAnswer) {
849 return false;
850 }
851
852 RTC_DCHECK(local_desc_ && remote_desc_);
853 const cricket::ContentGroup* local_bundle =
854 local_desc_->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
855 const cricket::ContentGroup* remote_bundle =
856 remote_desc_->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
857 return local_bundle && remote_bundle;
858 }
859
GetEncryptedHeaderExtensionIds(const cricket::ContentInfo & content_info)860 std::vector<int> JsepTransportController::GetEncryptedHeaderExtensionIds(
861 const cricket::ContentInfo& content_info) {
862 const cricket::MediaContentDescription* content_desc =
863 content_info.media_description();
864
865 if (!config_.crypto_options.srtp.enable_encrypted_rtp_header_extensions) {
866 return std::vector<int>();
867 }
868
869 std::vector<int> encrypted_header_extension_ids;
870 for (const auto& extension : content_desc->rtp_header_extensions()) {
871 if (!extension.encrypt) {
872 continue;
873 }
874 if (!absl::c_linear_search(encrypted_header_extension_ids, extension.id)) {
875 encrypted_header_extension_ids.push_back(extension.id);
876 }
877 }
878 return encrypted_header_extension_ids;
879 }
880
881 std::vector<int>
MergeEncryptedHeaderExtensionIdsForBundle(const cricket::SessionDescription * description)882 JsepTransportController::MergeEncryptedHeaderExtensionIdsForBundle(
883 const cricket::SessionDescription* description) {
884 RTC_DCHECK(description);
885 RTC_DCHECK(bundle_group_);
886
887 std::vector<int> merged_ids;
888 // Union the encrypted header IDs in the group when bundle is enabled.
889 for (const cricket::ContentInfo& content_info : description->contents()) {
890 if (bundle_group_->HasContentName(content_info.name)) {
891 std::vector<int> extension_ids =
892 GetEncryptedHeaderExtensionIds(content_info);
893 for (int id : extension_ids) {
894 if (!absl::c_linear_search(merged_ids, id)) {
895 merged_ids.push_back(id);
896 }
897 }
898 }
899 }
900 return merged_ids;
901 }
902
GetRtpAbsSendTimeHeaderExtensionId(const cricket::ContentInfo & content_info)903 int JsepTransportController::GetRtpAbsSendTimeHeaderExtensionId(
904 const cricket::ContentInfo& content_info) {
905 if (!config_.enable_external_auth) {
906 return -1;
907 }
908
909 const cricket::MediaContentDescription* content_desc =
910 content_info.media_description();
911
912 const webrtc::RtpExtension* send_time_extension =
913 webrtc::RtpExtension::FindHeaderExtensionByUri(
914 content_desc->rtp_header_extensions(),
915 webrtc::RtpExtension::kAbsSendTimeUri);
916 return send_time_extension ? send_time_extension->id : -1;
917 }
918
GetJsepTransportForMid(const std::string & mid) const919 const cricket::JsepTransport* JsepTransportController::GetJsepTransportForMid(
920 const std::string& mid) const {
921 auto it = mid_to_transport_.find(mid);
922 return it == mid_to_transport_.end() ? nullptr : it->second;
923 }
924
GetJsepTransportForMid(const std::string & mid)925 cricket::JsepTransport* JsepTransportController::GetJsepTransportForMid(
926 const std::string& mid) {
927 auto it = mid_to_transport_.find(mid);
928 return it == mid_to_transport_.end() ? nullptr : it->second;
929 }
930
GetJsepTransportByName(const std::string & transport_name) const931 const cricket::JsepTransport* JsepTransportController::GetJsepTransportByName(
932 const std::string& transport_name) const {
933 auto it = jsep_transports_by_name_.find(transport_name);
934 return (it == jsep_transports_by_name_.end()) ? nullptr : it->second.get();
935 }
936
GetJsepTransportByName(const std::string & transport_name)937 cricket::JsepTransport* JsepTransportController::GetJsepTransportByName(
938 const std::string& transport_name) {
939 auto it = jsep_transports_by_name_.find(transport_name);
940 return (it == jsep_transports_by_name_.end()) ? nullptr : it->second.get();
941 }
942
MaybeCreateJsepTransport(bool local,const cricket::ContentInfo & content_info,const cricket::SessionDescription & description)943 RTCError JsepTransportController::MaybeCreateJsepTransport(
944 bool local,
945 const cricket::ContentInfo& content_info,
946 const cricket::SessionDescription& description) {
947 cricket::JsepTransport* transport = GetJsepTransportByName(content_info.name);
948 if (transport) {
949 return RTCError::OK();
950 }
951
952 const cricket::MediaContentDescription* content_desc =
953 content_info.media_description();
954 if (certificate_ && !content_desc->cryptos().empty()) {
955 return RTCError(RTCErrorType::INVALID_PARAMETER,
956 "SDES and DTLS-SRTP cannot be enabled at the same time.");
957 }
958
959 rtc::scoped_refptr<webrtc::IceTransportInterface> ice =
960 CreateIceTransport(content_info.name, /*rtcp=*/false);
961 RTC_DCHECK(ice);
962
963 std::unique_ptr<cricket::DtlsTransportInternal> rtp_dtls_transport =
964 CreateDtlsTransport(content_info, ice->internal());
965
966 std::unique_ptr<cricket::DtlsTransportInternal> rtcp_dtls_transport;
967 std::unique_ptr<RtpTransport> unencrypted_rtp_transport;
968 std::unique_ptr<SrtpTransport> sdes_transport;
969 std::unique_ptr<DtlsSrtpTransport> dtls_srtp_transport;
970
971 rtc::scoped_refptr<webrtc::IceTransportInterface> rtcp_ice;
972 if (config_.rtcp_mux_policy !=
973 PeerConnectionInterface::kRtcpMuxPolicyRequire &&
974 content_info.type == cricket::MediaProtocolType::kRtp) {
975 rtcp_ice = CreateIceTransport(content_info.name, /*rtcp=*/true);
976 rtcp_dtls_transport =
977 CreateDtlsTransport(content_info, rtcp_ice->internal());
978 }
979
980 if (config_.disable_encryption) {
981 RTC_LOG(LS_INFO)
982 << "Creating UnencryptedRtpTransport, becayse encryption is disabled.";
983 unencrypted_rtp_transport = CreateUnencryptedRtpTransport(
984 content_info.name, rtp_dtls_transport.get(), rtcp_dtls_transport.get());
985 } else if (!content_desc->cryptos().empty()) {
986 sdes_transport = CreateSdesTransport(
987 content_info.name, rtp_dtls_transport.get(), rtcp_dtls_transport.get());
988 RTC_LOG(LS_INFO) << "Creating SdesTransport.";
989 } else {
990 RTC_LOG(LS_INFO) << "Creating DtlsSrtpTransport.";
991 dtls_srtp_transport = CreateDtlsSrtpTransport(
992 content_info.name, rtp_dtls_transport.get(), rtcp_dtls_transport.get());
993 }
994
995 std::unique_ptr<cricket::SctpTransportInternal> sctp_transport;
996 if (config_.sctp_factory) {
997 sctp_transport =
998 config_.sctp_factory->CreateSctpTransport(rtp_dtls_transport.get());
999 }
1000
1001 std::unique_ptr<cricket::JsepTransport> jsep_transport =
1002 std::make_unique<cricket::JsepTransport>(
1003 content_info.name, certificate_, std::move(ice), std::move(rtcp_ice),
1004 std::move(unencrypted_rtp_transport), std::move(sdes_transport),
1005 std::move(dtls_srtp_transport), std::move(rtp_dtls_transport),
1006 std::move(rtcp_dtls_transport), std::move(sctp_transport));
1007
1008 jsep_transport->rtp_transport()->SignalRtcpPacketReceived.connect(
1009 this, &JsepTransportController::OnRtcpPacketReceived_n);
1010
1011 jsep_transport->SignalRtcpMuxActive.connect(
1012 this, &JsepTransportController::UpdateAggregateStates_n);
1013 SetTransportForMid(content_info.name, jsep_transport.get());
1014
1015 jsep_transports_by_name_[content_info.name] = std::move(jsep_transport);
1016 UpdateAggregateStates_n();
1017 return RTCError::OK();
1018 }
1019
MaybeDestroyJsepTransport(const std::string & mid)1020 void JsepTransportController::MaybeDestroyJsepTransport(
1021 const std::string& mid) {
1022 auto jsep_transport = GetJsepTransportByName(mid);
1023 if (!jsep_transport) {
1024 return;
1025 }
1026
1027 // Don't destroy the JsepTransport if there are still media sections referring
1028 // to it.
1029 for (const auto& kv : mid_to_transport_) {
1030 if (kv.second == jsep_transport) {
1031 return;
1032 }
1033 }
1034
1035 jsep_transports_by_name_.erase(mid);
1036 UpdateAggregateStates_n();
1037 }
1038
DestroyAllJsepTransports_n()1039 void JsepTransportController::DestroyAllJsepTransports_n() {
1040 for (const auto& jsep_transport : jsep_transports_by_name_) {
1041 config_.transport_observer->OnTransportChanged(jsep_transport.first,
1042 nullptr, nullptr, nullptr);
1043 }
1044
1045 jsep_transports_by_name_.clear();
1046 }
1047
SetIceRole_n(cricket::IceRole ice_role)1048 void JsepTransportController::SetIceRole_n(cricket::IceRole ice_role) {
1049 ice_role_ = ice_role;
1050 auto dtls_transports = GetDtlsTransports();
1051 for (auto& dtls : dtls_transports) {
1052 dtls->ice_transport()->SetIceRole(ice_role_);
1053 }
1054 }
1055
DetermineIceRole(cricket::JsepTransport * jsep_transport,const cricket::TransportInfo & transport_info,SdpType type,bool local)1056 cricket::IceRole JsepTransportController::DetermineIceRole(
1057 cricket::JsepTransport* jsep_transport,
1058 const cricket::TransportInfo& transport_info,
1059 SdpType type,
1060 bool local) {
1061 cricket::IceRole ice_role = ice_role_;
1062 auto tdesc = transport_info.description;
1063 if (local) {
1064 // The initial offer side may use ICE Lite, in which case, per RFC5245
1065 // Section 5.1.1, the answer side should take the controlling role if it is
1066 // in the full ICE mode.
1067 //
1068 // When both sides use ICE Lite, the initial offer side must take the
1069 // controlling role, and this is the default logic implemented in
1070 // SetLocalDescription in JsepTransportController.
1071 if (jsep_transport->remote_description() &&
1072 jsep_transport->remote_description()->transport_desc.ice_mode ==
1073 cricket::ICEMODE_LITE &&
1074 ice_role_ == cricket::ICEROLE_CONTROLLED &&
1075 tdesc.ice_mode == cricket::ICEMODE_FULL) {
1076 ice_role = cricket::ICEROLE_CONTROLLING;
1077 }
1078 } else {
1079 // If our role is cricket::ICEROLE_CONTROLLED and the remote endpoint
1080 // supports only ice_lite, this local endpoint should take the CONTROLLING
1081 // role.
1082 // TODO(deadbeef): This is a session-level attribute, so it really shouldn't
1083 // be in a TransportDescription in the first place...
1084 if (ice_role_ == cricket::ICEROLE_CONTROLLED &&
1085 tdesc.ice_mode == cricket::ICEMODE_LITE) {
1086 ice_role = cricket::ICEROLE_CONTROLLING;
1087 }
1088
1089 // If we use ICE Lite and the remote endpoint uses the full implementation
1090 // of ICE, the local endpoint must take the controlled role, and the other
1091 // side must be the controlling role.
1092 if (jsep_transport->local_description() &&
1093 jsep_transport->local_description()->transport_desc.ice_mode ==
1094 cricket::ICEMODE_LITE &&
1095 ice_role_ == cricket::ICEROLE_CONTROLLING &&
1096 tdesc.ice_mode == cricket::ICEMODE_FULL) {
1097 ice_role = cricket::ICEROLE_CONTROLLED;
1098 }
1099 }
1100
1101 return ice_role;
1102 }
1103
OnTransportWritableState_n(rtc::PacketTransportInternal * transport)1104 void JsepTransportController::OnTransportWritableState_n(
1105 rtc::PacketTransportInternal* transport) {
1106 RTC_LOG(LS_INFO) << " Transport " << transport->transport_name()
1107 << " writability changed to " << transport->writable()
1108 << ".";
1109 UpdateAggregateStates_n();
1110 }
1111
OnTransportReceivingState_n(rtc::PacketTransportInternal * transport)1112 void JsepTransportController::OnTransportReceivingState_n(
1113 rtc::PacketTransportInternal* transport) {
1114 UpdateAggregateStates_n();
1115 }
1116
OnTransportGatheringState_n(cricket::IceTransportInternal * transport)1117 void JsepTransportController::OnTransportGatheringState_n(
1118 cricket::IceTransportInternal* transport) {
1119 UpdateAggregateStates_n();
1120 }
1121
OnTransportCandidateGathered_n(cricket::IceTransportInternal * transport,const cricket::Candidate & candidate)1122 void JsepTransportController::OnTransportCandidateGathered_n(
1123 cricket::IceTransportInternal* transport,
1124 const cricket::Candidate& candidate) {
1125 // We should never signal peer-reflexive candidates.
1126 if (candidate.type() == cricket::PRFLX_PORT_TYPE) {
1127 RTC_NOTREACHED();
1128 return;
1129 }
1130
1131 signal_ice_candidates_gathered_.Send(
1132 transport->transport_name(), std::vector<cricket::Candidate>{candidate});
1133 }
1134
OnTransportCandidateError_n(cricket::IceTransportInternal * transport,const cricket::IceCandidateErrorEvent & event)1135 void JsepTransportController::OnTransportCandidateError_n(
1136 cricket::IceTransportInternal* transport,
1137 const cricket::IceCandidateErrorEvent& event) {
1138 signal_ice_candidate_error_.Send(event);
1139 }
OnTransportCandidatesRemoved_n(cricket::IceTransportInternal * transport,const cricket::Candidates & candidates)1140 void JsepTransportController::OnTransportCandidatesRemoved_n(
1141 cricket::IceTransportInternal* transport,
1142 const cricket::Candidates& candidates) {
1143 signal_ice_candidates_removed_.Send(candidates);
1144 }
OnTransportCandidatePairChanged_n(const cricket::CandidatePairChangeEvent & event)1145 void JsepTransportController::OnTransportCandidatePairChanged_n(
1146 const cricket::CandidatePairChangeEvent& event) {
1147 signal_ice_candidate_pair_changed_.Send(event);
1148 }
1149
OnTransportRoleConflict_n(cricket::IceTransportInternal * transport)1150 void JsepTransportController::OnTransportRoleConflict_n(
1151 cricket::IceTransportInternal* transport) {
1152 // Note: since the role conflict is handled entirely on the network thread,
1153 // we don't need to worry about role conflicts occurring on two ports at
1154 // once. The first one encountered should immediately reverse the role.
1155 cricket::IceRole reversed_role = (ice_role_ == cricket::ICEROLE_CONTROLLING)
1156 ? cricket::ICEROLE_CONTROLLED
1157 : cricket::ICEROLE_CONTROLLING;
1158 RTC_LOG(LS_INFO) << "Got role conflict; switching to "
1159 << (reversed_role == cricket::ICEROLE_CONTROLLING
1160 ? "controlling"
1161 : "controlled")
1162 << " role.";
1163 SetIceRole_n(reversed_role);
1164 }
1165
OnTransportStateChanged_n(cricket::IceTransportInternal * transport)1166 void JsepTransportController::OnTransportStateChanged_n(
1167 cricket::IceTransportInternal* transport) {
1168 RTC_LOG(LS_INFO) << transport->transport_name() << " Transport "
1169 << transport->component()
1170 << " state changed. Check if state is complete.";
1171 UpdateAggregateStates_n();
1172 }
1173
UpdateAggregateStates_n()1174 void JsepTransportController::UpdateAggregateStates_n() {
1175 auto dtls_transports = GetDtlsTransports();
1176 cricket::IceConnectionState new_connection_state =
1177 cricket::kIceConnectionConnecting;
1178 PeerConnectionInterface::IceConnectionState new_ice_connection_state =
1179 PeerConnectionInterface::IceConnectionState::kIceConnectionNew;
1180 PeerConnectionInterface::PeerConnectionState new_combined_state =
1181 PeerConnectionInterface::PeerConnectionState::kNew;
1182 cricket::IceGatheringState new_gathering_state = cricket::kIceGatheringNew;
1183 bool any_failed = false;
1184 bool all_connected = !dtls_transports.empty();
1185 bool all_completed = !dtls_transports.empty();
1186 bool any_gathering = false;
1187 bool all_done_gathering = !dtls_transports.empty();
1188
1189 std::map<IceTransportState, int> ice_state_counts;
1190 std::map<cricket::DtlsTransportState, int> dtls_state_counts;
1191
1192 for (const auto& dtls : dtls_transports) {
1193 any_failed = any_failed || dtls->ice_transport()->GetState() ==
1194 cricket::IceTransportState::STATE_FAILED;
1195 all_connected = all_connected && dtls->writable();
1196 all_completed =
1197 all_completed && dtls->writable() &&
1198 dtls->ice_transport()->GetState() ==
1199 cricket::IceTransportState::STATE_COMPLETED &&
1200 dtls->ice_transport()->GetIceRole() == cricket::ICEROLE_CONTROLLING &&
1201 dtls->ice_transport()->gathering_state() ==
1202 cricket::kIceGatheringComplete;
1203 any_gathering = any_gathering || dtls->ice_transport()->gathering_state() !=
1204 cricket::kIceGatheringNew;
1205 all_done_gathering =
1206 all_done_gathering && dtls->ice_transport()->gathering_state() ==
1207 cricket::kIceGatheringComplete;
1208
1209 dtls_state_counts[dtls->dtls_state()]++;
1210 ice_state_counts[dtls->ice_transport()->GetIceTransportState()]++;
1211 }
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
1223 signal_ice_connection_state_.Send(new_connection_state);
1224 }
1225
1226 // Compute the current RTCIceConnectionState as described in
1227 // https://www.w3.org/TR/webrtc/#dom-rtciceconnectionstate.
1228 // The PeerConnection is responsible for handling the "closed" state.
1229 int total_ice_checking = ice_state_counts[IceTransportState::kChecking];
1230 int total_ice_connected = ice_state_counts[IceTransportState::kConnected];
1231 int total_ice_completed = ice_state_counts[IceTransportState::kCompleted];
1232 int total_ice_failed = ice_state_counts[IceTransportState::kFailed];
1233 int total_ice_disconnected =
1234 ice_state_counts[IceTransportState::kDisconnected];
1235 int total_ice_closed = ice_state_counts[IceTransportState::kClosed];
1236 int total_ice_new = ice_state_counts[IceTransportState::kNew];
1237 int total_ice = dtls_transports.size();
1238
1239 if (total_ice_failed > 0) {
1240 // Any RTCIceTransports are in the "failed" state.
1241 new_ice_connection_state = PeerConnectionInterface::kIceConnectionFailed;
1242 } else if (total_ice_disconnected > 0) {
1243 // None of the previous states apply and any RTCIceTransports are in the
1244 // "disconnected" state.
1245 new_ice_connection_state =
1246 PeerConnectionInterface::kIceConnectionDisconnected;
1247 } else if (total_ice_new + total_ice_closed == total_ice) {
1248 // None of the previous states apply and all RTCIceTransports are in the
1249 // "new" or "closed" state, or there are no transports.
1250 new_ice_connection_state = PeerConnectionInterface::kIceConnectionNew;
1251 } else if (total_ice_new + total_ice_checking > 0) {
1252 // None of the previous states apply and any RTCIceTransports are in the
1253 // "new" or "checking" state.
1254 new_ice_connection_state = PeerConnectionInterface::kIceConnectionChecking;
1255 } else if (total_ice_completed + total_ice_closed == total_ice ||
1256 all_completed) {
1257 // None of the previous states apply and all RTCIceTransports are in the
1258 // "completed" or "closed" state.
1259 //
1260 // TODO(https://bugs.webrtc.org/10356): The all_completed condition is added
1261 // to mimic the behavior of the old ICE connection state, and should be
1262 // removed once we get end-of-candidates signaling in place.
1263 new_ice_connection_state = PeerConnectionInterface::kIceConnectionCompleted;
1264 } else if (total_ice_connected + total_ice_completed + total_ice_closed ==
1265 total_ice) {
1266 // None of the previous states apply and all RTCIceTransports are in the
1267 // "connected", "completed" or "closed" state.
1268 new_ice_connection_state = PeerConnectionInterface::kIceConnectionConnected;
1269 } else {
1270 RTC_NOTREACHED();
1271 }
1272
1273 if (standardized_ice_connection_state_ != new_ice_connection_state) {
1274 if (standardized_ice_connection_state_ ==
1275 PeerConnectionInterface::kIceConnectionChecking &&
1276 new_ice_connection_state ==
1277 PeerConnectionInterface::kIceConnectionCompleted) {
1278 // Ensure that we never skip over the "connected" state.
1279 signal_standardized_ice_connection_state_.Send(
1280 PeerConnectionInterface::kIceConnectionConnected);
1281 }
1282 standardized_ice_connection_state_ = new_ice_connection_state;
1283 signal_standardized_ice_connection_state_.Send(new_ice_connection_state);
1284 }
1285
1286 // Compute the current RTCPeerConnectionState as described in
1287 // https://www.w3.org/TR/webrtc/#dom-rtcpeerconnectionstate.
1288 // The PeerConnection is responsible for handling the "closed" state.
1289 // Note that "connecting" is only a valid state for DTLS transports while
1290 // "checking", "completed" and "disconnected" are only valid for ICE
1291 // transports.
1292 int total_connected = total_ice_connected +
1293 dtls_state_counts[cricket::DTLS_TRANSPORT_CONNECTED];
1294 int total_dtls_connecting =
1295 dtls_state_counts[cricket::DTLS_TRANSPORT_CONNECTING];
1296 int total_failed =
1297 total_ice_failed + dtls_state_counts[cricket::DTLS_TRANSPORT_FAILED];
1298 int total_closed =
1299 total_ice_closed + dtls_state_counts[cricket::DTLS_TRANSPORT_CLOSED];
1300 int total_new =
1301 total_ice_new + dtls_state_counts[cricket::DTLS_TRANSPORT_NEW];
1302 int total_transports = total_ice * 2;
1303
1304 if (total_failed > 0) {
1305 // Any of the RTCIceTransports or RTCDtlsTransports are in a "failed" state.
1306 new_combined_state = PeerConnectionInterface::PeerConnectionState::kFailed;
1307 } else if (total_ice_disconnected > 0) {
1308 // None of the previous states apply and any RTCIceTransports or
1309 // RTCDtlsTransports are in the "disconnected" state.
1310 new_combined_state =
1311 PeerConnectionInterface::PeerConnectionState::kDisconnected;
1312 } else if (total_new + total_closed == total_transports) {
1313 // None of the previous states apply and all RTCIceTransports and
1314 // RTCDtlsTransports are in the "new" or "closed" state, or there are no
1315 // transports.
1316 new_combined_state = PeerConnectionInterface::PeerConnectionState::kNew;
1317 } else if (total_new + total_dtls_connecting + total_ice_checking > 0) {
1318 // None of the previous states apply and all RTCIceTransports or
1319 // RTCDtlsTransports are in the "new", "connecting" or "checking" state.
1320 new_combined_state =
1321 PeerConnectionInterface::PeerConnectionState::kConnecting;
1322 } else if (total_connected + total_ice_completed + total_closed ==
1323 total_transports) {
1324 // None of the previous states apply and all RTCIceTransports and
1325 // RTCDtlsTransports are in the "connected", "completed" or "closed" state.
1326 new_combined_state =
1327 PeerConnectionInterface::PeerConnectionState::kConnected;
1328 } else {
1329 RTC_NOTREACHED();
1330 }
1331
1332 if (combined_connection_state_ != new_combined_state) {
1333 combined_connection_state_ = new_combined_state;
1334 signal_connection_state_.Send(new_combined_state);
1335 }
1336
1337 // Compute the gathering state.
1338 if (dtls_transports.empty()) {
1339 new_gathering_state = cricket::kIceGatheringNew;
1340 } else if (all_done_gathering) {
1341 new_gathering_state = cricket::kIceGatheringComplete;
1342 } else if (any_gathering) {
1343 new_gathering_state = cricket::kIceGatheringGathering;
1344 }
1345 if (ice_gathering_state_ != new_gathering_state) {
1346 ice_gathering_state_ = new_gathering_state;
1347 signal_ice_gathering_state_.Send(new_gathering_state);
1348 }
1349 }
1350
OnRtcpPacketReceived_n(rtc::CopyOnWriteBuffer * packet,int64_t packet_time_us)1351 void JsepTransportController::OnRtcpPacketReceived_n(
1352 rtc::CopyOnWriteBuffer* packet,
1353 int64_t packet_time_us) {
1354 RTC_DCHECK(config_.rtcp_handler);
1355 config_.rtcp_handler(*packet, packet_time_us);
1356 }
1357
OnDtlsHandshakeError(rtc::SSLHandshakeError error)1358 void JsepTransportController::OnDtlsHandshakeError(
1359 rtc::SSLHandshakeError error) {
1360 config_.on_dtls_handshake_error_(error);
1361 }
1362
1363 } // namespace webrtc
1364