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