blob: 19a2d402752fd936dd0d8d8ca06f8ef21cc5ad3e [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"
Zhi Huange818b6e2018-02-22 15:26:27 -080020#include "rtc_base/thread.h"
21
22using webrtc::SdpType;
23
24namespace {
25
Zhi Huange818b6e2018-02-22 15:26:27 -080026webrtc::RTCError VerifyCandidate(const cricket::Candidate& cand) {
27 // No address zero.
28 if (cand.address().IsNil() || cand.address().IsAnyIP()) {
29 return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
30 "candidate has address of zero");
31 }
32
33 // Disallow all ports below 1024, except for 80 and 443 on public addresses.
34 int port = cand.address().port();
35 if (cand.protocol() == cricket::TCP_PROTOCOL_NAME &&
36 (cand.tcptype() == cricket::TCPTYPE_ACTIVE_STR || port == 0)) {
37 // Expected for active-only candidates per
38 // http://tools.ietf.org/html/rfc6544#section-4.5 so no error.
39 // Libjingle clients emit port 0, in "active" mode.
40 return webrtc::RTCError::OK();
41 }
42 if (port < 1024) {
43 if ((port != 80) && (port != 443)) {
44 return webrtc::RTCError(
45 webrtc::RTCErrorType::INVALID_PARAMETER,
46 "candidate has port below 1024, but not 80 or 443");
47 }
48
49 if (cand.address().IsPrivateIP()) {
50 return webrtc::RTCError(
51 webrtc::RTCErrorType::INVALID_PARAMETER,
52 "candidate has port of 80 or 443 with private IP address");
53 }
54 }
55
56 return webrtc::RTCError::OK();
57}
58
59webrtc::RTCError VerifyCandidates(const cricket::Candidates& candidates) {
60 for (const cricket::Candidate& candidate : candidates) {
61 webrtc::RTCError error = VerifyCandidate(candidate);
62 if (!error.ok()) {
63 return error;
64 }
65 }
66 return webrtc::RTCError::OK();
67}
68
69} // namespace
70
71namespace webrtc {
72
73JsepTransportController::JsepTransportController(
74 rtc::Thread* signaling_thread,
75 rtc::Thread* network_thread,
76 cricket::PortAllocator* port_allocator,
Zach Steine20867f2018-08-02 13:20:15 -070077 AsyncResolverFactory* async_resolver_factory,
Zhi Huange818b6e2018-02-22 15:26:27 -080078 Config config)
79 : signaling_thread_(signaling_thread),
80 network_thread_(network_thread),
81 port_allocator_(port_allocator),
Zach Steine20867f2018-08-02 13:20:15 -070082 async_resolver_factory_(async_resolver_factory),
Zhi Huang365381f2018-04-13 16:44:34 -070083 config_(config) {
84 // The |transport_observer| is assumed to be non-null.
85 RTC_DCHECK(config_.transport_observer);
86}
Zhi Huange818b6e2018-02-22 15:26:27 -080087
88JsepTransportController::~JsepTransportController() {
89 // Channel destructors may try to send packets, so this needs to happen on
90 // the network thread.
91 network_thread_->Invoke<void>(
92 RTC_FROM_HERE,
93 rtc::Bind(&JsepTransportController::DestroyAllJsepTransports_n, this));
94}
95
96RTCError JsepTransportController::SetLocalDescription(
97 SdpType type,
98 const cricket::SessionDescription* description) {
99 if (!network_thread_->IsCurrent()) {
100 return network_thread_->Invoke<RTCError>(
101 RTC_FROM_HERE, [=] { return SetLocalDescription(type, description); });
102 }
103
104 if (!initial_offerer_.has_value()) {
105 initial_offerer_.emplace(type == SdpType::kOffer);
106 if (*initial_offerer_) {
107 SetIceRole_n(cricket::ICEROLE_CONTROLLING);
108 } else {
109 SetIceRole_n(cricket::ICEROLE_CONTROLLED);
110 }
111 }
112 return ApplyDescription_n(/*local=*/true, type, description);
113}
114
115RTCError JsepTransportController::SetRemoteDescription(
116 SdpType type,
117 const cricket::SessionDescription* description) {
118 if (!network_thread_->IsCurrent()) {
119 return network_thread_->Invoke<RTCError>(
120 RTC_FROM_HERE, [=] { return SetRemoteDescription(type, description); });
121 }
122
123 return ApplyDescription_n(/*local=*/false, type, description);
124}
125
126RtpTransportInternal* JsepTransportController::GetRtpTransport(
127 const std::string& mid) const {
Zhi Huange830e682018-03-30 10:48:35 -0700128 auto jsep_transport = GetJsepTransportForMid(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -0800129 if (!jsep_transport) {
130 return nullptr;
131 }
132 return jsep_transport->rtp_transport();
133}
134
Anton Sukhanov7940da02018-10-10 10:34:49 -0700135MediaTransportInterface* JsepTransportController::GetMediaTransport(
136 const std::string& mid) const {
137 auto jsep_transport = GetJsepTransportForMid(mid);
138 if (!jsep_transport) {
139 return nullptr;
140 }
141 return jsep_transport->media_transport();
142}
143
Zhi Huange818b6e2018-02-22 15:26:27 -0800144cricket::DtlsTransportInternal* JsepTransportController::GetDtlsTransport(
145 const std::string& mid) const {
Zhi Huange830e682018-03-30 10:48:35 -0700146 auto jsep_transport = GetJsepTransportForMid(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -0800147 if (!jsep_transport) {
148 return nullptr;
149 }
150 return jsep_transport->rtp_dtls_transport();
151}
152
153cricket::DtlsTransportInternal* JsepTransportController::GetRtcpDtlsTransport(
154 const std::string& mid) const {
Zhi Huange830e682018-03-30 10:48:35 -0700155 auto jsep_transport = GetJsepTransportForMid(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -0800156 if (!jsep_transport) {
157 return nullptr;
158 }
159 return jsep_transport->rtcp_dtls_transport();
160}
161
162void JsepTransportController::SetIceConfig(const cricket::IceConfig& config) {
163 if (!network_thread_->IsCurrent()) {
164 network_thread_->Invoke<void>(RTC_FROM_HERE, [&] { SetIceConfig(config); });
165 return;
166 }
167
168 ice_config_ = config;
169 for (auto& dtls : GetDtlsTransports()) {
170 dtls->ice_transport()->SetIceConfig(ice_config_);
171 }
172}
173
174void JsepTransportController::SetNeedsIceRestartFlag() {
Zhi Huange830e682018-03-30 10:48:35 -0700175 for (auto& kv : jsep_transports_by_name_) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800176 kv.second->SetNeedsIceRestartFlag();
177 }
178}
179
180bool JsepTransportController::NeedsIceRestart(
181 const std::string& transport_name) const {
Zhi Huang365381f2018-04-13 16:44:34 -0700182 const cricket::JsepTransport* transport =
Zhi Huange830e682018-03-30 10:48:35 -0700183 GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800184 if (!transport) {
185 return false;
186 }
187 return transport->needs_ice_restart();
188}
189
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200190absl::optional<rtc::SSLRole> JsepTransportController::GetDtlsRole(
Zhi Huange830e682018-03-30 10:48:35 -0700191 const std::string& mid) const {
Zhi Huange818b6e2018-02-22 15:26:27 -0800192 if (!network_thread_->IsCurrent()) {
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200193 return network_thread_->Invoke<absl::optional<rtc::SSLRole>>(
Zhi Huange830e682018-03-30 10:48:35 -0700194 RTC_FROM_HERE, [&] { return GetDtlsRole(mid); });
Zhi Huange818b6e2018-02-22 15:26:27 -0800195 }
196
Zhi Huang365381f2018-04-13 16:44:34 -0700197 const cricket::JsepTransport* t = GetJsepTransportForMid(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -0800198 if (!t) {
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200199 return absl::optional<rtc::SSLRole>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800200 }
201 return t->GetDtlsRole();
202}
203
204bool JsepTransportController::SetLocalCertificate(
205 const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) {
206 if (!network_thread_->IsCurrent()) {
207 return network_thread_->Invoke<bool>(
208 RTC_FROM_HERE, [&] { return SetLocalCertificate(certificate); });
209 }
210
211 // Can't change a certificate, or set a null certificate.
212 if (certificate_ || !certificate) {
213 return false;
214 }
215 certificate_ = certificate;
216
217 // Set certificate for JsepTransport, which verifies it matches the
218 // fingerprint in SDP, and DTLS transport.
219 // Fallback from DTLS to SDES is not supported.
Zhi Huange830e682018-03-30 10:48:35 -0700220 for (auto& kv : jsep_transports_by_name_) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800221 kv.second->SetLocalCertificate(certificate_);
222 }
223 for (auto& dtls : GetDtlsTransports()) {
224 bool set_cert_success = dtls->SetLocalCertificate(certificate_);
225 RTC_DCHECK(set_cert_success);
226 }
227 return true;
228}
229
230rtc::scoped_refptr<rtc::RTCCertificate>
231JsepTransportController::GetLocalCertificate(
232 const std::string& transport_name) const {
233 if (!network_thread_->IsCurrent()) {
234 return network_thread_->Invoke<rtc::scoped_refptr<rtc::RTCCertificate>>(
235 RTC_FROM_HERE, [&] { return GetLocalCertificate(transport_name); });
236 }
237
Zhi Huang365381f2018-04-13 16:44:34 -0700238 const cricket::JsepTransport* t = GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800239 if (!t) {
240 return nullptr;
241 }
242 return t->GetLocalCertificate();
243}
244
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800245std::unique_ptr<rtc::SSLCertChain>
246JsepTransportController::GetRemoteSSLCertChain(
Zhi Huange818b6e2018-02-22 15:26:27 -0800247 const std::string& transport_name) const {
248 if (!network_thread_->IsCurrent()) {
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800249 return network_thread_->Invoke<std::unique_ptr<rtc::SSLCertChain>>(
250 RTC_FROM_HERE, [&] { return GetRemoteSSLCertChain(transport_name); });
Zhi Huange818b6e2018-02-22 15:26:27 -0800251 }
252
Zhi Huange830e682018-03-30 10:48:35 -0700253 // Get the certificate from the RTP transport's DTLS handshake. Should be
254 // identical to the RTCP transport's, since they were given the same remote
Zhi Huange818b6e2018-02-22 15:26:27 -0800255 // fingerprint.
Zhi Huange830e682018-03-30 10:48:35 -0700256 auto jsep_transport = GetJsepTransportByName(transport_name);
257 if (!jsep_transport) {
258 return nullptr;
259 }
260 auto dtls = jsep_transport->rtp_dtls_transport();
Zhi Huange818b6e2018-02-22 15:26:27 -0800261 if (!dtls) {
262 return nullptr;
263 }
264
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800265 return dtls->GetRemoteSSLCertChain();
Zhi Huange818b6e2018-02-22 15:26:27 -0800266}
267
268void JsepTransportController::MaybeStartGathering() {
269 if (!network_thread_->IsCurrent()) {
270 network_thread_->Invoke<void>(RTC_FROM_HERE,
271 [&] { MaybeStartGathering(); });
272 return;
273 }
274
275 for (auto& dtls : GetDtlsTransports()) {
276 dtls->ice_transport()->MaybeStartGathering();
277 }
278}
279
280RTCError JsepTransportController::AddRemoteCandidates(
281 const std::string& transport_name,
282 const cricket::Candidates& candidates) {
283 if (!network_thread_->IsCurrent()) {
284 return network_thread_->Invoke<RTCError>(RTC_FROM_HERE, [&] {
285 return AddRemoteCandidates(transport_name, candidates);
286 });
287 }
288
289 // Verify each candidate before passing down to the transport layer.
290 RTCError error = VerifyCandidates(candidates);
291 if (!error.ok()) {
292 return error;
293 }
Zhi Huange830e682018-03-30 10:48:35 -0700294 auto jsep_transport = GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800295 if (!jsep_transport) {
Zhi Huange830e682018-03-30 10:48:35 -0700296 RTC_LOG(LS_WARNING) << "Not adding candidate because the JsepTransport "
297 "doesn't exist. Ignore it.";
298 return RTCError::OK();
Zhi Huange818b6e2018-02-22 15:26:27 -0800299 }
Zhi Huange818b6e2018-02-22 15:26:27 -0800300 return jsep_transport->AddRemoteCandidates(candidates);
301}
302
303RTCError JsepTransportController::RemoveRemoteCandidates(
304 const cricket::Candidates& candidates) {
305 if (!network_thread_->IsCurrent()) {
306 return network_thread_->Invoke<RTCError>(
307 RTC_FROM_HERE, [&] { return RemoveRemoteCandidates(candidates); });
308 }
309
310 // Verify each candidate before passing down to the transport layer.
311 RTCError error = VerifyCandidates(candidates);
312 if (!error.ok()) {
313 return error;
314 }
315
316 std::map<std::string, cricket::Candidates> candidates_by_transport_name;
317 for (const cricket::Candidate& cand : candidates) {
318 if (!cand.transport_name().empty()) {
319 candidates_by_transport_name[cand.transport_name()].push_back(cand);
320 } else {
321 RTC_LOG(LS_ERROR) << "Not removing candidate because it does not have a "
322 "transport name set: "
323 << cand.ToString();
324 }
325 }
326
327 for (const auto& kv : candidates_by_transport_name) {
328 const std::string& transport_name = kv.first;
329 const cricket::Candidates& candidates = kv.second;
Zhi Huang365381f2018-04-13 16:44:34 -0700330 cricket::JsepTransport* jsep_transport =
Zhi Huange830e682018-03-30 10:48:35 -0700331 GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800332 if (!jsep_transport) {
Zhi Huange830e682018-03-30 10:48:35 -0700333 RTC_LOG(LS_WARNING)
334 << "Not removing candidate because the JsepTransport doesn't exist.";
335 continue;
Zhi Huange818b6e2018-02-22 15:26:27 -0800336 }
337 for (const cricket::Candidate& candidate : candidates) {
338 auto dtls = candidate.component() == cricket::ICE_CANDIDATE_COMPONENT_RTP
339 ? jsep_transport->rtp_dtls_transport()
340 : jsep_transport->rtcp_dtls_transport();
341 if (dtls) {
342 dtls->ice_transport()->RemoveRemoteCandidate(candidate);
343 }
344 }
345 }
346 return RTCError::OK();
347}
348
349bool JsepTransportController::GetStats(const std::string& transport_name,
350 cricket::TransportStats* stats) {
351 if (!network_thread_->IsCurrent()) {
352 return network_thread_->Invoke<bool>(
353 RTC_FROM_HERE, [=] { return GetStats(transport_name, stats); });
354 }
355
Zhi Huang365381f2018-04-13 16:44:34 -0700356 cricket::JsepTransport* transport = GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800357 if (!transport) {
358 return false;
359 }
360 return transport->GetStats(stats);
361}
362
Zhi Huangb57e1692018-06-12 11:41:11 -0700363void JsepTransportController::SetActiveResetSrtpParams(
364 bool active_reset_srtp_params) {
365 if (!network_thread_->IsCurrent()) {
366 network_thread_->Invoke<void>(RTC_FROM_HERE, [=] {
367 SetActiveResetSrtpParams(active_reset_srtp_params);
368 });
369 return;
370 }
371
372 RTC_LOG(INFO)
373 << "Updating the active_reset_srtp_params for JsepTransportController: "
374 << active_reset_srtp_params;
375 config_.active_reset_srtp_params = active_reset_srtp_params;
376 for (auto& kv : jsep_transports_by_name_) {
377 kv.second->SetActiveResetSrtpParams(active_reset_srtp_params);
378 }
379}
380
Zhi Huange818b6e2018-02-22 15:26:27 -0800381std::unique_ptr<cricket::DtlsTransportInternal>
382JsepTransportController::CreateDtlsTransport(const std::string& transport_name,
383 bool rtcp) {
384 RTC_DCHECK(network_thread_->IsCurrent());
385 int component = rtcp ? cricket::ICE_CANDIDATE_COMPONENT_RTCP
386 : cricket::ICE_CANDIDATE_COMPONENT_RTP;
387
388 std::unique_ptr<cricket::DtlsTransportInternal> dtls;
389 if (config_.external_transport_factory) {
390 auto ice = config_.external_transport_factory->CreateIceTransport(
391 transport_name, component);
392 dtls = config_.external_transport_factory->CreateDtlsTransport(
393 std::move(ice), config_.crypto_options);
394 } else {
Karl Wiberg918f50c2018-07-05 11:40:33 +0200395 auto ice = absl::make_unique<cricket::P2PTransportChannel>(
Zach Steine20867f2018-08-02 13:20:15 -0700396 transport_name, component, port_allocator_, async_resolver_factory_,
397 config_.event_log);
Karl Wiberg918f50c2018-07-05 11:40:33 +0200398 dtls = absl::make_unique<cricket::DtlsTransport>(std::move(ice),
399 config_.crypto_options);
Zhi Huange818b6e2018-02-22 15:26:27 -0800400 }
401
402 RTC_DCHECK(dtls);
403 dtls->SetSslMaxProtocolVersion(config_.ssl_max_version);
Zhi Huange818b6e2018-02-22 15:26:27 -0800404 dtls->ice_transport()->SetIceRole(ice_role_);
405 dtls->ice_transport()->SetIceTiebreaker(ice_tiebreaker_);
406 dtls->ice_transport()->SetIceConfig(ice_config_);
407 if (certificate_) {
408 bool set_cert_success = dtls->SetLocalCertificate(certificate_);
409 RTC_DCHECK(set_cert_success);
410 }
411
412 // Connect to signals offered by the DTLS and ICE transport.
413 dtls->SignalWritableState.connect(
414 this, &JsepTransportController::OnTransportWritableState_n);
415 dtls->SignalReceivingState.connect(
416 this, &JsepTransportController::OnTransportReceivingState_n);
417 dtls->SignalDtlsHandshakeError.connect(
418 this, &JsepTransportController::OnDtlsHandshakeError);
419 dtls->ice_transport()->SignalGatheringState.connect(
420 this, &JsepTransportController::OnTransportGatheringState_n);
421 dtls->ice_transport()->SignalCandidateGathered.connect(
422 this, &JsepTransportController::OnTransportCandidateGathered_n);
423 dtls->ice_transport()->SignalCandidatesRemoved.connect(
424 this, &JsepTransportController::OnTransportCandidatesRemoved_n);
425 dtls->ice_transport()->SignalRoleConflict.connect(
426 this, &JsepTransportController::OnTransportRoleConflict_n);
427 dtls->ice_transport()->SignalStateChanged.connect(
428 this, &JsepTransportController::OnTransportStateChanged_n);
429 return dtls;
430}
431
432std::unique_ptr<webrtc::RtpTransport>
433JsepTransportController::CreateUnencryptedRtpTransport(
434 const std::string& transport_name,
435 rtc::PacketTransportInternal* rtp_packet_transport,
436 rtc::PacketTransportInternal* rtcp_packet_transport) {
437 RTC_DCHECK(network_thread_->IsCurrent());
Zhi Huange830e682018-03-30 10:48:35 -0700438 auto unencrypted_rtp_transport =
Karl Wiberg918f50c2018-07-05 11:40:33 +0200439 absl::make_unique<RtpTransport>(rtcp_packet_transport == nullptr);
Zhi Huange830e682018-03-30 10:48:35 -0700440 unencrypted_rtp_transport->SetRtpPacketTransport(rtp_packet_transport);
441 if (rtcp_packet_transport) {
442 unencrypted_rtp_transport->SetRtcpPacketTransport(rtcp_packet_transport);
443 }
444 return unencrypted_rtp_transport;
Zhi Huange818b6e2018-02-22 15:26:27 -0800445}
446
447std::unique_ptr<webrtc::SrtpTransport>
448JsepTransportController::CreateSdesTransport(
449 const std::string& transport_name,
Zhi Huange830e682018-03-30 10:48:35 -0700450 cricket::DtlsTransportInternal* rtp_dtls_transport,
451 cricket::DtlsTransportInternal* rtcp_dtls_transport) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800452 RTC_DCHECK(network_thread_->IsCurrent());
Zhi Huange818b6e2018-02-22 15:26:27 -0800453 auto srtp_transport =
Karl Wiberg918f50c2018-07-05 11:40:33 +0200454 absl::make_unique<webrtc::SrtpTransport>(rtcp_dtls_transport == nullptr);
Zhi Huange830e682018-03-30 10:48:35 -0700455 RTC_DCHECK(rtp_dtls_transport);
456 srtp_transport->SetRtpPacketTransport(rtp_dtls_transport);
457 if (rtcp_dtls_transport) {
458 srtp_transport->SetRtcpPacketTransport(rtcp_dtls_transport);
Zhi Huange818b6e2018-02-22 15:26:27 -0800459 }
460 if (config_.enable_external_auth) {
461 srtp_transport->EnableExternalAuth();
462 }
463 return srtp_transport;
464}
465
466std::unique_ptr<webrtc::DtlsSrtpTransport>
467JsepTransportController::CreateDtlsSrtpTransport(
468 const std::string& transport_name,
469 cricket::DtlsTransportInternal* rtp_dtls_transport,
470 cricket::DtlsTransportInternal* rtcp_dtls_transport) {
471 RTC_DCHECK(network_thread_->IsCurrent());
Karl Wiberg918f50c2018-07-05 11:40:33 +0200472 auto dtls_srtp_transport = absl::make_unique<webrtc::DtlsSrtpTransport>(
Zhi Huang365381f2018-04-13 16:44:34 -0700473 rtcp_dtls_transport == nullptr);
Zhi Huang27f3bf52018-03-26 21:37:23 -0700474 if (config_.enable_external_auth) {
Zhi Huang365381f2018-04-13 16:44:34 -0700475 dtls_srtp_transport->EnableExternalAuth();
Zhi Huang27f3bf52018-03-26 21:37:23 -0700476 }
Zhi Huang97d5e5b2018-03-27 00:09:01 +0000477
Zhi Huange818b6e2018-02-22 15:26:27 -0800478 dtls_srtp_transport->SetDtlsTransports(rtp_dtls_transport,
479 rtcp_dtls_transport);
Zhi Huangb57e1692018-06-12 11:41:11 -0700480 dtls_srtp_transport->SetActiveResetSrtpParams(
481 config_.active_reset_srtp_params);
Zhi Huange818b6e2018-02-22 15:26:27 -0800482 return dtls_srtp_transport;
483}
484
485std::vector<cricket::DtlsTransportInternal*>
486JsepTransportController::GetDtlsTransports() {
487 std::vector<cricket::DtlsTransportInternal*> dtls_transports;
Zhi Huange830e682018-03-30 10:48:35 -0700488 for (auto it = jsep_transports_by_name_.begin();
489 it != jsep_transports_by_name_.end(); ++it) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800490 auto jsep_transport = it->second.get();
491 RTC_DCHECK(jsep_transport);
492 if (jsep_transport->rtp_dtls_transport()) {
493 dtls_transports.push_back(jsep_transport->rtp_dtls_transport());
494 }
495
496 if (jsep_transport->rtcp_dtls_transport()) {
497 dtls_transports.push_back(jsep_transport->rtcp_dtls_transport());
498 }
499 }
500 return dtls_transports;
501}
502
Zhi Huange818b6e2018-02-22 15:26:27 -0800503RTCError JsepTransportController::ApplyDescription_n(
504 bool local,
505 SdpType type,
506 const cricket::SessionDescription* description) {
507 RTC_DCHECK(network_thread_->IsCurrent());
508 RTC_DCHECK(description);
509
510 if (local) {
511 local_desc_ = description;
512 } else {
513 remote_desc_ = description;
514 }
515
Zhi Huange830e682018-03-30 10:48:35 -0700516 RTCError error;
Zhi Huangd2248f82018-04-10 14:41:03 -0700517 error = ValidateAndMaybeUpdateBundleGroup(local, type, description);
Zhi Huange830e682018-03-30 10:48:35 -0700518 if (!error.ok()) {
519 return error;
Zhi Huange818b6e2018-02-22 15:26:27 -0800520 }
521
522 std::vector<int> merged_encrypted_extension_ids;
523 if (bundle_group_) {
524 merged_encrypted_extension_ids =
525 MergeEncryptedHeaderExtensionIdsForBundle(description);
526 }
527
528 for (const cricket::ContentInfo& content_info : description->contents()) {
529 // Don't create transports for rejected m-lines and bundled m-lines."
530 if (content_info.rejected ||
531 (IsBundled(content_info.name) && content_info.name != *bundled_mid())) {
532 continue;
533 }
Anton Sukhanov7940da02018-10-10 10:34:49 -0700534 error = MaybeCreateJsepTransport(local, content_info);
Zhi Huange830e682018-03-30 10:48:35 -0700535 if (!error.ok()) {
536 return error;
537 }
Zhi Huange818b6e2018-02-22 15:26:27 -0800538 }
539
540 RTC_DCHECK(description->contents().size() ==
541 description->transport_infos().size());
542 for (size_t i = 0; i < description->contents().size(); ++i) {
543 const cricket::ContentInfo& content_info = description->contents()[i];
544 const cricket::TransportInfo& transport_info =
545 description->transport_infos()[i];
546 if (content_info.rejected) {
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700547 HandleRejectedContent(content_info, description);
Zhi Huange818b6e2018-02-22 15:26:27 -0800548 continue;
549 }
550
551 if (IsBundled(content_info.name) && content_info.name != *bundled_mid()) {
Zhi Huang365381f2018-04-13 16:44:34 -0700552 if (!HandleBundledContent(content_info)) {
553 return RTCError(RTCErrorType::INVALID_PARAMETER,
554 "Failed to process the bundled m= section.");
555 }
Zhi Huange818b6e2018-02-22 15:26:27 -0800556 continue;
557 }
558
Zhi Huange830e682018-03-30 10:48:35 -0700559 error = ValidateContent(content_info);
560 if (!error.ok()) {
561 return error;
562 }
563
Zhi Huange818b6e2018-02-22 15:26:27 -0800564 std::vector<int> extension_ids;
Taylor Brandstetter0ab56512018-04-12 10:30:48 -0700565 if (bundled_mid() && content_info.name == *bundled_mid()) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800566 extension_ids = merged_encrypted_extension_ids;
567 } else {
568 extension_ids = GetEncryptedHeaderExtensionIds(content_info);
569 }
570
Zhi Huange830e682018-03-30 10:48:35 -0700571 int rtp_abs_sendtime_extn_id =
572 GetRtpAbsSendTimeHeaderExtensionId(content_info);
573
Zhi Huang365381f2018-04-13 16:44:34 -0700574 cricket::JsepTransport* transport =
Zhi Huange830e682018-03-30 10:48:35 -0700575 GetJsepTransportForMid(content_info.name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800576 RTC_DCHECK(transport);
577
578 SetIceRole_n(DetermineIceRole(transport, transport_info, type, local));
579
Zhi Huange818b6e2018-02-22 15:26:27 -0800580 cricket::JsepTransportDescription jsep_description =
581 CreateJsepTransportDescription(content_info, transport_info,
Zhi Huange830e682018-03-30 10:48:35 -0700582 extension_ids, rtp_abs_sendtime_extn_id);
Zhi Huange818b6e2018-02-22 15:26:27 -0800583 if (local) {
584 error =
585 transport->SetLocalJsepTransportDescription(jsep_description, type);
586 } else {
587 error =
588 transport->SetRemoteJsepTransportDescription(jsep_description, type);
589 }
590
591 if (!error.ok()) {
592 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
593 "Failed to apply the description for " +
594 content_info.name + ": " + error.message());
595 }
596 }
597 return RTCError::OK();
598}
599
Zhi Huangd2248f82018-04-10 14:41:03 -0700600RTCError JsepTransportController::ValidateAndMaybeUpdateBundleGroup(
601 bool local,
602 SdpType type,
Zhi Huange830e682018-03-30 10:48:35 -0700603 const cricket::SessionDescription* description) {
604 RTC_DCHECK(description);
Zhi Huangd2248f82018-04-10 14:41:03 -0700605 const cricket::ContentGroup* new_bundle_group =
606 description->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
607
608 // The BUNDLE group containing a MID that no m= section has is invalid.
609 if (new_bundle_group) {
610 for (auto content_name : new_bundle_group->content_names()) {
611 if (!description->GetContentByName(content_name)) {
612 return RTCError(RTCErrorType::INVALID_PARAMETER,
613 "The BUNDLE group contains MID:" + content_name +
614 " matching no m= section.");
615 }
616 }
617 }
618
619 if (type == SdpType::kAnswer) {
620 const cricket::ContentGroup* offered_bundle_group =
621 local ? remote_desc_->GetGroupByName(cricket::GROUP_TYPE_BUNDLE)
622 : local_desc_->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
623
624 if (new_bundle_group) {
625 // The BUNDLE group in answer should be a subset of offered group.
626 for (auto content_name : new_bundle_group->content_names()) {
627 if (!offered_bundle_group ||
628 !offered_bundle_group->HasContentName(content_name)) {
629 return RTCError(RTCErrorType::INVALID_PARAMETER,
630 "The BUNDLE group in answer contains a MID that was "
631 "not in the offered group.");
632 }
633 }
634 }
635
636 if (bundle_group_) {
637 for (auto content_name : bundle_group_->content_names()) {
638 // An answer that removes m= sections from pre-negotiated BUNDLE group
639 // without rejecting it, is invalid.
640 if (!new_bundle_group ||
641 !new_bundle_group->HasContentName(content_name)) {
642 auto* content_info = description->GetContentByName(content_name);
643 if (!content_info || !content_info->rejected) {
644 return RTCError(RTCErrorType::INVALID_PARAMETER,
645 "Answer cannot remove m= section " + content_name +
646 " from already-established BUNDLE group.");
647 }
648 }
649 }
650 }
651 }
652
653 if (config_.bundle_policy ==
654 PeerConnectionInterface::kBundlePolicyMaxBundle &&
655 !description->HasGroup(cricket::GROUP_TYPE_BUNDLE)) {
656 return RTCError(RTCErrorType::INVALID_PARAMETER,
657 "max-bundle is used but no bundle group found.");
658 }
659
660 if (ShouldUpdateBundleGroup(type, description)) {
Taylor Brandstetter0ab56512018-04-12 10:30:48 -0700661 const std::string* new_bundled_mid = new_bundle_group->FirstContentName();
662 if (bundled_mid() && new_bundled_mid &&
663 *bundled_mid() != *new_bundled_mid) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700664 return RTCError(RTCErrorType::UNSUPPORTED_OPERATION,
665 "Changing the negotiated BUNDLE-tag is not supported.");
666 }
667
668 bundle_group_ = *new_bundle_group;
669 }
Zhi Huange830e682018-03-30 10:48:35 -0700670
671 if (!bundled_mid()) {
672 return RTCError::OK();
673 }
674
675 auto bundled_content = description->GetContentByName(*bundled_mid());
676 if (!bundled_content) {
677 return RTCError(
678 RTCErrorType::INVALID_PARAMETER,
679 "An m= section associated with the BUNDLE-tag doesn't exist.");
680 }
681
682 // If the |bundled_content| is rejected, other contents in the bundle group
683 // should be rejected.
684 if (bundled_content->rejected) {
685 for (auto content_name : bundle_group_->content_names()) {
686 auto other_content = description->GetContentByName(content_name);
687 if (!other_content->rejected) {
688 return RTCError(
689 RTCErrorType::INVALID_PARAMETER,
690 "The m= section:" + content_name + " should be rejected.");
691 }
692 }
693 }
694
695 return RTCError::OK();
696}
697
698RTCError JsepTransportController::ValidateContent(
699 const cricket::ContentInfo& content_info) {
700 if (config_.rtcp_mux_policy ==
701 PeerConnectionInterface::kRtcpMuxPolicyRequire &&
702 content_info.type == cricket::MediaProtocolType::kRtp &&
703 !content_info.media_description()->rtcp_mux()) {
704 return RTCError(RTCErrorType::INVALID_PARAMETER,
705 "The m= section:" + content_info.name +
706 " is invalid. RTCP-MUX is not "
707 "enabled when it is required.");
708 }
709 return RTCError::OK();
710}
711
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700712void JsepTransportController::HandleRejectedContent(
Zhi Huangd2248f82018-04-10 14:41:03 -0700713 const cricket::ContentInfo& content_info,
714 const cricket::SessionDescription* description) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800715 // If the content is rejected, let the
716 // BaseChannel/SctpTransport change the RtpTransport/DtlsTransport first,
Zhi Huang365381f2018-04-13 16:44:34 -0700717 // then destroy the cricket::JsepTransport.
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700718 RemoveTransportForMid(content_info.name);
Zhi Huange830e682018-03-30 10:48:35 -0700719 if (content_info.name == bundled_mid()) {
720 for (auto content_name : bundle_group_->content_names()) {
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700721 RemoveTransportForMid(content_name);
Zhi Huange830e682018-03-30 10:48:35 -0700722 }
723 bundle_group_.reset();
724 } else if (IsBundled(content_info.name)) {
725 // Remove the rejected content from the |bundle_group_|.
Zhi Huange818b6e2018-02-22 15:26:27 -0800726 bundle_group_->RemoveContentName(content_info.name);
Zhi Huange830e682018-03-30 10:48:35 -0700727 // Reset the bundle group if nothing left.
728 if (!bundle_group_->FirstContentName()) {
729 bundle_group_.reset();
730 }
Zhi Huange818b6e2018-02-22 15:26:27 -0800731 }
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700732 MaybeDestroyJsepTransport(content_info.name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800733}
734
Zhi Huang365381f2018-04-13 16:44:34 -0700735bool JsepTransportController::HandleBundledContent(
Zhi Huange818b6e2018-02-22 15:26:27 -0800736 const cricket::ContentInfo& content_info) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700737 auto jsep_transport = GetJsepTransportByName(*bundled_mid());
738 RTC_DCHECK(jsep_transport);
Zhi Huange818b6e2018-02-22 15:26:27 -0800739 // If the content is bundled, let the
740 // BaseChannel/SctpTransport change the RtpTransport/DtlsTransport first,
Zhi Huang365381f2018-04-13 16:44:34 -0700741 // then destroy the cricket::JsepTransport.
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700742 if (SetTransportForMid(content_info.name, jsep_transport)) {
Zhi Huang365381f2018-04-13 16:44:34 -0700743 MaybeDestroyJsepTransport(content_info.name);
744 return true;
745 }
746 return false;
Zhi Huange818b6e2018-02-22 15:26:27 -0800747}
748
Zhi Huang365381f2018-04-13 16:44:34 -0700749bool JsepTransportController::SetTransportForMid(
Zhi Huangd2248f82018-04-10 14:41:03 -0700750 const std::string& mid,
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700751 cricket::JsepTransport* jsep_transport) {
Zhi Huang365381f2018-04-13 16:44:34 -0700752 RTC_DCHECK(jsep_transport);
Zhi Huangd2248f82018-04-10 14:41:03 -0700753 if (mid_to_transport_[mid] == jsep_transport) {
Zhi Huang365381f2018-04-13 16:44:34 -0700754 return true;
Zhi Huangd2248f82018-04-10 14:41:03 -0700755 }
756
757 mid_to_transport_[mid] = jsep_transport;
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700758 return config_.transport_observer->OnTransportChanged(
759 mid, jsep_transport->rtp_transport(),
760 jsep_transport->rtp_dtls_transport());
Zhi Huangd2248f82018-04-10 14:41:03 -0700761}
762
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700763void JsepTransportController::RemoveTransportForMid(const std::string& mid) {
764 bool ret =
765 config_.transport_observer->OnTransportChanged(mid, nullptr, nullptr);
766 // Calling OnTransportChanged with nullptr should always succeed, since it is
767 // only expected to fail when adding media to a transport (not removing).
768 RTC_DCHECK(ret);
Zhi Huangd2248f82018-04-10 14:41:03 -0700769 mid_to_transport_.erase(mid);
770}
771
Zhi Huange818b6e2018-02-22 15:26:27 -0800772cricket::JsepTransportDescription
773JsepTransportController::CreateJsepTransportDescription(
774 cricket::ContentInfo content_info,
775 cricket::TransportInfo transport_info,
Zhi Huange830e682018-03-30 10:48:35 -0700776 const std::vector<int>& encrypted_extension_ids,
777 int rtp_abs_sendtime_extn_id) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800778 const cricket::MediaContentDescription* content_desc =
779 static_cast<const cricket::MediaContentDescription*>(
780 content_info.description);
781 RTC_DCHECK(content_desc);
782 bool rtcp_mux_enabled = content_info.type == cricket::MediaProtocolType::kSctp
783 ? true
784 : content_desc->rtcp_mux();
785
786 return cricket::JsepTransportDescription(
787 rtcp_mux_enabled, content_desc->cryptos(), encrypted_extension_ids,
Zhi Huange830e682018-03-30 10:48:35 -0700788 rtp_abs_sendtime_extn_id, transport_info.description);
Zhi Huange818b6e2018-02-22 15:26:27 -0800789}
790
791bool JsepTransportController::ShouldUpdateBundleGroup(
792 SdpType type,
793 const cricket::SessionDescription* description) {
794 if (config_.bundle_policy ==
795 PeerConnectionInterface::kBundlePolicyMaxBundle) {
796 return true;
797 }
798
799 if (type != SdpType::kAnswer) {
800 return false;
801 }
802
803 RTC_DCHECK(local_desc_ && remote_desc_);
804 const cricket::ContentGroup* local_bundle =
805 local_desc_->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
806 const cricket::ContentGroup* remote_bundle =
807 remote_desc_->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
808 return local_bundle && remote_bundle;
809}
810
811std::vector<int> JsepTransportController::GetEncryptedHeaderExtensionIds(
812 const cricket::ContentInfo& content_info) {
813 const cricket::MediaContentDescription* content_desc =
814 static_cast<const cricket::MediaContentDescription*>(
815 content_info.description);
816
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700817 if (!config_.crypto_options.srtp.enable_encrypted_rtp_header_extensions) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800818 return std::vector<int>();
819 }
820
821 std::vector<int> encrypted_header_extension_ids;
822 for (auto extension : content_desc->rtp_header_extensions()) {
823 if (!extension.encrypt) {
824 continue;
825 }
826 auto it = std::find(encrypted_header_extension_ids.begin(),
827 encrypted_header_extension_ids.end(), extension.id);
828 if (it == encrypted_header_extension_ids.end()) {
829 encrypted_header_extension_ids.push_back(extension.id);
830 }
831 }
832 return encrypted_header_extension_ids;
833}
834
835std::vector<int>
836JsepTransportController::MergeEncryptedHeaderExtensionIdsForBundle(
837 const cricket::SessionDescription* description) {
838 RTC_DCHECK(description);
839 RTC_DCHECK(bundle_group_);
840
841 std::vector<int> merged_ids;
842 // Union the encrypted header IDs in the group when bundle is enabled.
843 for (const cricket::ContentInfo& content_info : description->contents()) {
844 if (bundle_group_->HasContentName(content_info.name)) {
845 std::vector<int> extension_ids =
846 GetEncryptedHeaderExtensionIds(content_info);
847 for (int id : extension_ids) {
848 auto it = std::find(merged_ids.begin(), merged_ids.end(), id);
849 if (it == merged_ids.end()) {
850 merged_ids.push_back(id);
851 }
852 }
853 }
854 }
855 return merged_ids;
856}
857
Zhi Huange830e682018-03-30 10:48:35 -0700858int JsepTransportController::GetRtpAbsSendTimeHeaderExtensionId(
Zhi Huange818b6e2018-02-22 15:26:27 -0800859 const cricket::ContentInfo& content_info) {
Zhi Huange830e682018-03-30 10:48:35 -0700860 if (!config_.enable_external_auth) {
861 return -1;
Zhi Huange818b6e2018-02-22 15:26:27 -0800862 }
863
864 const cricket::MediaContentDescription* content_desc =
865 static_cast<const cricket::MediaContentDescription*>(
866 content_info.description);
Zhi Huange830e682018-03-30 10:48:35 -0700867
868 const webrtc::RtpExtension* send_time_extension =
869 webrtc::RtpExtension::FindHeaderExtensionByUri(
870 content_desc->rtp_header_extensions(),
871 webrtc::RtpExtension::kAbsSendTimeUri);
872 return send_time_extension ? send_time_extension->id : -1;
873}
874
Zhi Huang365381f2018-04-13 16:44:34 -0700875const cricket::JsepTransport* JsepTransportController::GetJsepTransportForMid(
Zhi Huange830e682018-03-30 10:48:35 -0700876 const std::string& mid) const {
Zhi Huangd2248f82018-04-10 14:41:03 -0700877 auto it = mid_to_transport_.find(mid);
878 return it == mid_to_transport_.end() ? nullptr : it->second;
Zhi Huange830e682018-03-30 10:48:35 -0700879}
880
Zhi Huang365381f2018-04-13 16:44:34 -0700881cricket::JsepTransport* JsepTransportController::GetJsepTransportForMid(
Zhi Huange830e682018-03-30 10:48:35 -0700882 const std::string& mid) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700883 auto it = mid_to_transport_.find(mid);
884 return it == mid_to_transport_.end() ? nullptr : it->second;
Zhi Huange830e682018-03-30 10:48:35 -0700885}
886
Zhi Huang365381f2018-04-13 16:44:34 -0700887const cricket::JsepTransport* JsepTransportController::GetJsepTransportByName(
Zhi Huange830e682018-03-30 10:48:35 -0700888 const std::string& transport_name) const {
889 auto it = jsep_transports_by_name_.find(transport_name);
890 return (it == jsep_transports_by_name_.end()) ? nullptr : it->second.get();
891}
892
Zhi Huang365381f2018-04-13 16:44:34 -0700893cricket::JsepTransport* JsepTransportController::GetJsepTransportByName(
Zhi Huange830e682018-03-30 10:48:35 -0700894 const std::string& transport_name) {
895 auto it = jsep_transports_by_name_.find(transport_name);
896 return (it == jsep_transports_by_name_.end()) ? nullptr : it->second.get();
897}
898
899RTCError JsepTransportController::MaybeCreateJsepTransport(
Anton Sukhanov7940da02018-10-10 10:34:49 -0700900 bool local,
Zhi Huange830e682018-03-30 10:48:35 -0700901 const cricket::ContentInfo& content_info) {
902 RTC_DCHECK(network_thread_->IsCurrent());
Zhi Huang365381f2018-04-13 16:44:34 -0700903 cricket::JsepTransport* transport = GetJsepTransportByName(content_info.name);
Zhi Huange830e682018-03-30 10:48:35 -0700904 if (transport) {
905 return RTCError::OK();
906 }
907
908 const cricket::MediaContentDescription* content_desc =
909 static_cast<const cricket::MediaContentDescription*>(
910 content_info.description);
911 if (certificate_ && !content_desc->cryptos().empty()) {
912 return RTCError(RTCErrorType::INVALID_PARAMETER,
913 "SDES and DTLS-SRTP cannot be enabled at the same time.");
914 }
915
Zhi Huange818b6e2018-02-22 15:26:27 -0800916 std::unique_ptr<cricket::DtlsTransportInternal> rtp_dtls_transport =
Zhi Huangd2248f82018-04-10 14:41:03 -0700917 CreateDtlsTransport(content_info.name, /*rtcp =*/false);
Anton Sukhanov7940da02018-10-10 10:34:49 -0700918
Zhi Huange818b6e2018-02-22 15:26:27 -0800919 std::unique_ptr<cricket::DtlsTransportInternal> rtcp_dtls_transport;
Anton Sukhanov7940da02018-10-10 10:34:49 -0700920 std::unique_ptr<RtpTransport> unencrypted_rtp_transport;
921 std::unique_ptr<SrtpTransport> sdes_transport;
922 std::unique_ptr<DtlsSrtpTransport> dtls_srtp_transport;
923 std::unique_ptr<MediaTransportInterface> media_transport;
924
Zhi Huange830e682018-03-30 10:48:35 -0700925 if (config_.rtcp_mux_policy !=
926 PeerConnectionInterface::kRtcpMuxPolicyRequire &&
927 content_info.type == cricket::MediaProtocolType::kRtp) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700928 rtcp_dtls_transport =
929 CreateDtlsTransport(content_info.name, /*rtcp =*/true);
Zhi Huange818b6e2018-02-22 15:26:27 -0800930 }
931
Anton Sukhanov7940da02018-10-10 10:34:49 -0700932 if (config_.media_transport_factory != nullptr) {
933 auto media_transport_result =
934 config_.media_transport_factory->CreateMediaTransport(
935 rtp_dtls_transport->ice_transport(), network_thread_,
936 /*is_caller=*/local);
937
938 // TODO(sukhanov): Proper error handling.
939 RTC_CHECK(media_transport_result.ok());
940
941 media_transport = std::move(media_transport_result.value());
942 }
943
944 // TODO(sukhanov): Do not create RTP/RTCP transports if media transport is
945 // used.
Zhi Huange818b6e2018-02-22 15:26:27 -0800946 if (config_.disable_encryption) {
947 unencrypted_rtp_transport = CreateUnencryptedRtpTransport(
Zhi Huangd2248f82018-04-10 14:41:03 -0700948 content_info.name, rtp_dtls_transport.get(), rtcp_dtls_transport.get());
Zhi Huange818b6e2018-02-22 15:26:27 -0800949 } else if (!content_desc->cryptos().empty()) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700950 sdes_transport = CreateSdesTransport(
951 content_info.name, rtp_dtls_transport.get(), rtcp_dtls_transport.get());
Zhi Huange818b6e2018-02-22 15:26:27 -0800952 } else {
Zhi Huangd2248f82018-04-10 14:41:03 -0700953 dtls_srtp_transport = CreateDtlsSrtpTransport(
954 content_info.name, rtp_dtls_transport.get(), rtcp_dtls_transport.get());
Zhi Huange818b6e2018-02-22 15:26:27 -0800955 }
956
Zhi Huang365381f2018-04-13 16:44:34 -0700957 std::unique_ptr<cricket::JsepTransport> jsep_transport =
Karl Wiberg918f50c2018-07-05 11:40:33 +0200958 absl::make_unique<cricket::JsepTransport>(
Zhi Huangd2248f82018-04-10 14:41:03 -0700959 content_info.name, certificate_, std::move(unencrypted_rtp_transport),
Zhi Huange818b6e2018-02-22 15:26:27 -0800960 std::move(sdes_transport), std::move(dtls_srtp_transport),
Anton Sukhanov7940da02018-10-10 10:34:49 -0700961 std::move(rtp_dtls_transport), std::move(rtcp_dtls_transport),
962 std::move(media_transport));
Zhi Huange818b6e2018-02-22 15:26:27 -0800963 jsep_transport->SignalRtcpMuxActive.connect(
964 this, &JsepTransportController::UpdateAggregateStates_n);
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700965 SetTransportForMid(content_info.name, jsep_transport.get());
Zhi Huange830e682018-03-30 10:48:35 -0700966
Zhi Huangd2248f82018-04-10 14:41:03 -0700967 jsep_transports_by_name_[content_info.name] = std::move(jsep_transport);
968 UpdateAggregateStates_n();
Zhi Huange830e682018-03-30 10:48:35 -0700969 return RTCError::OK();
Zhi Huange818b6e2018-02-22 15:26:27 -0800970}
971
972void JsepTransportController::MaybeDestroyJsepTransport(
973 const std::string& mid) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700974 auto jsep_transport = GetJsepTransportByName(mid);
975 if (!jsep_transport) {
976 return;
977 }
978
979 // Don't destroy the JsepTransport if there are still media sections referring
980 // to it.
981 for (const auto& kv : mid_to_transport_) {
982 if (kv.second == jsep_transport) {
983 return;
984 }
985 }
Zhi Huange830e682018-03-30 10:48:35 -0700986 jsep_transports_by_name_.erase(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -0800987 UpdateAggregateStates_n();
988}
989
990void JsepTransportController::DestroyAllJsepTransports_n() {
991 RTC_DCHECK(network_thread_->IsCurrent());
Zhi Huange830e682018-03-30 10:48:35 -0700992 jsep_transports_by_name_.clear();
Zhi Huange818b6e2018-02-22 15:26:27 -0800993}
994
995void JsepTransportController::SetIceRole_n(cricket::IceRole ice_role) {
996 RTC_DCHECK(network_thread_->IsCurrent());
997
998 ice_role_ = ice_role;
999 for (auto& dtls : GetDtlsTransports()) {
1000 dtls->ice_transport()->SetIceRole(ice_role_);
1001 }
1002}
1003
1004cricket::IceRole JsepTransportController::DetermineIceRole(
Zhi Huang365381f2018-04-13 16:44:34 -07001005 cricket::JsepTransport* jsep_transport,
Zhi Huange818b6e2018-02-22 15:26:27 -08001006 const cricket::TransportInfo& transport_info,
1007 SdpType type,
1008 bool local) {
1009 cricket::IceRole ice_role = ice_role_;
1010 auto tdesc = transport_info.description;
1011 if (local) {
1012 // The initial offer side may use ICE Lite, in which case, per RFC5245
1013 // Section 5.1.1, the answer side should take the controlling role if it is
1014 // in the full ICE mode.
1015 //
1016 // When both sides use ICE Lite, the initial offer side must take the
1017 // controlling role, and this is the default logic implemented in
1018 // SetLocalDescription in JsepTransportController.
1019 if (jsep_transport->remote_description() &&
1020 jsep_transport->remote_description()->transport_desc.ice_mode ==
1021 cricket::ICEMODE_LITE &&
1022 ice_role_ == cricket::ICEROLE_CONTROLLED &&
1023 tdesc.ice_mode == cricket::ICEMODE_FULL) {
1024 ice_role = cricket::ICEROLE_CONTROLLING;
1025 }
1026
1027 // Older versions of Chrome expect the ICE role to be re-determined when an
1028 // ICE restart occurs, and also don't perform conflict resolution correctly,
1029 // so for now we can't safely stop doing this, unless the application opts
1030 // in by setting |config_.redetermine_role_on_ice_restart_| to false. See:
1031 // https://bugs.chromium.org/p/chromium/issues/detail?id=628676
1032 // TODO(deadbeef): Remove this when these old versions of Chrome reach a low
1033 // enough population.
1034 if (config_.redetermine_role_on_ice_restart &&
1035 jsep_transport->local_description() &&
1036 cricket::IceCredentialsChanged(
1037 jsep_transport->local_description()->transport_desc.ice_ufrag,
1038 jsep_transport->local_description()->transport_desc.ice_pwd,
1039 tdesc.ice_ufrag, tdesc.ice_pwd) &&
1040 // Don't change the ICE role if the remote endpoint is ICE lite; we
1041 // should always be controlling in that case.
1042 (!jsep_transport->remote_description() ||
1043 jsep_transport->remote_description()->transport_desc.ice_mode !=
1044 cricket::ICEMODE_LITE)) {
1045 ice_role = (type == SdpType::kOffer) ? cricket::ICEROLE_CONTROLLING
1046 : cricket::ICEROLE_CONTROLLED;
1047 }
1048 } else {
1049 // If our role is cricket::ICEROLE_CONTROLLED and the remote endpoint
1050 // supports only ice_lite, this local endpoint should take the CONTROLLING
1051 // role.
1052 // TODO(deadbeef): This is a session-level attribute, so it really shouldn't
1053 // be in a TransportDescription in the first place...
1054 if (ice_role_ == cricket::ICEROLE_CONTROLLED &&
1055 tdesc.ice_mode == cricket::ICEMODE_LITE) {
1056 ice_role = cricket::ICEROLE_CONTROLLING;
1057 }
1058
1059 // If we use ICE Lite and the remote endpoint uses the full implementation
1060 // of ICE, the local endpoint must take the controlled role, and the other
1061 // side must be the controlling role.
1062 if (jsep_transport->local_description() &&
1063 jsep_transport->local_description()->transport_desc.ice_mode ==
1064 cricket::ICEMODE_LITE &&
1065 ice_role_ == cricket::ICEROLE_CONTROLLING &&
Zhi Huange830e682018-03-30 10:48:35 -07001066 tdesc.ice_mode == cricket::ICEMODE_FULL) {
Zhi Huange818b6e2018-02-22 15:26:27 -08001067 ice_role = cricket::ICEROLE_CONTROLLED;
1068 }
1069 }
1070
1071 return ice_role;
1072}
1073
1074void JsepTransportController::OnTransportWritableState_n(
1075 rtc::PacketTransportInternal* transport) {
1076 RTC_DCHECK(network_thread_->IsCurrent());
1077 RTC_LOG(LS_INFO) << " Transport " << transport->transport_name()
1078 << " writability changed to " << transport->writable()
1079 << ".";
1080 UpdateAggregateStates_n();
1081}
1082
1083void JsepTransportController::OnTransportReceivingState_n(
1084 rtc::PacketTransportInternal* transport) {
1085 RTC_DCHECK(network_thread_->IsCurrent());
1086 UpdateAggregateStates_n();
1087}
1088
1089void JsepTransportController::OnTransportGatheringState_n(
1090 cricket::IceTransportInternal* transport) {
1091 RTC_DCHECK(network_thread_->IsCurrent());
1092 UpdateAggregateStates_n();
1093}
1094
1095void JsepTransportController::OnTransportCandidateGathered_n(
1096 cricket::IceTransportInternal* transport,
1097 const cricket::Candidate& candidate) {
1098 RTC_DCHECK(network_thread_->IsCurrent());
1099
1100 // We should never signal peer-reflexive candidates.
1101 if (candidate.type() == cricket::PRFLX_PORT_TYPE) {
1102 RTC_NOTREACHED();
1103 return;
1104 }
Steve Antond25828a2018-08-31 13:06:05 -07001105 std::string transport_name = transport->transport_name();
1106 invoker_.AsyncInvoke<void>(
1107 RTC_FROM_HERE, signaling_thread_, [this, transport_name, candidate] {
1108 SignalIceCandidatesGathered(transport_name, {candidate});
1109 });
Zhi Huange818b6e2018-02-22 15:26:27 -08001110}
1111
1112void JsepTransportController::OnTransportCandidatesRemoved_n(
1113 cricket::IceTransportInternal* transport,
1114 const cricket::Candidates& candidates) {
1115 invoker_.AsyncInvoke<void>(
1116 RTC_FROM_HERE, signaling_thread_,
Steve Antond25828a2018-08-31 13:06:05 -07001117 [this, candidates] { SignalIceCandidatesRemoved(candidates); });
Zhi Huange818b6e2018-02-22 15:26:27 -08001118}
1119
1120void JsepTransportController::OnTransportRoleConflict_n(
1121 cricket::IceTransportInternal* transport) {
1122 RTC_DCHECK(network_thread_->IsCurrent());
1123 // Note: since the role conflict is handled entirely on the network thread,
1124 // we don't need to worry about role conflicts occurring on two ports at
1125 // once. The first one encountered should immediately reverse the role.
1126 cricket::IceRole reversed_role = (ice_role_ == cricket::ICEROLE_CONTROLLING)
1127 ? cricket::ICEROLE_CONTROLLED
1128 : cricket::ICEROLE_CONTROLLING;
1129 RTC_LOG(LS_INFO) << "Got role conflict; switching to "
1130 << (reversed_role == cricket::ICEROLE_CONTROLLING
1131 ? "controlling"
1132 : "controlled")
1133 << " role.";
1134 SetIceRole_n(reversed_role);
1135}
1136
1137void JsepTransportController::OnTransportStateChanged_n(
1138 cricket::IceTransportInternal* transport) {
1139 RTC_DCHECK(network_thread_->IsCurrent());
1140 RTC_LOG(LS_INFO) << transport->transport_name() << " Transport "
1141 << transport->component()
1142 << " state changed. Check if state is complete.";
1143 UpdateAggregateStates_n();
1144}
1145
1146void JsepTransportController::UpdateAggregateStates_n() {
1147 RTC_DCHECK(network_thread_->IsCurrent());
1148
1149 auto dtls_transports = GetDtlsTransports();
1150 cricket::IceConnectionState new_connection_state =
1151 cricket::kIceConnectionConnecting;
1152 cricket::IceGatheringState new_gathering_state = cricket::kIceGatheringNew;
1153 bool any_failed = false;
1154 bool all_connected = !dtls_transports.empty();
1155 bool all_completed = !dtls_transports.empty();
1156 bool any_gathering = false;
1157 bool all_done_gathering = !dtls_transports.empty();
1158 for (const auto& dtls : dtls_transports) {
1159 any_failed = any_failed || dtls->ice_transport()->GetState() ==
1160 cricket::IceTransportState::STATE_FAILED;
1161 all_connected = all_connected && dtls->writable();
1162 all_completed =
1163 all_completed && dtls->writable() &&
1164 dtls->ice_transport()->GetState() ==
1165 cricket::IceTransportState::STATE_COMPLETED &&
1166 dtls->ice_transport()->GetIceRole() == cricket::ICEROLE_CONTROLLING &&
1167 dtls->ice_transport()->gathering_state() ==
1168 cricket::kIceGatheringComplete;
1169 any_gathering = any_gathering || dtls->ice_transport()->gathering_state() !=
1170 cricket::kIceGatheringNew;
1171 all_done_gathering =
1172 all_done_gathering && dtls->ice_transport()->gathering_state() ==
1173 cricket::kIceGatheringComplete;
1174 }
1175 if (any_failed) {
1176 new_connection_state = cricket::kIceConnectionFailed;
1177 } else if (all_completed) {
1178 new_connection_state = cricket::kIceConnectionCompleted;
1179 } else if (all_connected) {
1180 new_connection_state = cricket::kIceConnectionConnected;
1181 }
1182 if (ice_connection_state_ != new_connection_state) {
1183 ice_connection_state_ = new_connection_state;
Steve Antond25828a2018-08-31 13:06:05 -07001184 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_,
1185 [this, new_connection_state] {
1186 SignalIceConnectionState(new_connection_state);
1187 });
Zhi Huange818b6e2018-02-22 15:26:27 -08001188 }
1189
1190 if (all_done_gathering) {
1191 new_gathering_state = cricket::kIceGatheringComplete;
1192 } else if (any_gathering) {
1193 new_gathering_state = cricket::kIceGatheringGathering;
1194 }
1195 if (ice_gathering_state_ != new_gathering_state) {
1196 ice_gathering_state_ = new_gathering_state;
Steve Antond25828a2018-08-31 13:06:05 -07001197 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_,
1198 [this, new_gathering_state] {
1199 SignalIceGatheringState(new_gathering_state);
1200 });
Zhi Huange818b6e2018-02-22 15:26:27 -08001201 }
1202}
1203
1204void JsepTransportController::OnDtlsHandshakeError(
1205 rtc::SSLHandshakeError error) {
1206 SignalDtlsHandshakeError(error);
1207}
1208
1209} // namespace webrtc