blob: 31d27cae4d6d34f2a1b22907526245443f692684 [file] [log] [blame]
Zhi Huange818b6e2018-02-22 15:26:27 -08001/*
2 * Copyright 2017 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "pc/jseptransportcontroller.h"
12
13#include <algorithm>
14#include <memory>
15#include <utility>
16
17#include "p2p/base/port.h"
18#include "rtc_base/bind.h"
19#include "rtc_base/checks.h"
20#include "rtc_base/ptr_util.h"
21#include "rtc_base/thread.h"
22
23using webrtc::SdpType;
24
25namespace {
26
27enum {
28 MSG_ICECONNECTIONSTATE,
29 MSG_ICEGATHERINGSTATE,
30 MSG_ICECANDIDATESGATHERED,
31};
32
33struct CandidatesData : public rtc::MessageData {
34 CandidatesData(const std::string& transport_name,
35 const cricket::Candidates& candidates)
36 : transport_name(transport_name), candidates(candidates) {}
37
38 std::string transport_name;
39 cricket::Candidates candidates;
40};
41
42webrtc::RTCError VerifyCandidate(const cricket::Candidate& cand) {
43 // No address zero.
44 if (cand.address().IsNil() || cand.address().IsAnyIP()) {
45 return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
46 "candidate has address of zero");
47 }
48
49 // Disallow all ports below 1024, except for 80 and 443 on public addresses.
50 int port = cand.address().port();
51 if (cand.protocol() == cricket::TCP_PROTOCOL_NAME &&
52 (cand.tcptype() == cricket::TCPTYPE_ACTIVE_STR || port == 0)) {
53 // Expected for active-only candidates per
54 // http://tools.ietf.org/html/rfc6544#section-4.5 so no error.
55 // Libjingle clients emit port 0, in "active" mode.
56 return webrtc::RTCError::OK();
57 }
58 if (port < 1024) {
59 if ((port != 80) && (port != 443)) {
60 return webrtc::RTCError(
61 webrtc::RTCErrorType::INVALID_PARAMETER,
62 "candidate has port below 1024, but not 80 or 443");
63 }
64
65 if (cand.address().IsPrivateIP()) {
66 return webrtc::RTCError(
67 webrtc::RTCErrorType::INVALID_PARAMETER,
68 "candidate has port of 80 or 443 with private IP address");
69 }
70 }
71
72 return webrtc::RTCError::OK();
73}
74
75webrtc::RTCError VerifyCandidates(const cricket::Candidates& candidates) {
76 for (const cricket::Candidate& candidate : candidates) {
77 webrtc::RTCError error = VerifyCandidate(candidate);
78 if (!error.ok()) {
79 return error;
80 }
81 }
82 return webrtc::RTCError::OK();
83}
84
85} // namespace
86
87namespace webrtc {
88
89JsepTransportController::JsepTransportController(
90 rtc::Thread* signaling_thread,
91 rtc::Thread* network_thread,
92 cricket::PortAllocator* port_allocator,
93 Config config)
94 : signaling_thread_(signaling_thread),
95 network_thread_(network_thread),
96 port_allocator_(port_allocator),
97 config_(config) {}
98
99JsepTransportController::~JsepTransportController() {
100 // Channel destructors may try to send packets, so this needs to happen on
101 // the network thread.
102 network_thread_->Invoke<void>(
103 RTC_FROM_HERE,
104 rtc::Bind(&JsepTransportController::DestroyAllJsepTransports_n, this));
105}
106
107RTCError JsepTransportController::SetLocalDescription(
108 SdpType type,
109 const cricket::SessionDescription* description) {
110 if (!network_thread_->IsCurrent()) {
111 return network_thread_->Invoke<RTCError>(
112 RTC_FROM_HERE, [=] { return SetLocalDescription(type, description); });
113 }
114
115 if (!initial_offerer_.has_value()) {
116 initial_offerer_.emplace(type == SdpType::kOffer);
117 if (*initial_offerer_) {
118 SetIceRole_n(cricket::ICEROLE_CONTROLLING);
119 } else {
120 SetIceRole_n(cricket::ICEROLE_CONTROLLED);
121 }
122 }
123 return ApplyDescription_n(/*local=*/true, type, description);
124}
125
126RTCError JsepTransportController::SetRemoteDescription(
127 SdpType type,
128 const cricket::SessionDescription* description) {
129 if (!network_thread_->IsCurrent()) {
130 return network_thread_->Invoke<RTCError>(
131 RTC_FROM_HERE, [=] { return SetRemoteDescription(type, description); });
132 }
133
134 return ApplyDescription_n(/*local=*/false, type, description);
135}
136
137RtpTransportInternal* JsepTransportController::GetRtpTransport(
138 const std::string& mid) const {
Zhi Huange830e682018-03-30 10:48:35 -0700139 auto jsep_transport = GetJsepTransportForMid(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -0800140 if (!jsep_transport) {
141 return nullptr;
142 }
143 return jsep_transport->rtp_transport();
144}
145
146cricket::DtlsTransportInternal* JsepTransportController::GetDtlsTransport(
147 const std::string& mid) const {
Zhi Huange830e682018-03-30 10:48:35 -0700148 auto jsep_transport = GetJsepTransportForMid(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -0800149 if (!jsep_transport) {
150 return nullptr;
151 }
152 return jsep_transport->rtp_dtls_transport();
153}
154
155cricket::DtlsTransportInternal* JsepTransportController::GetRtcpDtlsTransport(
156 const std::string& mid) const {
Zhi Huange830e682018-03-30 10:48:35 -0700157 auto jsep_transport = GetJsepTransportForMid(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -0800158 if (!jsep_transport) {
159 return nullptr;
160 }
161 return jsep_transport->rtcp_dtls_transport();
162}
163
164void JsepTransportController::SetIceConfig(const cricket::IceConfig& config) {
165 if (!network_thread_->IsCurrent()) {
166 network_thread_->Invoke<void>(RTC_FROM_HERE, [&] { SetIceConfig(config); });
167 return;
168 }
169
170 ice_config_ = config;
171 for (auto& dtls : GetDtlsTransports()) {
172 dtls->ice_transport()->SetIceConfig(ice_config_);
173 }
174}
175
176void JsepTransportController::SetNeedsIceRestartFlag() {
Zhi Huange830e682018-03-30 10:48:35 -0700177 for (auto& kv : jsep_transports_by_name_) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800178 kv.second->SetNeedsIceRestartFlag();
179 }
180}
181
182bool JsepTransportController::NeedsIceRestart(
183 const std::string& transport_name) const {
Zhi Huange830e682018-03-30 10:48:35 -0700184 const cricket::JsepTransport2* transport =
185 GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800186 if (!transport) {
187 return false;
188 }
189 return transport->needs_ice_restart();
190}
191
192rtc::Optional<rtc::SSLRole> JsepTransportController::GetDtlsRole(
Zhi Huange830e682018-03-30 10:48:35 -0700193 const std::string& mid) const {
Zhi Huange818b6e2018-02-22 15:26:27 -0800194 if (!network_thread_->IsCurrent()) {
195 return network_thread_->Invoke<rtc::Optional<rtc::SSLRole>>(
Zhi Huange830e682018-03-30 10:48:35 -0700196 RTC_FROM_HERE, [&] { return GetDtlsRole(mid); });
Zhi Huange818b6e2018-02-22 15:26:27 -0800197 }
198
Zhi Huange830e682018-03-30 10:48:35 -0700199 const cricket::JsepTransport2* t = GetJsepTransportForMid(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -0800200 if (!t) {
201 return rtc::Optional<rtc::SSLRole>();
202 }
203 return t->GetDtlsRole();
204}
205
206bool JsepTransportController::SetLocalCertificate(
207 const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) {
208 if (!network_thread_->IsCurrent()) {
209 return network_thread_->Invoke<bool>(
210 RTC_FROM_HERE, [&] { return SetLocalCertificate(certificate); });
211 }
212
213 // Can't change a certificate, or set a null certificate.
214 if (certificate_ || !certificate) {
215 return false;
216 }
217 certificate_ = certificate;
218
219 // Set certificate for JsepTransport, which verifies it matches the
220 // fingerprint in SDP, and DTLS transport.
221 // Fallback from DTLS to SDES is not supported.
Zhi Huange830e682018-03-30 10:48:35 -0700222 for (auto& kv : jsep_transports_by_name_) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800223 kv.second->SetLocalCertificate(certificate_);
224 }
225 for (auto& dtls : GetDtlsTransports()) {
226 bool set_cert_success = dtls->SetLocalCertificate(certificate_);
227 RTC_DCHECK(set_cert_success);
228 }
229 return true;
230}
231
232rtc::scoped_refptr<rtc::RTCCertificate>
233JsepTransportController::GetLocalCertificate(
234 const std::string& transport_name) const {
235 if (!network_thread_->IsCurrent()) {
236 return network_thread_->Invoke<rtc::scoped_refptr<rtc::RTCCertificate>>(
237 RTC_FROM_HERE, [&] { return GetLocalCertificate(transport_name); });
238 }
239
Zhi Huange830e682018-03-30 10:48:35 -0700240 const cricket::JsepTransport2* t = GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800241 if (!t) {
242 return nullptr;
243 }
244 return t->GetLocalCertificate();
245}
246
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800247std::unique_ptr<rtc::SSLCertChain>
248JsepTransportController::GetRemoteSSLCertChain(
Zhi Huange818b6e2018-02-22 15:26:27 -0800249 const std::string& transport_name) const {
250 if (!network_thread_->IsCurrent()) {
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800251 return network_thread_->Invoke<std::unique_ptr<rtc::SSLCertChain>>(
252 RTC_FROM_HERE, [&] { return GetRemoteSSLCertChain(transport_name); });
Zhi Huange818b6e2018-02-22 15:26:27 -0800253 }
254
Zhi Huange830e682018-03-30 10:48:35 -0700255 // Get the certificate from the RTP transport's DTLS handshake. Should be
256 // identical to the RTCP transport's, since they were given the same remote
Zhi Huange818b6e2018-02-22 15:26:27 -0800257 // fingerprint.
Zhi Huange830e682018-03-30 10:48:35 -0700258 auto jsep_transport = GetJsepTransportByName(transport_name);
259 if (!jsep_transport) {
260 return nullptr;
261 }
262 auto dtls = jsep_transport->rtp_dtls_transport();
Zhi Huange818b6e2018-02-22 15:26:27 -0800263 if (!dtls) {
264 return nullptr;
265 }
266
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800267 return dtls->GetRemoteSSLCertChain();
Zhi Huange818b6e2018-02-22 15:26:27 -0800268}
269
270void JsepTransportController::MaybeStartGathering() {
271 if (!network_thread_->IsCurrent()) {
272 network_thread_->Invoke<void>(RTC_FROM_HERE,
273 [&] { MaybeStartGathering(); });
274 return;
275 }
276
277 for (auto& dtls : GetDtlsTransports()) {
278 dtls->ice_transport()->MaybeStartGathering();
279 }
280}
281
282RTCError JsepTransportController::AddRemoteCandidates(
283 const std::string& transport_name,
284 const cricket::Candidates& candidates) {
285 if (!network_thread_->IsCurrent()) {
286 return network_thread_->Invoke<RTCError>(RTC_FROM_HERE, [&] {
287 return AddRemoteCandidates(transport_name, candidates);
288 });
289 }
290
291 // Verify each candidate before passing down to the transport layer.
292 RTCError error = VerifyCandidates(candidates);
293 if (!error.ok()) {
294 return error;
295 }
Zhi Huange830e682018-03-30 10:48:35 -0700296 auto jsep_transport = GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800297 if (!jsep_transport) {
Zhi Huange830e682018-03-30 10:48:35 -0700298 RTC_LOG(LS_WARNING) << "Not adding candidate because the JsepTransport "
299 "doesn't exist. Ignore it.";
300 return RTCError::OK();
Zhi Huange818b6e2018-02-22 15:26:27 -0800301 }
Zhi Huange818b6e2018-02-22 15:26:27 -0800302 return jsep_transport->AddRemoteCandidates(candidates);
303}
304
305RTCError JsepTransportController::RemoveRemoteCandidates(
306 const cricket::Candidates& candidates) {
307 if (!network_thread_->IsCurrent()) {
308 return network_thread_->Invoke<RTCError>(
309 RTC_FROM_HERE, [&] { return RemoveRemoteCandidates(candidates); });
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
318 std::map<std::string, cricket::Candidates> candidates_by_transport_name;
319 for (const cricket::Candidate& cand : candidates) {
320 if (!cand.transport_name().empty()) {
321 candidates_by_transport_name[cand.transport_name()].push_back(cand);
322 } else {
323 RTC_LOG(LS_ERROR) << "Not removing candidate because it does not have a "
324 "transport name set: "
325 << cand.ToString();
326 }
327 }
328
329 for (const auto& kv : candidates_by_transport_name) {
330 const std::string& transport_name = kv.first;
331 const cricket::Candidates& candidates = kv.second;
Zhi Huange830e682018-03-30 10:48:35 -0700332 cricket::JsepTransport2* jsep_transport =
333 GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800334 if (!jsep_transport) {
Zhi Huange830e682018-03-30 10:48:35 -0700335 RTC_LOG(LS_WARNING)
336 << "Not removing candidate because the JsepTransport doesn't exist.";
337 continue;
Zhi Huange818b6e2018-02-22 15:26:27 -0800338 }
339 for (const cricket::Candidate& candidate : candidates) {
340 auto dtls = candidate.component() == cricket::ICE_CANDIDATE_COMPONENT_RTP
341 ? jsep_transport->rtp_dtls_transport()
342 : jsep_transport->rtcp_dtls_transport();
343 if (dtls) {
344 dtls->ice_transport()->RemoveRemoteCandidate(candidate);
345 }
346 }
347 }
348 return RTCError::OK();
349}
350
351bool JsepTransportController::GetStats(const std::string& transport_name,
352 cricket::TransportStats* stats) {
353 if (!network_thread_->IsCurrent()) {
354 return network_thread_->Invoke<bool>(
355 RTC_FROM_HERE, [=] { return GetStats(transport_name, stats); });
356 }
357
Zhi Huange830e682018-03-30 10:48:35 -0700358 cricket::JsepTransport2* transport = GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800359 if (!transport) {
360 return false;
361 }
362 return transport->GetStats(stats);
363}
364
365void JsepTransportController::SetMetricsObserver(
366 webrtc::MetricsObserverInterface* metrics_observer) {
367 if (!network_thread_->IsCurrent()) {
368 network_thread_->Invoke<void>(
369 RTC_FROM_HERE, [=] { SetMetricsObserver(metrics_observer); });
370 return;
371 }
372
373 metrics_observer_ = metrics_observer;
374 for (auto& dtls : GetDtlsTransports()) {
375 dtls->ice_transport()->SetMetricsObserver(metrics_observer);
376 }
377}
378
379std::unique_ptr<cricket::DtlsTransportInternal>
380JsepTransportController::CreateDtlsTransport(const std::string& transport_name,
381 bool rtcp) {
382 RTC_DCHECK(network_thread_->IsCurrent());
383 int component = rtcp ? cricket::ICE_CANDIDATE_COMPONENT_RTCP
384 : cricket::ICE_CANDIDATE_COMPONENT_RTP;
385
386 std::unique_ptr<cricket::DtlsTransportInternal> dtls;
387 if (config_.external_transport_factory) {
388 auto ice = config_.external_transport_factory->CreateIceTransport(
389 transport_name, component);
390 dtls = config_.external_transport_factory->CreateDtlsTransport(
391 std::move(ice), config_.crypto_options);
392 } else {
393 auto ice = rtc::MakeUnique<cricket::P2PTransportChannel>(
394 transport_name, component, port_allocator_);
395 dtls = rtc::MakeUnique<cricket::DtlsTransport>(std::move(ice),
396 config_.crypto_options);
397 }
398
399 RTC_DCHECK(dtls);
400 dtls->SetSslMaxProtocolVersion(config_.ssl_max_version);
401 dtls->ice_transport()->SetMetricsObserver(metrics_observer_);
402 dtls->ice_transport()->SetIceRole(ice_role_);
403 dtls->ice_transport()->SetIceTiebreaker(ice_tiebreaker_);
404 dtls->ice_transport()->SetIceConfig(ice_config_);
405 if (certificate_) {
406 bool set_cert_success = dtls->SetLocalCertificate(certificate_);
407 RTC_DCHECK(set_cert_success);
408 }
409
410 // Connect to signals offered by the DTLS and ICE transport.
411 dtls->SignalWritableState.connect(
412 this, &JsepTransportController::OnTransportWritableState_n);
413 dtls->SignalReceivingState.connect(
414 this, &JsepTransportController::OnTransportReceivingState_n);
415 dtls->SignalDtlsHandshakeError.connect(
416 this, &JsepTransportController::OnDtlsHandshakeError);
417 dtls->ice_transport()->SignalGatheringState.connect(
418 this, &JsepTransportController::OnTransportGatheringState_n);
419 dtls->ice_transport()->SignalCandidateGathered.connect(
420 this, &JsepTransportController::OnTransportCandidateGathered_n);
421 dtls->ice_transport()->SignalCandidatesRemoved.connect(
422 this, &JsepTransportController::OnTransportCandidatesRemoved_n);
423 dtls->ice_transport()->SignalRoleConflict.connect(
424 this, &JsepTransportController::OnTransportRoleConflict_n);
425 dtls->ice_transport()->SignalStateChanged.connect(
426 this, &JsepTransportController::OnTransportStateChanged_n);
427 return dtls;
428}
429
430std::unique_ptr<webrtc::RtpTransport>
431JsepTransportController::CreateUnencryptedRtpTransport(
432 const std::string& transport_name,
433 rtc::PacketTransportInternal* rtp_packet_transport,
434 rtc::PacketTransportInternal* rtcp_packet_transport) {
435 RTC_DCHECK(network_thread_->IsCurrent());
Zhi Huange830e682018-03-30 10:48:35 -0700436 auto unencrypted_rtp_transport =
437 rtc::MakeUnique<RtpTransport>(rtcp_packet_transport == nullptr);
438 unencrypted_rtp_transport->SetRtpPacketTransport(rtp_packet_transport);
439 if (rtcp_packet_transport) {
440 unencrypted_rtp_transport->SetRtcpPacketTransport(rtcp_packet_transport);
441 }
442 return unencrypted_rtp_transport;
Zhi Huange818b6e2018-02-22 15:26:27 -0800443}
444
445std::unique_ptr<webrtc::SrtpTransport>
446JsepTransportController::CreateSdesTransport(
447 const std::string& transport_name,
Zhi Huange830e682018-03-30 10:48:35 -0700448 cricket::DtlsTransportInternal* rtp_dtls_transport,
449 cricket::DtlsTransportInternal* rtcp_dtls_transport) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800450 RTC_DCHECK(network_thread_->IsCurrent());
Zhi Huange818b6e2018-02-22 15:26:27 -0800451 auto srtp_transport =
Zhi Huange830e682018-03-30 10:48:35 -0700452 rtc::MakeUnique<webrtc::SrtpTransport>(rtcp_dtls_transport == nullptr);
453 RTC_DCHECK(rtp_dtls_transport);
454 srtp_transport->SetRtpPacketTransport(rtp_dtls_transport);
455 if (rtcp_dtls_transport) {
456 srtp_transport->SetRtcpPacketTransport(rtcp_dtls_transport);
Zhi Huange818b6e2018-02-22 15:26:27 -0800457 }
458 if (config_.enable_external_auth) {
459 srtp_transport->EnableExternalAuth();
460 }
461 return srtp_transport;
462}
463
464std::unique_ptr<webrtc::DtlsSrtpTransport>
465JsepTransportController::CreateDtlsSrtpTransport(
466 const std::string& transport_name,
467 cricket::DtlsTransportInternal* rtp_dtls_transport,
468 cricket::DtlsTransportInternal* rtcp_dtls_transport) {
469 RTC_DCHECK(network_thread_->IsCurrent());
Zhi Huang95e7dbb2018-03-29 00:08:03 +0000470 auto srtp_transport =
Zhi Huange830e682018-03-30 10:48:35 -0700471 rtc::MakeUnique<webrtc::SrtpTransport>(rtcp_dtls_transport == nullptr);
Zhi Huang27f3bf52018-03-26 21:37:23 -0700472 if (config_.enable_external_auth) {
Zhi Huang95e7dbb2018-03-29 00:08:03 +0000473 srtp_transport->EnableExternalAuth();
Zhi Huang27f3bf52018-03-26 21:37:23 -0700474 }
Zhi Huang97d5e5b2018-03-27 00:09:01 +0000475
Zhi Huang95e7dbb2018-03-29 00:08:03 +0000476 auto dtls_srtp_transport =
477 rtc::MakeUnique<webrtc::DtlsSrtpTransport>(std::move(srtp_transport));
478
Zhi Huange818b6e2018-02-22 15:26:27 -0800479 dtls_srtp_transport->SetDtlsTransports(rtp_dtls_transport,
480 rtcp_dtls_transport);
481 return dtls_srtp_transport;
482}
483
484std::vector<cricket::DtlsTransportInternal*>
485JsepTransportController::GetDtlsTransports() {
486 std::vector<cricket::DtlsTransportInternal*> dtls_transports;
Zhi Huange830e682018-03-30 10:48:35 -0700487 for (auto it = jsep_transports_by_name_.begin();
488 it != jsep_transports_by_name_.end(); ++it) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800489 auto jsep_transport = it->second.get();
490 RTC_DCHECK(jsep_transport);
491 if (jsep_transport->rtp_dtls_transport()) {
492 dtls_transports.push_back(jsep_transport->rtp_dtls_transport());
493 }
494
495 if (jsep_transport->rtcp_dtls_transport()) {
496 dtls_transports.push_back(jsep_transport->rtcp_dtls_transport());
497 }
498 }
499 return dtls_transports;
500}
501
502void JsepTransportController::OnMessage(rtc::Message* pmsg) {
503 RTC_DCHECK(signaling_thread_->IsCurrent());
504
505 switch (pmsg->message_id) {
506 case MSG_ICECONNECTIONSTATE: {
507 rtc::TypedMessageData<cricket::IceConnectionState>* data =
508 static_cast<rtc::TypedMessageData<cricket::IceConnectionState>*>(
509 pmsg->pdata);
510 SignalIceConnectionState(data->data());
511 delete data;
512 break;
513 }
514 case MSG_ICEGATHERINGSTATE: {
515 rtc::TypedMessageData<cricket::IceGatheringState>* data =
516 static_cast<rtc::TypedMessageData<cricket::IceGatheringState>*>(
517 pmsg->pdata);
518 SignalIceGatheringState(data->data());
519 delete data;
520 break;
521 }
522 case MSG_ICECANDIDATESGATHERED: {
523 CandidatesData* data = static_cast<CandidatesData*>(pmsg->pdata);
524 SignalIceCandidatesGathered(data->transport_name, data->candidates);
525 delete data;
526 break;
527 }
528 default:
529 RTC_NOTREACHED();
530 }
531}
532
533RTCError JsepTransportController::ApplyDescription_n(
534 bool local,
535 SdpType type,
536 const cricket::SessionDescription* description) {
537 RTC_DCHECK(network_thread_->IsCurrent());
538 RTC_DCHECK(description);
539
540 if (local) {
541 local_desc_ = description;
542 } else {
543 remote_desc_ = description;
544 }
545
Zhi Huange830e682018-03-30 10:48:35 -0700546 RTCError error;
Zhi Huangd2248f82018-04-10 14:41:03 -0700547 error = ValidateAndMaybeUpdateBundleGroup(local, type, description);
Zhi Huange830e682018-03-30 10:48:35 -0700548 if (!error.ok()) {
549 return error;
Zhi Huange818b6e2018-02-22 15:26:27 -0800550 }
551
552 std::vector<int> merged_encrypted_extension_ids;
553 if (bundle_group_) {
554 merged_encrypted_extension_ids =
555 MergeEncryptedHeaderExtensionIdsForBundle(description);
556 }
557
558 for (const cricket::ContentInfo& content_info : description->contents()) {
559 // Don't create transports for rejected m-lines and bundled m-lines."
560 if (content_info.rejected ||
561 (IsBundled(content_info.name) && content_info.name != *bundled_mid())) {
562 continue;
563 }
Zhi Huangd2248f82018-04-10 14:41:03 -0700564 error = MaybeCreateJsepTransport(content_info);
Zhi Huange830e682018-03-30 10:48:35 -0700565 if (!error.ok()) {
566 return error;
567 }
Zhi Huange818b6e2018-02-22 15:26:27 -0800568 }
569
570 RTC_DCHECK(description->contents().size() ==
571 description->transport_infos().size());
572 for (size_t i = 0; i < description->contents().size(); ++i) {
573 const cricket::ContentInfo& content_info = description->contents()[i];
574 const cricket::TransportInfo& transport_info =
575 description->transport_infos()[i];
576 if (content_info.rejected) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700577 HandleRejectedContent(content_info, description);
Zhi Huange818b6e2018-02-22 15:26:27 -0800578 continue;
579 }
580
581 if (IsBundled(content_info.name) && content_info.name != *bundled_mid()) {
582 HandleBundledContent(content_info);
583 continue;
584 }
585
Zhi Huange830e682018-03-30 10:48:35 -0700586 error = ValidateContent(content_info);
587 if (!error.ok()) {
588 return error;
589 }
590
Zhi Huange818b6e2018-02-22 15:26:27 -0800591 std::vector<int> extension_ids;
592 if (bundle_group_ && content_info.name == *bundled_mid()) {
593 extension_ids = merged_encrypted_extension_ids;
594 } else {
595 extension_ids = GetEncryptedHeaderExtensionIds(content_info);
596 }
597
Zhi Huange830e682018-03-30 10:48:35 -0700598 int rtp_abs_sendtime_extn_id =
599 GetRtpAbsSendTimeHeaderExtensionId(content_info);
600
601 cricket::JsepTransport2* transport =
602 GetJsepTransportForMid(content_info.name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800603 RTC_DCHECK(transport);
604
605 SetIceRole_n(DetermineIceRole(transport, transport_info, type, local));
606
Zhi Huange818b6e2018-02-22 15:26:27 -0800607 cricket::JsepTransportDescription jsep_description =
608 CreateJsepTransportDescription(content_info, transport_info,
Zhi Huange830e682018-03-30 10:48:35 -0700609 extension_ids, rtp_abs_sendtime_extn_id);
Zhi Huange818b6e2018-02-22 15:26:27 -0800610 if (local) {
611 error =
612 transport->SetLocalJsepTransportDescription(jsep_description, type);
613 } else {
614 error =
615 transport->SetRemoteJsepTransportDescription(jsep_description, type);
616 }
617
618 if (!error.ok()) {
619 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
620 "Failed to apply the description for " +
621 content_info.name + ": " + error.message());
622 }
623 }
624 return RTCError::OK();
625}
626
Zhi Huangd2248f82018-04-10 14:41:03 -0700627RTCError JsepTransportController::ValidateAndMaybeUpdateBundleGroup(
628 bool local,
629 SdpType type,
Zhi Huange830e682018-03-30 10:48:35 -0700630 const cricket::SessionDescription* description) {
631 RTC_DCHECK(description);
Zhi Huangd2248f82018-04-10 14:41:03 -0700632 const cricket::ContentGroup* new_bundle_group =
633 description->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
634
635 // The BUNDLE group containing a MID that no m= section has is invalid.
636 if (new_bundle_group) {
637 for (auto content_name : new_bundle_group->content_names()) {
638 if (!description->GetContentByName(content_name)) {
639 return RTCError(RTCErrorType::INVALID_PARAMETER,
640 "The BUNDLE group contains MID:" + content_name +
641 " matching no m= section.");
642 }
643 }
644 }
645
646 if (type == SdpType::kAnswer) {
647 const cricket::ContentGroup* offered_bundle_group =
648 local ? remote_desc_->GetGroupByName(cricket::GROUP_TYPE_BUNDLE)
649 : local_desc_->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
650
651 if (new_bundle_group) {
652 // The BUNDLE group in answer should be a subset of offered group.
653 for (auto content_name : new_bundle_group->content_names()) {
654 if (!offered_bundle_group ||
655 !offered_bundle_group->HasContentName(content_name)) {
656 return RTCError(RTCErrorType::INVALID_PARAMETER,
657 "The BUNDLE group in answer contains a MID that was "
658 "not in the offered group.");
659 }
660 }
661 }
662
663 if (bundle_group_) {
664 for (auto content_name : bundle_group_->content_names()) {
665 // An answer that removes m= sections from pre-negotiated BUNDLE group
666 // without rejecting it, is invalid.
667 if (!new_bundle_group ||
668 !new_bundle_group->HasContentName(content_name)) {
669 auto* content_info = description->GetContentByName(content_name);
670 if (!content_info || !content_info->rejected) {
671 return RTCError(RTCErrorType::INVALID_PARAMETER,
672 "Answer cannot remove m= section " + content_name +
673 " from already-established BUNDLE group.");
674 }
675 }
676 }
677 }
678 }
679
680 if (config_.bundle_policy ==
681 PeerConnectionInterface::kBundlePolicyMaxBundle &&
682 !description->HasGroup(cricket::GROUP_TYPE_BUNDLE)) {
683 return RTCError(RTCErrorType::INVALID_PARAMETER,
684 "max-bundle is used but no bundle group found.");
685 }
686
687 if (ShouldUpdateBundleGroup(type, description)) {
688 std::string new_bundled_mid = *(new_bundle_group->FirstContentName());
689 if (bundled_mid() && *bundled_mid() != new_bundled_mid) {
690 return RTCError(RTCErrorType::UNSUPPORTED_OPERATION,
691 "Changing the negotiated BUNDLE-tag is not supported.");
692 }
693
694 bundle_group_ = *new_bundle_group;
695 }
Zhi Huange830e682018-03-30 10:48:35 -0700696
697 if (!bundled_mid()) {
698 return RTCError::OK();
699 }
700
701 auto bundled_content = description->GetContentByName(*bundled_mid());
702 if (!bundled_content) {
703 return RTCError(
704 RTCErrorType::INVALID_PARAMETER,
705 "An m= section associated with the BUNDLE-tag doesn't exist.");
706 }
707
708 // If the |bundled_content| is rejected, other contents in the bundle group
709 // should be rejected.
710 if (bundled_content->rejected) {
711 for (auto content_name : bundle_group_->content_names()) {
712 auto other_content = description->GetContentByName(content_name);
713 if (!other_content->rejected) {
714 return RTCError(
715 RTCErrorType::INVALID_PARAMETER,
716 "The m= section:" + content_name + " should be rejected.");
717 }
718 }
719 }
720
721 return RTCError::OK();
722}
723
724RTCError JsepTransportController::ValidateContent(
725 const cricket::ContentInfo& content_info) {
726 if (config_.rtcp_mux_policy ==
727 PeerConnectionInterface::kRtcpMuxPolicyRequire &&
728 content_info.type == cricket::MediaProtocolType::kRtp &&
729 !content_info.media_description()->rtcp_mux()) {
730 return RTCError(RTCErrorType::INVALID_PARAMETER,
731 "The m= section:" + content_info.name +
732 " is invalid. RTCP-MUX is not "
733 "enabled when it is required.");
734 }
735 return RTCError::OK();
736}
737
Zhi Huange818b6e2018-02-22 15:26:27 -0800738void JsepTransportController::HandleRejectedContent(
Zhi Huangd2248f82018-04-10 14:41:03 -0700739 const cricket::ContentInfo& content_info,
740 const cricket::SessionDescription* description) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800741 // If the content is rejected, let the
742 // BaseChannel/SctpTransport change the RtpTransport/DtlsTransport first,
743 // then destroy the cricket::JsepTransport2.
Zhi Huangd2248f82018-04-10 14:41:03 -0700744 RemoveTransportForMid(content_info.name, content_info.type);
Zhi Huange830e682018-03-30 10:48:35 -0700745 // If the answerer rejects the first content, which other contents are bundled
746 // on, all the other contents in the bundle group will be rejected.
747 if (content_info.name == bundled_mid()) {
748 for (auto content_name : bundle_group_->content_names()) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700749 const cricket::ContentInfo* content_in_group =
750 description->GetContentByName(content_name);
751 RTC_DCHECK(content_in_group);
752 RemoveTransportForMid(content_name, content_in_group->type);
Zhi Huange830e682018-03-30 10:48:35 -0700753 }
754 bundle_group_.reset();
755 } else if (IsBundled(content_info.name)) {
756 // Remove the rejected content from the |bundle_group_|.
Zhi Huange818b6e2018-02-22 15:26:27 -0800757 bundle_group_->RemoveContentName(content_info.name);
Zhi Huange830e682018-03-30 10:48:35 -0700758 // Reset the bundle group if nothing left.
759 if (!bundle_group_->FirstContentName()) {
760 bundle_group_.reset();
761 }
Zhi Huange818b6e2018-02-22 15:26:27 -0800762 }
763 MaybeDestroyJsepTransport(content_info.name);
764}
765
766void JsepTransportController::HandleBundledContent(
767 const cricket::ContentInfo& content_info) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700768 auto jsep_transport = GetJsepTransportByName(*bundled_mid());
769 RTC_DCHECK(jsep_transport);
Zhi Huange818b6e2018-02-22 15:26:27 -0800770 // If the content is bundled, let the
771 // BaseChannel/SctpTransport change the RtpTransport/DtlsTransport first,
772 // then destroy the cricket::JsepTransport2.
Zhi Huangd2248f82018-04-10 14:41:03 -0700773 SetTransportForMid(content_info.name, jsep_transport, content_info.type);
Zhi Huange818b6e2018-02-22 15:26:27 -0800774 MaybeDestroyJsepTransport(content_info.name);
775}
776
Zhi Huangd2248f82018-04-10 14:41:03 -0700777void JsepTransportController::SetTransportForMid(
778 const std::string& mid,
779 cricket::JsepTransport2* jsep_transport,
780 cricket::MediaProtocolType protocol_type) {
781 if (mid_to_transport_[mid] == jsep_transport) {
782 return;
783 }
784
785 mid_to_transport_[mid] = jsep_transport;
786 if (protocol_type == cricket::MediaProtocolType::kRtp) {
787 SignalRtpTransportChanged(mid, jsep_transport->rtp_transport());
788 } else {
789 SignalDtlsTransportChanged(mid, jsep_transport->rtp_dtls_transport());
790 }
791}
792
793void JsepTransportController::RemoveTransportForMid(
794 const std::string& mid,
795 cricket::MediaProtocolType protocol_type) {
796 if (protocol_type == cricket::MediaProtocolType::kRtp) {
797 SignalRtpTransportChanged(mid, nullptr);
798 } else {
799 SignalDtlsTransportChanged(mid, nullptr);
800 }
801 mid_to_transport_.erase(mid);
802}
803
Zhi Huange818b6e2018-02-22 15:26:27 -0800804cricket::JsepTransportDescription
805JsepTransportController::CreateJsepTransportDescription(
806 cricket::ContentInfo content_info,
807 cricket::TransportInfo transport_info,
Zhi Huange830e682018-03-30 10:48:35 -0700808 const std::vector<int>& encrypted_extension_ids,
809 int rtp_abs_sendtime_extn_id) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800810 const cricket::MediaContentDescription* content_desc =
811 static_cast<const cricket::MediaContentDescription*>(
812 content_info.description);
813 RTC_DCHECK(content_desc);
814 bool rtcp_mux_enabled = content_info.type == cricket::MediaProtocolType::kSctp
815 ? true
816 : content_desc->rtcp_mux();
817
818 return cricket::JsepTransportDescription(
819 rtcp_mux_enabled, content_desc->cryptos(), encrypted_extension_ids,
Zhi Huange830e682018-03-30 10:48:35 -0700820 rtp_abs_sendtime_extn_id, transport_info.description);
Zhi Huange818b6e2018-02-22 15:26:27 -0800821}
822
823bool JsepTransportController::ShouldUpdateBundleGroup(
824 SdpType type,
825 const cricket::SessionDescription* description) {
826 if (config_.bundle_policy ==
827 PeerConnectionInterface::kBundlePolicyMaxBundle) {
828 return true;
829 }
830
831 if (type != SdpType::kAnswer) {
832 return false;
833 }
834
835 RTC_DCHECK(local_desc_ && remote_desc_);
836 const cricket::ContentGroup* local_bundle =
837 local_desc_->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
838 const cricket::ContentGroup* remote_bundle =
839 remote_desc_->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
840 return local_bundle && remote_bundle;
841}
842
843std::vector<int> JsepTransportController::GetEncryptedHeaderExtensionIds(
844 const cricket::ContentInfo& content_info) {
845 const cricket::MediaContentDescription* content_desc =
846 static_cast<const cricket::MediaContentDescription*>(
847 content_info.description);
848
849 if (!config_.crypto_options.enable_encrypted_rtp_header_extensions) {
850 return std::vector<int>();
851 }
852
853 std::vector<int> encrypted_header_extension_ids;
854 for (auto extension : content_desc->rtp_header_extensions()) {
855 if (!extension.encrypt) {
856 continue;
857 }
858 auto it = std::find(encrypted_header_extension_ids.begin(),
859 encrypted_header_extension_ids.end(), extension.id);
860 if (it == encrypted_header_extension_ids.end()) {
861 encrypted_header_extension_ids.push_back(extension.id);
862 }
863 }
864 return encrypted_header_extension_ids;
865}
866
867std::vector<int>
868JsepTransportController::MergeEncryptedHeaderExtensionIdsForBundle(
869 const cricket::SessionDescription* description) {
870 RTC_DCHECK(description);
871 RTC_DCHECK(bundle_group_);
872
873 std::vector<int> merged_ids;
874 // Union the encrypted header IDs in the group when bundle is enabled.
875 for (const cricket::ContentInfo& content_info : description->contents()) {
876 if (bundle_group_->HasContentName(content_info.name)) {
877 std::vector<int> extension_ids =
878 GetEncryptedHeaderExtensionIds(content_info);
879 for (int id : extension_ids) {
880 auto it = std::find(merged_ids.begin(), merged_ids.end(), id);
881 if (it == merged_ids.end()) {
882 merged_ids.push_back(id);
883 }
884 }
885 }
886 }
887 return merged_ids;
888}
889
Zhi Huange830e682018-03-30 10:48:35 -0700890int JsepTransportController::GetRtpAbsSendTimeHeaderExtensionId(
Zhi Huange818b6e2018-02-22 15:26:27 -0800891 const cricket::ContentInfo& content_info) {
Zhi Huange830e682018-03-30 10:48:35 -0700892 if (!config_.enable_external_auth) {
893 return -1;
Zhi Huange818b6e2018-02-22 15:26:27 -0800894 }
895
896 const cricket::MediaContentDescription* content_desc =
897 static_cast<const cricket::MediaContentDescription*>(
898 content_info.description);
Zhi Huange830e682018-03-30 10:48:35 -0700899
900 const webrtc::RtpExtension* send_time_extension =
901 webrtc::RtpExtension::FindHeaderExtensionByUri(
902 content_desc->rtp_header_extensions(),
903 webrtc::RtpExtension::kAbsSendTimeUri);
904 return send_time_extension ? send_time_extension->id : -1;
905}
906
907const cricket::JsepTransport2* JsepTransportController::GetJsepTransportForMid(
908 const std::string& mid) const {
Zhi Huangd2248f82018-04-10 14:41:03 -0700909 auto it = mid_to_transport_.find(mid);
910 return it == mid_to_transport_.end() ? nullptr : it->second;
Zhi Huange830e682018-03-30 10:48:35 -0700911}
912
913cricket::JsepTransport2* JsepTransportController::GetJsepTransportForMid(
914 const std::string& mid) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700915 auto it = mid_to_transport_.find(mid);
916 return it == mid_to_transport_.end() ? nullptr : it->second;
Zhi Huange830e682018-03-30 10:48:35 -0700917}
918
919const cricket::JsepTransport2* JsepTransportController::GetJsepTransportByName(
920 const std::string& transport_name) const {
921 auto it = jsep_transports_by_name_.find(transport_name);
922 return (it == jsep_transports_by_name_.end()) ? nullptr : it->second.get();
923}
924
925cricket::JsepTransport2* JsepTransportController::GetJsepTransportByName(
926 const std::string& transport_name) {
927 auto it = jsep_transports_by_name_.find(transport_name);
928 return (it == jsep_transports_by_name_.end()) ? nullptr : it->second.get();
929}
930
931RTCError JsepTransportController::MaybeCreateJsepTransport(
Zhi Huange830e682018-03-30 10:48:35 -0700932 const cricket::ContentInfo& content_info) {
933 RTC_DCHECK(network_thread_->IsCurrent());
Zhi Huangd2248f82018-04-10 14:41:03 -0700934 cricket::JsepTransport2* transport =
935 GetJsepTransportByName(content_info.name);
Zhi Huange830e682018-03-30 10:48:35 -0700936 if (transport) {
937 return RTCError::OK();
938 }
939
940 const cricket::MediaContentDescription* content_desc =
941 static_cast<const cricket::MediaContentDescription*>(
942 content_info.description);
943 if (certificate_ && !content_desc->cryptos().empty()) {
944 return RTCError(RTCErrorType::INVALID_PARAMETER,
945 "SDES and DTLS-SRTP cannot be enabled at the same time.");
946 }
947
Zhi Huange818b6e2018-02-22 15:26:27 -0800948 std::unique_ptr<cricket::DtlsTransportInternal> rtp_dtls_transport =
Zhi Huangd2248f82018-04-10 14:41:03 -0700949 CreateDtlsTransport(content_info.name, /*rtcp =*/false);
Zhi Huange818b6e2018-02-22 15:26:27 -0800950 std::unique_ptr<cricket::DtlsTransportInternal> rtcp_dtls_transport;
Zhi Huange830e682018-03-30 10:48:35 -0700951 if (config_.rtcp_mux_policy !=
952 PeerConnectionInterface::kRtcpMuxPolicyRequire &&
953 content_info.type == cricket::MediaProtocolType::kRtp) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700954 rtcp_dtls_transport =
955 CreateDtlsTransport(content_info.name, /*rtcp =*/true);
Zhi Huange818b6e2018-02-22 15:26:27 -0800956 }
957
958 std::unique_ptr<RtpTransport> unencrypted_rtp_transport;
959 std::unique_ptr<SrtpTransport> sdes_transport;
960 std::unique_ptr<DtlsSrtpTransport> dtls_srtp_transport;
961 if (config_.disable_encryption) {
962 unencrypted_rtp_transport = CreateUnencryptedRtpTransport(
Zhi Huangd2248f82018-04-10 14:41:03 -0700963 content_info.name, rtp_dtls_transport.get(), rtcp_dtls_transport.get());
Zhi Huange818b6e2018-02-22 15:26:27 -0800964 } else if (!content_desc->cryptos().empty()) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700965 sdes_transport = CreateSdesTransport(
966 content_info.name, rtp_dtls_transport.get(), rtcp_dtls_transport.get());
Zhi Huange818b6e2018-02-22 15:26:27 -0800967 } else {
Zhi Huangd2248f82018-04-10 14:41:03 -0700968 dtls_srtp_transport = CreateDtlsSrtpTransport(
969 content_info.name, rtp_dtls_transport.get(), rtcp_dtls_transport.get());
Zhi Huange818b6e2018-02-22 15:26:27 -0800970 }
971
972 std::unique_ptr<cricket::JsepTransport2> jsep_transport =
973 rtc::MakeUnique<cricket::JsepTransport2>(
Zhi Huangd2248f82018-04-10 14:41:03 -0700974 content_info.name, certificate_, std::move(unencrypted_rtp_transport),
Zhi Huange818b6e2018-02-22 15:26:27 -0800975 std::move(sdes_transport), std::move(dtls_srtp_transport),
976 std::move(rtp_dtls_transport), std::move(rtcp_dtls_transport));
977 jsep_transport->SignalRtcpMuxActive.connect(
978 this, &JsepTransportController::UpdateAggregateStates_n);
Zhi Huangd2248f82018-04-10 14:41:03 -0700979 SetTransportForMid(content_info.name, jsep_transport.get(),
980 content_info.type);
Zhi Huange830e682018-03-30 10:48:35 -0700981
Zhi Huangd2248f82018-04-10 14:41:03 -0700982 jsep_transports_by_name_[content_info.name] = std::move(jsep_transport);
983 UpdateAggregateStates_n();
Zhi Huange830e682018-03-30 10:48:35 -0700984 return RTCError::OK();
Zhi Huange818b6e2018-02-22 15:26:27 -0800985}
986
987void JsepTransportController::MaybeDestroyJsepTransport(
988 const std::string& mid) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700989 auto jsep_transport = GetJsepTransportByName(mid);
990 if (!jsep_transport) {
991 return;
992 }
993
994 // Don't destroy the JsepTransport if there are still media sections referring
995 // to it.
996 for (const auto& kv : mid_to_transport_) {
997 if (kv.second == jsep_transport) {
998 return;
999 }
1000 }
Zhi Huange830e682018-03-30 10:48:35 -07001001 jsep_transports_by_name_.erase(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -08001002 UpdateAggregateStates_n();
1003}
1004
1005void JsepTransportController::DestroyAllJsepTransports_n() {
1006 RTC_DCHECK(network_thread_->IsCurrent());
Zhi Huange830e682018-03-30 10:48:35 -07001007 jsep_transports_by_name_.clear();
Zhi Huange818b6e2018-02-22 15:26:27 -08001008}
1009
1010void JsepTransportController::SetIceRole_n(cricket::IceRole ice_role) {
1011 RTC_DCHECK(network_thread_->IsCurrent());
1012
1013 ice_role_ = ice_role;
1014 for (auto& dtls : GetDtlsTransports()) {
1015 dtls->ice_transport()->SetIceRole(ice_role_);
1016 }
1017}
1018
1019cricket::IceRole JsepTransportController::DetermineIceRole(
1020 cricket::JsepTransport2* jsep_transport,
1021 const cricket::TransportInfo& transport_info,
1022 SdpType type,
1023 bool local) {
1024 cricket::IceRole ice_role = ice_role_;
1025 auto tdesc = transport_info.description;
1026 if (local) {
1027 // The initial offer side may use ICE Lite, in which case, per RFC5245
1028 // Section 5.1.1, the answer side should take the controlling role if it is
1029 // in the full ICE mode.
1030 //
1031 // When both sides use ICE Lite, the initial offer side must take the
1032 // controlling role, and this is the default logic implemented in
1033 // SetLocalDescription in JsepTransportController.
1034 if (jsep_transport->remote_description() &&
1035 jsep_transport->remote_description()->transport_desc.ice_mode ==
1036 cricket::ICEMODE_LITE &&
1037 ice_role_ == cricket::ICEROLE_CONTROLLED &&
1038 tdesc.ice_mode == cricket::ICEMODE_FULL) {
1039 ice_role = cricket::ICEROLE_CONTROLLING;
1040 }
1041
1042 // Older versions of Chrome expect the ICE role to be re-determined when an
1043 // ICE restart occurs, and also don't perform conflict resolution correctly,
1044 // so for now we can't safely stop doing this, unless the application opts
1045 // in by setting |config_.redetermine_role_on_ice_restart_| to false. See:
1046 // https://bugs.chromium.org/p/chromium/issues/detail?id=628676
1047 // TODO(deadbeef): Remove this when these old versions of Chrome reach a low
1048 // enough population.
1049 if (config_.redetermine_role_on_ice_restart &&
1050 jsep_transport->local_description() &&
1051 cricket::IceCredentialsChanged(
1052 jsep_transport->local_description()->transport_desc.ice_ufrag,
1053 jsep_transport->local_description()->transport_desc.ice_pwd,
1054 tdesc.ice_ufrag, tdesc.ice_pwd) &&
1055 // Don't change the ICE role if the remote endpoint is ICE lite; we
1056 // should always be controlling in that case.
1057 (!jsep_transport->remote_description() ||
1058 jsep_transport->remote_description()->transport_desc.ice_mode !=
1059 cricket::ICEMODE_LITE)) {
1060 ice_role = (type == SdpType::kOffer) ? cricket::ICEROLE_CONTROLLING
1061 : cricket::ICEROLE_CONTROLLED;
1062 }
1063 } else {
1064 // If our role is cricket::ICEROLE_CONTROLLED and the remote endpoint
1065 // supports only ice_lite, this local endpoint should take the CONTROLLING
1066 // role.
1067 // TODO(deadbeef): This is a session-level attribute, so it really shouldn't
1068 // be in a TransportDescription in the first place...
1069 if (ice_role_ == cricket::ICEROLE_CONTROLLED &&
1070 tdesc.ice_mode == cricket::ICEMODE_LITE) {
1071 ice_role = cricket::ICEROLE_CONTROLLING;
1072 }
1073
1074 // If we use ICE Lite and the remote endpoint uses the full implementation
1075 // of ICE, the local endpoint must take the controlled role, and the other
1076 // side must be the controlling role.
1077 if (jsep_transport->local_description() &&
1078 jsep_transport->local_description()->transport_desc.ice_mode ==
1079 cricket::ICEMODE_LITE &&
1080 ice_role_ == cricket::ICEROLE_CONTROLLING &&
Zhi Huange830e682018-03-30 10:48:35 -07001081 tdesc.ice_mode == cricket::ICEMODE_FULL) {
Zhi Huange818b6e2018-02-22 15:26:27 -08001082 ice_role = cricket::ICEROLE_CONTROLLED;
1083 }
1084 }
1085
1086 return ice_role;
1087}
1088
1089void JsepTransportController::OnTransportWritableState_n(
1090 rtc::PacketTransportInternal* transport) {
1091 RTC_DCHECK(network_thread_->IsCurrent());
1092 RTC_LOG(LS_INFO) << " Transport " << transport->transport_name()
1093 << " writability changed to " << transport->writable()
1094 << ".";
1095 UpdateAggregateStates_n();
1096}
1097
1098void JsepTransportController::OnTransportReceivingState_n(
1099 rtc::PacketTransportInternal* transport) {
1100 RTC_DCHECK(network_thread_->IsCurrent());
1101 UpdateAggregateStates_n();
1102}
1103
1104void JsepTransportController::OnTransportGatheringState_n(
1105 cricket::IceTransportInternal* transport) {
1106 RTC_DCHECK(network_thread_->IsCurrent());
1107 UpdateAggregateStates_n();
1108}
1109
1110void JsepTransportController::OnTransportCandidateGathered_n(
1111 cricket::IceTransportInternal* transport,
1112 const cricket::Candidate& candidate) {
1113 RTC_DCHECK(network_thread_->IsCurrent());
1114
1115 // We should never signal peer-reflexive candidates.
1116 if (candidate.type() == cricket::PRFLX_PORT_TYPE) {
1117 RTC_NOTREACHED();
1118 return;
1119 }
1120 std::vector<cricket::Candidate> candidates;
1121 candidates.push_back(candidate);
1122 CandidatesData* data =
1123 new CandidatesData(transport->transport_name(), candidates);
1124 signaling_thread_->Post(RTC_FROM_HERE, this, MSG_ICECANDIDATESGATHERED, data);
1125}
1126
1127void JsepTransportController::OnTransportCandidatesRemoved_n(
1128 cricket::IceTransportInternal* transport,
1129 const cricket::Candidates& candidates) {
1130 invoker_.AsyncInvoke<void>(
1131 RTC_FROM_HERE, signaling_thread_,
1132 rtc::Bind(&JsepTransportController::OnTransportCandidatesRemoved, this,
1133 candidates));
1134}
1135
1136void JsepTransportController::OnTransportCandidatesRemoved(
1137 const cricket::Candidates& candidates) {
1138 RTC_DCHECK(signaling_thread_->IsCurrent());
1139 SignalIceCandidatesRemoved(candidates);
1140}
1141
1142void JsepTransportController::OnTransportRoleConflict_n(
1143 cricket::IceTransportInternal* transport) {
1144 RTC_DCHECK(network_thread_->IsCurrent());
1145 // Note: since the role conflict is handled entirely on the network thread,
1146 // we don't need to worry about role conflicts occurring on two ports at
1147 // once. The first one encountered should immediately reverse the role.
1148 cricket::IceRole reversed_role = (ice_role_ == cricket::ICEROLE_CONTROLLING)
1149 ? cricket::ICEROLE_CONTROLLED
1150 : cricket::ICEROLE_CONTROLLING;
1151 RTC_LOG(LS_INFO) << "Got role conflict; switching to "
1152 << (reversed_role == cricket::ICEROLE_CONTROLLING
1153 ? "controlling"
1154 : "controlled")
1155 << " role.";
1156 SetIceRole_n(reversed_role);
1157}
1158
1159void JsepTransportController::OnTransportStateChanged_n(
1160 cricket::IceTransportInternal* transport) {
1161 RTC_DCHECK(network_thread_->IsCurrent());
1162 RTC_LOG(LS_INFO) << transport->transport_name() << " Transport "
1163 << transport->component()
1164 << " state changed. Check if state is complete.";
1165 UpdateAggregateStates_n();
1166}
1167
1168void JsepTransportController::UpdateAggregateStates_n() {
1169 RTC_DCHECK(network_thread_->IsCurrent());
1170
1171 auto dtls_transports = GetDtlsTransports();
1172 cricket::IceConnectionState new_connection_state =
1173 cricket::kIceConnectionConnecting;
1174 cricket::IceGatheringState new_gathering_state = cricket::kIceGatheringNew;
1175 bool any_failed = false;
1176 bool all_connected = !dtls_transports.empty();
1177 bool all_completed = !dtls_transports.empty();
1178 bool any_gathering = false;
1179 bool all_done_gathering = !dtls_transports.empty();
1180 for (const auto& dtls : dtls_transports) {
1181 any_failed = any_failed || dtls->ice_transport()->GetState() ==
1182 cricket::IceTransportState::STATE_FAILED;
1183 all_connected = all_connected && dtls->writable();
1184 all_completed =
1185 all_completed && dtls->writable() &&
1186 dtls->ice_transport()->GetState() ==
1187 cricket::IceTransportState::STATE_COMPLETED &&
1188 dtls->ice_transport()->GetIceRole() == cricket::ICEROLE_CONTROLLING &&
1189 dtls->ice_transport()->gathering_state() ==
1190 cricket::kIceGatheringComplete;
1191 any_gathering = any_gathering || dtls->ice_transport()->gathering_state() !=
1192 cricket::kIceGatheringNew;
1193 all_done_gathering =
1194 all_done_gathering && dtls->ice_transport()->gathering_state() ==
1195 cricket::kIceGatheringComplete;
1196 }
1197 if (any_failed) {
1198 new_connection_state = cricket::kIceConnectionFailed;
1199 } else if (all_completed) {
1200 new_connection_state = cricket::kIceConnectionCompleted;
1201 } else if (all_connected) {
1202 new_connection_state = cricket::kIceConnectionConnected;
1203 }
1204 if (ice_connection_state_ != new_connection_state) {
1205 ice_connection_state_ = new_connection_state;
1206 signaling_thread_->Post(
1207 RTC_FROM_HERE, this, MSG_ICECONNECTIONSTATE,
1208 new rtc::TypedMessageData<cricket::IceConnectionState>(
1209 new_connection_state));
1210 }
1211
1212 if (all_done_gathering) {
1213 new_gathering_state = cricket::kIceGatheringComplete;
1214 } else if (any_gathering) {
1215 new_gathering_state = cricket::kIceGatheringGathering;
1216 }
1217 if (ice_gathering_state_ != new_gathering_state) {
1218 ice_gathering_state_ = new_gathering_state;
1219 signaling_thread_->Post(
1220 RTC_FROM_HERE, this, MSG_ICEGATHERINGSTATE,
1221 new rtc::TypedMessageData<cricket::IceGatheringState>(
1222 new_gathering_state));
1223 }
1224}
1225
1226void JsepTransportController::OnDtlsHandshakeError(
1227 rtc::SSLHandshakeError error) {
1228 SignalDtlsHandshakeError(error);
1229}
1230
1231} // namespace webrtc