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