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