blob: fd9551a328c4658c0574875f56275727d3393a42 [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
Steve Anton10542f22019-01-11 09:11:00 -080011#include "pc/jsep_transport_controller.h"
Zhi Huange818b6e2018-02-22 15:26:27 -080012
Zhi Huange818b6e2018-02-22 15:26:27 -080013#include <memory>
14#include <utility>
15
Steve Anton64b626b2019-01-28 17:25:26 -080016#include "absl/algorithm/container.h"
Zach Steinc64078f2018-11-27 15:53:01 -080017#include "absl/memory/memory.h"
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -080018#include "p2p/base/ice_transport_internal.h"
19#include "p2p/base/no_op_dtls_transport.h"
Zhi Huange818b6e2018-02-22 15:26:27 -080020#include "p2p/base/port.h"
Steve Anton10542f22019-01-11 09:11:00 -080021#include "pc/srtp_filter.h"
Zhi Huange818b6e2018-02-22 15:26:27 -080022#include "rtc_base/bind.h"
23#include "rtc_base/checks.h"
Zhi Huange818b6e2018-02-22 15:26:27 -080024#include "rtc_base/thread.h"
25
26using webrtc::SdpType;
27
28namespace {
29
Zhi Huange818b6e2018-02-22 15:26:27 -080030webrtc::RTCError VerifyCandidate(const cricket::Candidate& cand) {
31 // No address zero.
32 if (cand.address().IsNil() || cand.address().IsAnyIP()) {
33 return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
34 "candidate has address of zero");
35 }
36
37 // Disallow all ports below 1024, except for 80 and 443 on public addresses.
38 int port = cand.address().port();
39 if (cand.protocol() == cricket::TCP_PROTOCOL_NAME &&
40 (cand.tcptype() == cricket::TCPTYPE_ACTIVE_STR || port == 0)) {
41 // Expected for active-only candidates per
42 // http://tools.ietf.org/html/rfc6544#section-4.5 so no error.
43 // Libjingle clients emit port 0, in "active" mode.
44 return webrtc::RTCError::OK();
45 }
46 if (port < 1024) {
47 if ((port != 80) && (port != 443)) {
48 return webrtc::RTCError(
49 webrtc::RTCErrorType::INVALID_PARAMETER,
50 "candidate has port below 1024, but not 80 or 443");
51 }
52
53 if (cand.address().IsPrivateIP()) {
54 return webrtc::RTCError(
55 webrtc::RTCErrorType::INVALID_PARAMETER,
56 "candidate has port of 80 or 443 with private IP address");
57 }
58 }
59
60 return webrtc::RTCError::OK();
61}
62
63webrtc::RTCError VerifyCandidates(const cricket::Candidates& candidates) {
64 for (const cricket::Candidate& candidate : candidates) {
65 webrtc::RTCError error = VerifyCandidate(candidate);
66 if (!error.ok()) {
67 return error;
68 }
69 }
70 return webrtc::RTCError::OK();
71}
72
73} // namespace
74
75namespace webrtc {
76
77JsepTransportController::JsepTransportController(
78 rtc::Thread* signaling_thread,
79 rtc::Thread* network_thread,
80 cricket::PortAllocator* port_allocator,
Zach Steine20867f2018-08-02 13:20:15 -070081 AsyncResolverFactory* async_resolver_factory,
Zhi Huange818b6e2018-02-22 15:26:27 -080082 Config config)
83 : signaling_thread_(signaling_thread),
84 network_thread_(network_thread),
85 port_allocator_(port_allocator),
Zach Steine20867f2018-08-02 13:20:15 -070086 async_resolver_factory_(async_resolver_factory),
Zhi Huang365381f2018-04-13 16:44:34 -070087 config_(config) {
88 // The |transport_observer| is assumed to be non-null.
89 RTC_DCHECK(config_.transport_observer);
90}
Zhi Huange818b6e2018-02-22 15:26:27 -080091
92JsepTransportController::~JsepTransportController() {
93 // Channel destructors may try to send packets, so this needs to happen on
94 // the network thread.
95 network_thread_->Invoke<void>(
96 RTC_FROM_HERE,
97 rtc::Bind(&JsepTransportController::DestroyAllJsepTransports_n, this));
98}
99
100RTCError JsepTransportController::SetLocalDescription(
101 SdpType type,
102 const cricket::SessionDescription* description) {
103 if (!network_thread_->IsCurrent()) {
104 return network_thread_->Invoke<RTCError>(
105 RTC_FROM_HERE, [=] { return SetLocalDescription(type, description); });
106 }
107
108 if (!initial_offerer_.has_value()) {
109 initial_offerer_.emplace(type == SdpType::kOffer);
110 if (*initial_offerer_) {
111 SetIceRole_n(cricket::ICEROLE_CONTROLLING);
112 } else {
113 SetIceRole_n(cricket::ICEROLE_CONTROLLED);
114 }
115 }
116 return ApplyDescription_n(/*local=*/true, type, description);
117}
118
119RTCError JsepTransportController::SetRemoteDescription(
120 SdpType type,
121 const cricket::SessionDescription* description) {
122 if (!network_thread_->IsCurrent()) {
123 return network_thread_->Invoke<RTCError>(
124 RTC_FROM_HERE, [=] { return SetRemoteDescription(type, description); });
125 }
126
127 return ApplyDescription_n(/*local=*/false, type, description);
128}
129
130RtpTransportInternal* JsepTransportController::GetRtpTransport(
131 const std::string& mid) const {
Zhi Huange830e682018-03-30 10:48:35 -0700132 auto jsep_transport = GetJsepTransportForMid(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -0800133 if (!jsep_transport) {
134 return nullptr;
135 }
136 return jsep_transport->rtp_transport();
137}
138
Anton Sukhanov7940da02018-10-10 10:34:49 -0700139MediaTransportInterface* JsepTransportController::GetMediaTransport(
140 const std::string& mid) const {
141 auto jsep_transport = GetJsepTransportForMid(mid);
142 if (!jsep_transport) {
143 return nullptr;
144 }
145 return jsep_transport->media_transport();
146}
147
Bjorn Mellem175aa2e2018-11-08 11:23:22 -0800148MediaTransportState JsepTransportController::GetMediaTransportState(
149 const std::string& mid) const {
150 auto jsep_transport = GetJsepTransportForMid(mid);
151 if (!jsep_transport) {
152 return MediaTransportState::kPending;
153 }
154 return jsep_transport->media_transport_state();
155}
156
Zhi Huange818b6e2018-02-22 15:26:27 -0800157cricket::DtlsTransportInternal* JsepTransportController::GetDtlsTransport(
Harald Alvestrandad88c882018-11-28 16:47:46 +0100158 const std::string& mid) {
Zhi Huange830e682018-03-30 10:48:35 -0700159 auto jsep_transport = GetJsepTransportForMid(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -0800160 if (!jsep_transport) {
161 return nullptr;
162 }
163 return jsep_transport->rtp_dtls_transport();
164}
165
Harald Alvestrandad88c882018-11-28 16:47:46 +0100166const cricket::DtlsTransportInternal*
167JsepTransportController::GetRtcpDtlsTransport(const std::string& mid) const {
Zhi Huange830e682018-03-30 10:48:35 -0700168 auto jsep_transport = GetJsepTransportForMid(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -0800169 if (!jsep_transport) {
170 return nullptr;
171 }
172 return jsep_transport->rtcp_dtls_transport();
173}
174
Harald Alvestrand4a7b3ac2019-01-17 10:39:40 +0100175rtc::scoped_refptr<webrtc::DtlsTransport>
Harald Alvestrandad88c882018-11-28 16:47:46 +0100176JsepTransportController::LookupDtlsTransportByMid(const std::string& mid) {
177 auto jsep_transport = GetJsepTransportForMid(mid);
178 if (!jsep_transport) {
179 return nullptr;
180 }
181 return jsep_transport->RtpDtlsTransport();
182}
183
Zhi Huange818b6e2018-02-22 15:26:27 -0800184void JsepTransportController::SetIceConfig(const cricket::IceConfig& config) {
185 if (!network_thread_->IsCurrent()) {
186 network_thread_->Invoke<void>(RTC_FROM_HERE, [&] { SetIceConfig(config); });
187 return;
188 }
189
190 ice_config_ = config;
191 for (auto& dtls : GetDtlsTransports()) {
192 dtls->ice_transport()->SetIceConfig(ice_config_);
193 }
194}
195
196void JsepTransportController::SetNeedsIceRestartFlag() {
Zhi Huange830e682018-03-30 10:48:35 -0700197 for (auto& kv : jsep_transports_by_name_) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800198 kv.second->SetNeedsIceRestartFlag();
199 }
200}
201
202bool JsepTransportController::NeedsIceRestart(
203 const std::string& transport_name) const {
Zhi Huang365381f2018-04-13 16:44:34 -0700204 const cricket::JsepTransport* transport =
Zhi Huange830e682018-03-30 10:48:35 -0700205 GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800206 if (!transport) {
207 return false;
208 }
209 return transport->needs_ice_restart();
210}
211
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200212absl::optional<rtc::SSLRole> JsepTransportController::GetDtlsRole(
Zhi Huange830e682018-03-30 10:48:35 -0700213 const std::string& mid) const {
Zhi Huange818b6e2018-02-22 15:26:27 -0800214 if (!network_thread_->IsCurrent()) {
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200215 return network_thread_->Invoke<absl::optional<rtc::SSLRole>>(
Zhi Huange830e682018-03-30 10:48:35 -0700216 RTC_FROM_HERE, [&] { return GetDtlsRole(mid); });
Zhi Huange818b6e2018-02-22 15:26:27 -0800217 }
218
Zhi Huang365381f2018-04-13 16:44:34 -0700219 const cricket::JsepTransport* t = GetJsepTransportForMid(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -0800220 if (!t) {
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200221 return absl::optional<rtc::SSLRole>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800222 }
223 return t->GetDtlsRole();
224}
225
226bool JsepTransportController::SetLocalCertificate(
227 const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) {
228 if (!network_thread_->IsCurrent()) {
229 return network_thread_->Invoke<bool>(
230 RTC_FROM_HERE, [&] { return SetLocalCertificate(certificate); });
231 }
232
233 // Can't change a certificate, or set a null certificate.
234 if (certificate_ || !certificate) {
235 return false;
236 }
237 certificate_ = certificate;
238
239 // Set certificate for JsepTransport, which verifies it matches the
240 // fingerprint in SDP, and DTLS transport.
241 // Fallback from DTLS to SDES is not supported.
Zhi Huange830e682018-03-30 10:48:35 -0700242 for (auto& kv : jsep_transports_by_name_) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800243 kv.second->SetLocalCertificate(certificate_);
244 }
245 for (auto& dtls : GetDtlsTransports()) {
246 bool set_cert_success = dtls->SetLocalCertificate(certificate_);
247 RTC_DCHECK(set_cert_success);
248 }
249 return true;
250}
251
252rtc::scoped_refptr<rtc::RTCCertificate>
253JsepTransportController::GetLocalCertificate(
254 const std::string& transport_name) const {
255 if (!network_thread_->IsCurrent()) {
256 return network_thread_->Invoke<rtc::scoped_refptr<rtc::RTCCertificate>>(
257 RTC_FROM_HERE, [&] { return GetLocalCertificate(transport_name); });
258 }
259
Zhi Huang365381f2018-04-13 16:44:34 -0700260 const cricket::JsepTransport* t = GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800261 if (!t) {
262 return nullptr;
263 }
264 return t->GetLocalCertificate();
265}
266
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800267std::unique_ptr<rtc::SSLCertChain>
268JsepTransportController::GetRemoteSSLCertChain(
Zhi Huange818b6e2018-02-22 15:26:27 -0800269 const std::string& transport_name) const {
270 if (!network_thread_->IsCurrent()) {
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800271 return network_thread_->Invoke<std::unique_ptr<rtc::SSLCertChain>>(
272 RTC_FROM_HERE, [&] { return GetRemoteSSLCertChain(transport_name); });
Zhi Huange818b6e2018-02-22 15:26:27 -0800273 }
274
Zhi Huange830e682018-03-30 10:48:35 -0700275 // Get the certificate from the RTP transport's DTLS handshake. Should be
276 // identical to the RTCP transport's, since they were given the same remote
Zhi Huange818b6e2018-02-22 15:26:27 -0800277 // fingerprint.
Zhi Huange830e682018-03-30 10:48:35 -0700278 auto jsep_transport = GetJsepTransportByName(transport_name);
279 if (!jsep_transport) {
280 return nullptr;
281 }
282 auto dtls = jsep_transport->rtp_dtls_transport();
Zhi Huange818b6e2018-02-22 15:26:27 -0800283 if (!dtls) {
284 return nullptr;
285 }
286
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800287 return dtls->GetRemoteSSLCertChain();
Zhi Huange818b6e2018-02-22 15:26:27 -0800288}
289
290void JsepTransportController::MaybeStartGathering() {
291 if (!network_thread_->IsCurrent()) {
292 network_thread_->Invoke<void>(RTC_FROM_HERE,
293 [&] { MaybeStartGathering(); });
294 return;
295 }
296
297 for (auto& dtls : GetDtlsTransports()) {
298 dtls->ice_transport()->MaybeStartGathering();
299 }
300}
301
302RTCError JsepTransportController::AddRemoteCandidates(
303 const std::string& transport_name,
304 const cricket::Candidates& candidates) {
305 if (!network_thread_->IsCurrent()) {
306 return network_thread_->Invoke<RTCError>(RTC_FROM_HERE, [&] {
307 return AddRemoteCandidates(transport_name, candidates);
308 });
309 }
310
311 // Verify each candidate before passing down to the transport layer.
312 RTCError error = VerifyCandidates(candidates);
313 if (!error.ok()) {
314 return error;
315 }
Zhi Huange830e682018-03-30 10:48:35 -0700316 auto jsep_transport = GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800317 if (!jsep_transport) {
Zhi Huange830e682018-03-30 10:48:35 -0700318 RTC_LOG(LS_WARNING) << "Not adding candidate because the JsepTransport "
319 "doesn't exist. Ignore it.";
320 return RTCError::OK();
Zhi Huange818b6e2018-02-22 15:26:27 -0800321 }
Zhi Huange818b6e2018-02-22 15:26:27 -0800322 return jsep_transport->AddRemoteCandidates(candidates);
323}
324
325RTCError JsepTransportController::RemoveRemoteCandidates(
326 const cricket::Candidates& candidates) {
327 if (!network_thread_->IsCurrent()) {
328 return network_thread_->Invoke<RTCError>(
329 RTC_FROM_HERE, [&] { return RemoveRemoteCandidates(candidates); });
330 }
331
332 // Verify each candidate before passing down to the transport layer.
333 RTCError error = VerifyCandidates(candidates);
334 if (!error.ok()) {
335 return error;
336 }
337
338 std::map<std::string, cricket::Candidates> candidates_by_transport_name;
339 for (const cricket::Candidate& cand : candidates) {
340 if (!cand.transport_name().empty()) {
341 candidates_by_transport_name[cand.transport_name()].push_back(cand);
342 } else {
343 RTC_LOG(LS_ERROR) << "Not removing candidate because it does not have a "
344 "transport name set: "
345 << cand.ToString();
346 }
347 }
348
349 for (const auto& kv : candidates_by_transport_name) {
350 const std::string& transport_name = kv.first;
351 const cricket::Candidates& candidates = kv.second;
Zhi Huang365381f2018-04-13 16:44:34 -0700352 cricket::JsepTransport* jsep_transport =
Zhi Huange830e682018-03-30 10:48:35 -0700353 GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800354 if (!jsep_transport) {
Zhi Huange830e682018-03-30 10:48:35 -0700355 RTC_LOG(LS_WARNING)
356 << "Not removing candidate because the JsepTransport doesn't exist.";
357 continue;
Zhi Huange818b6e2018-02-22 15:26:27 -0800358 }
359 for (const cricket::Candidate& candidate : candidates) {
Harald Alvestrandad88c882018-11-28 16:47:46 +0100360 cricket::DtlsTransportInternal* dtls =
361 candidate.component() == cricket::ICE_CANDIDATE_COMPONENT_RTP
362 ? jsep_transport->rtp_dtls_transport()
363 : jsep_transport->rtcp_dtls_transport();
Zhi Huange818b6e2018-02-22 15:26:27 -0800364 if (dtls) {
365 dtls->ice_transport()->RemoveRemoteCandidate(candidate);
366 }
367 }
368 }
369 return RTCError::OK();
370}
371
372bool JsepTransportController::GetStats(const std::string& transport_name,
373 cricket::TransportStats* stats) {
374 if (!network_thread_->IsCurrent()) {
375 return network_thread_->Invoke<bool>(
376 RTC_FROM_HERE, [=] { return GetStats(transport_name, stats); });
377 }
378
Zhi Huang365381f2018-04-13 16:44:34 -0700379 cricket::JsepTransport* transport = GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800380 if (!transport) {
381 return false;
382 }
383 return transport->GetStats(stats);
384}
385
Zhi Huangb57e1692018-06-12 11:41:11 -0700386void JsepTransportController::SetActiveResetSrtpParams(
387 bool active_reset_srtp_params) {
388 if (!network_thread_->IsCurrent()) {
389 network_thread_->Invoke<void>(RTC_FROM_HERE, [=] {
390 SetActiveResetSrtpParams(active_reset_srtp_params);
391 });
392 return;
393 }
394
395 RTC_LOG(INFO)
396 << "Updating the active_reset_srtp_params for JsepTransportController: "
397 << active_reset_srtp_params;
398 config_.active_reset_srtp_params = active_reset_srtp_params;
399 for (auto& kv : jsep_transports_by_name_) {
400 kv.second->SetActiveResetSrtpParams(active_reset_srtp_params);
401 }
402}
403
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800404void JsepTransportController::SetMediaTransportSettings(
405 bool use_media_transport_for_media,
406 bool use_media_transport_for_data_channels) {
407 RTC_DCHECK(use_media_transport_for_media ==
408 config_.use_media_transport_for_media ||
Piotr (Peter) Slatala97fc11f2018-10-18 12:57:59 -0700409 jsep_transports_by_name_.empty())
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800410 << "You can only change media transport configuration before creating "
411 "the first transport.";
412
413 RTC_DCHECK(use_media_transport_for_data_channels ==
414 config_.use_media_transport_for_data_channels ||
415 jsep_transports_by_name_.empty())
416 << "You can only change media transport configuration before creating "
417 "the first transport.";
418
419 config_.use_media_transport_for_media = use_media_transport_for_media;
420 config_.use_media_transport_for_data_channels =
421 use_media_transport_for_data_channels;
Piotr (Peter) Slatala97fc11f2018-10-18 12:57:59 -0700422}
423
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800424std::unique_ptr<cricket::IceTransportInternal>
425JsepTransportController::CreateIceTransport(const std::string transport_name,
426 bool rtcp) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800427 int component = rtcp ? cricket::ICE_CANDIDATE_COMPONENT_RTCP
428 : cricket::ICE_CANDIDATE_COMPONENT_RTP;
429
Zhi Huange818b6e2018-02-22 15:26:27 -0800430 if (config_.external_transport_factory) {
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800431 return config_.external_transport_factory->CreateIceTransport(
Zhi Huange818b6e2018-02-22 15:26:27 -0800432 transport_name, component);
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800433 } else {
434 return absl::make_unique<cricket::P2PTransportChannel>(
435 transport_name, component, port_allocator_, async_resolver_factory_,
436 config_.event_log);
437 }
438}
439
440std::unique_ptr<cricket::DtlsTransportInternal>
441JsepTransportController::CreateDtlsTransport(
442 std::unique_ptr<cricket::IceTransportInternal> ice) {
443 RTC_DCHECK(network_thread_->IsCurrent());
444
445 std::unique_ptr<cricket::DtlsTransportInternal> dtls;
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800446 // If media transport is used for both media and data channels,
447 // then we don't need to create DTLS.
448 // Otherwise, DTLS is still created.
Niels Möllerabea6e52019-03-08 14:49:32 +0100449 if (config_.media_transport_factory &&
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800450 config_.use_media_transport_for_media &&
451 config_.use_media_transport_for_data_channels) {
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800452 dtls = absl::make_unique<cricket::NoOpDtlsTransport>(
453 std::move(ice), config_.crypto_options);
454 } else if (config_.external_transport_factory) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800455 dtls = config_.external_transport_factory->CreateDtlsTransport(
456 std::move(ice), config_.crypto_options);
457 } else {
Zach Steinc64078f2018-11-27 15:53:01 -0800458 dtls = absl::make_unique<cricket::DtlsTransport>(
459 std::move(ice), config_.crypto_options, config_.event_log);
Zhi Huange818b6e2018-02-22 15:26:27 -0800460 }
461
462 RTC_DCHECK(dtls);
463 dtls->SetSslMaxProtocolVersion(config_.ssl_max_version);
Zhi Huange818b6e2018-02-22 15:26:27 -0800464 dtls->ice_transport()->SetIceRole(ice_role_);
465 dtls->ice_transport()->SetIceTiebreaker(ice_tiebreaker_);
466 dtls->ice_transport()->SetIceConfig(ice_config_);
467 if (certificate_) {
468 bool set_cert_success = dtls->SetLocalCertificate(certificate_);
469 RTC_DCHECK(set_cert_success);
470 }
471
472 // Connect to signals offered by the DTLS and ICE transport.
473 dtls->SignalWritableState.connect(
474 this, &JsepTransportController::OnTransportWritableState_n);
475 dtls->SignalReceivingState.connect(
476 this, &JsepTransportController::OnTransportReceivingState_n);
477 dtls->SignalDtlsHandshakeError.connect(
478 this, &JsepTransportController::OnDtlsHandshakeError);
479 dtls->ice_transport()->SignalGatheringState.connect(
480 this, &JsepTransportController::OnTransportGatheringState_n);
481 dtls->ice_transport()->SignalCandidateGathered.connect(
482 this, &JsepTransportController::OnTransportCandidateGathered_n);
483 dtls->ice_transport()->SignalCandidatesRemoved.connect(
484 this, &JsepTransportController::OnTransportCandidatesRemoved_n);
485 dtls->ice_transport()->SignalRoleConflict.connect(
486 this, &JsepTransportController::OnTransportRoleConflict_n);
487 dtls->ice_transport()->SignalStateChanged.connect(
488 this, &JsepTransportController::OnTransportStateChanged_n);
Jonas Olsson7a6739e2019-01-15 16:31:55 +0100489 dtls->ice_transport()->SignalIceTransportStateChanged.connect(
490 this, &JsepTransportController::OnTransportStateChanged_n);
Zhi Huange818b6e2018-02-22 15:26:27 -0800491 return dtls;
492}
493
494std::unique_ptr<webrtc::RtpTransport>
495JsepTransportController::CreateUnencryptedRtpTransport(
496 const std::string& transport_name,
497 rtc::PacketTransportInternal* rtp_packet_transport,
498 rtc::PacketTransportInternal* rtcp_packet_transport) {
499 RTC_DCHECK(network_thread_->IsCurrent());
Zhi Huange830e682018-03-30 10:48:35 -0700500 auto unencrypted_rtp_transport =
Karl Wiberg918f50c2018-07-05 11:40:33 +0200501 absl::make_unique<RtpTransport>(rtcp_packet_transport == nullptr);
Zhi Huange830e682018-03-30 10:48:35 -0700502 unencrypted_rtp_transport->SetRtpPacketTransport(rtp_packet_transport);
503 if (rtcp_packet_transport) {
504 unencrypted_rtp_transport->SetRtcpPacketTransport(rtcp_packet_transport);
505 }
506 return unencrypted_rtp_transport;
Zhi Huange818b6e2018-02-22 15:26:27 -0800507}
508
509std::unique_ptr<webrtc::SrtpTransport>
510JsepTransportController::CreateSdesTransport(
511 const std::string& transport_name,
Zhi Huange830e682018-03-30 10:48:35 -0700512 cricket::DtlsTransportInternal* rtp_dtls_transport,
513 cricket::DtlsTransportInternal* rtcp_dtls_transport) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800514 RTC_DCHECK(network_thread_->IsCurrent());
Zhi Huange818b6e2018-02-22 15:26:27 -0800515 auto srtp_transport =
Karl Wiberg918f50c2018-07-05 11:40:33 +0200516 absl::make_unique<webrtc::SrtpTransport>(rtcp_dtls_transport == nullptr);
Zhi Huange830e682018-03-30 10:48:35 -0700517 RTC_DCHECK(rtp_dtls_transport);
518 srtp_transport->SetRtpPacketTransport(rtp_dtls_transport);
519 if (rtcp_dtls_transport) {
520 srtp_transport->SetRtcpPacketTransport(rtcp_dtls_transport);
Zhi Huange818b6e2018-02-22 15:26:27 -0800521 }
522 if (config_.enable_external_auth) {
523 srtp_transport->EnableExternalAuth();
524 }
525 return srtp_transport;
526}
527
528std::unique_ptr<webrtc::DtlsSrtpTransport>
529JsepTransportController::CreateDtlsSrtpTransport(
530 const std::string& transport_name,
531 cricket::DtlsTransportInternal* rtp_dtls_transport,
532 cricket::DtlsTransportInternal* rtcp_dtls_transport) {
533 RTC_DCHECK(network_thread_->IsCurrent());
Karl Wiberg918f50c2018-07-05 11:40:33 +0200534 auto dtls_srtp_transport = absl::make_unique<webrtc::DtlsSrtpTransport>(
Zhi Huang365381f2018-04-13 16:44:34 -0700535 rtcp_dtls_transport == nullptr);
Zhi Huang27f3bf52018-03-26 21:37:23 -0700536 if (config_.enable_external_auth) {
Zhi Huang365381f2018-04-13 16:44:34 -0700537 dtls_srtp_transport->EnableExternalAuth();
Zhi Huang27f3bf52018-03-26 21:37:23 -0700538 }
Zhi Huang97d5e5b2018-03-27 00:09:01 +0000539
Zhi Huange818b6e2018-02-22 15:26:27 -0800540 dtls_srtp_transport->SetDtlsTransports(rtp_dtls_transport,
541 rtcp_dtls_transport);
Zhi Huangb57e1692018-06-12 11:41:11 -0700542 dtls_srtp_transport->SetActiveResetSrtpParams(
543 config_.active_reset_srtp_params);
Jonas Olsson635474e2018-10-18 15:58:17 +0200544 dtls_srtp_transport->SignalDtlsStateChange.connect(
545 this, &JsepTransportController::UpdateAggregateStates_n);
Zhi Huange818b6e2018-02-22 15:26:27 -0800546 return dtls_srtp_transport;
547}
548
549std::vector<cricket::DtlsTransportInternal*>
550JsepTransportController::GetDtlsTransports() {
551 std::vector<cricket::DtlsTransportInternal*> dtls_transports;
Zhi Huange830e682018-03-30 10:48:35 -0700552 for (auto it = jsep_transports_by_name_.begin();
553 it != jsep_transports_by_name_.end(); ++it) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800554 auto jsep_transport = it->second.get();
555 RTC_DCHECK(jsep_transport);
556 if (jsep_transport->rtp_dtls_transport()) {
557 dtls_transports.push_back(jsep_transport->rtp_dtls_transport());
558 }
559
560 if (jsep_transport->rtcp_dtls_transport()) {
561 dtls_transports.push_back(jsep_transport->rtcp_dtls_transport());
562 }
563 }
564 return dtls_transports;
565}
566
Zhi Huange818b6e2018-02-22 15:26:27 -0800567RTCError JsepTransportController::ApplyDescription_n(
568 bool local,
569 SdpType type,
570 const cricket::SessionDescription* description) {
571 RTC_DCHECK(network_thread_->IsCurrent());
572 RTC_DCHECK(description);
573
574 if (local) {
575 local_desc_ = description;
576 } else {
577 remote_desc_ = description;
578 }
579
Zhi Huange830e682018-03-30 10:48:35 -0700580 RTCError error;
Zhi Huangd2248f82018-04-10 14:41:03 -0700581 error = ValidateAndMaybeUpdateBundleGroup(local, type, description);
Zhi Huange830e682018-03-30 10:48:35 -0700582 if (!error.ok()) {
583 return error;
Zhi Huange818b6e2018-02-22 15:26:27 -0800584 }
585
586 std::vector<int> merged_encrypted_extension_ids;
587 if (bundle_group_) {
588 merged_encrypted_extension_ids =
589 MergeEncryptedHeaderExtensionIdsForBundle(description);
590 }
591
592 for (const cricket::ContentInfo& content_info : description->contents()) {
593 // Don't create transports for rejected m-lines and bundled m-lines."
594 if (content_info.rejected ||
595 (IsBundled(content_info.name) && content_info.name != *bundled_mid())) {
596 continue;
597 }
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -0800598 error = MaybeCreateJsepTransport(local, content_info, *description);
Zhi Huange830e682018-03-30 10:48:35 -0700599 if (!error.ok()) {
600 return error;
601 }
Zhi Huange818b6e2018-02-22 15:26:27 -0800602 }
603
604 RTC_DCHECK(description->contents().size() ==
605 description->transport_infos().size());
606 for (size_t i = 0; i < description->contents().size(); ++i) {
607 const cricket::ContentInfo& content_info = description->contents()[i];
608 const cricket::TransportInfo& transport_info =
609 description->transport_infos()[i];
610 if (content_info.rejected) {
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700611 HandleRejectedContent(content_info, description);
Zhi Huange818b6e2018-02-22 15:26:27 -0800612 continue;
613 }
614
615 if (IsBundled(content_info.name) && content_info.name != *bundled_mid()) {
Zhi Huang365381f2018-04-13 16:44:34 -0700616 if (!HandleBundledContent(content_info)) {
617 return RTCError(RTCErrorType::INVALID_PARAMETER,
618 "Failed to process the bundled m= section.");
619 }
Zhi Huange818b6e2018-02-22 15:26:27 -0800620 continue;
621 }
622
Zhi Huange830e682018-03-30 10:48:35 -0700623 error = ValidateContent(content_info);
624 if (!error.ok()) {
625 return error;
626 }
627
Zhi Huange818b6e2018-02-22 15:26:27 -0800628 std::vector<int> extension_ids;
Taylor Brandstetter0ab56512018-04-12 10:30:48 -0700629 if (bundled_mid() && content_info.name == *bundled_mid()) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800630 extension_ids = merged_encrypted_extension_ids;
631 } else {
632 extension_ids = GetEncryptedHeaderExtensionIds(content_info);
633 }
634
Zhi Huange830e682018-03-30 10:48:35 -0700635 int rtp_abs_sendtime_extn_id =
636 GetRtpAbsSendTimeHeaderExtensionId(content_info);
637
Zhi Huang365381f2018-04-13 16:44:34 -0700638 cricket::JsepTransport* transport =
Zhi Huange830e682018-03-30 10:48:35 -0700639 GetJsepTransportForMid(content_info.name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800640 RTC_DCHECK(transport);
641
642 SetIceRole_n(DetermineIceRole(transport, transport_info, type, local));
643
Zhi Huange818b6e2018-02-22 15:26:27 -0800644 cricket::JsepTransportDescription jsep_description =
645 CreateJsepTransportDescription(content_info, transport_info,
Zhi Huange830e682018-03-30 10:48:35 -0700646 extension_ids, rtp_abs_sendtime_extn_id);
Zhi Huange818b6e2018-02-22 15:26:27 -0800647 if (local) {
648 error =
649 transport->SetLocalJsepTransportDescription(jsep_description, type);
650 } else {
651 error =
652 transport->SetRemoteJsepTransportDescription(jsep_description, type);
653 }
654
655 if (!error.ok()) {
656 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
657 "Failed to apply the description for " +
658 content_info.name + ": " + error.message());
659 }
660 }
661 return RTCError::OK();
662}
663
Zhi Huangd2248f82018-04-10 14:41:03 -0700664RTCError JsepTransportController::ValidateAndMaybeUpdateBundleGroup(
665 bool local,
666 SdpType type,
Zhi Huange830e682018-03-30 10:48:35 -0700667 const cricket::SessionDescription* description) {
668 RTC_DCHECK(description);
Zhi Huangd2248f82018-04-10 14:41:03 -0700669 const cricket::ContentGroup* new_bundle_group =
670 description->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
671
672 // The BUNDLE group containing a MID that no m= section has is invalid.
673 if (new_bundle_group) {
Mirko Bonadei739baf02019-01-27 17:29:42 +0100674 for (const auto& content_name : new_bundle_group->content_names()) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700675 if (!description->GetContentByName(content_name)) {
676 return RTCError(RTCErrorType::INVALID_PARAMETER,
677 "The BUNDLE group contains MID:" + content_name +
678 " matching no m= section.");
679 }
680 }
681 }
682
683 if (type == SdpType::kAnswer) {
684 const cricket::ContentGroup* offered_bundle_group =
685 local ? remote_desc_->GetGroupByName(cricket::GROUP_TYPE_BUNDLE)
686 : local_desc_->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
687
688 if (new_bundle_group) {
689 // The BUNDLE group in answer should be a subset of offered group.
Mirko Bonadei739baf02019-01-27 17:29:42 +0100690 for (const auto& content_name : new_bundle_group->content_names()) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700691 if (!offered_bundle_group ||
692 !offered_bundle_group->HasContentName(content_name)) {
693 return RTCError(RTCErrorType::INVALID_PARAMETER,
694 "The BUNDLE group in answer contains a MID that was "
695 "not in the offered group.");
696 }
697 }
698 }
699
700 if (bundle_group_) {
Mirko Bonadei739baf02019-01-27 17:29:42 +0100701 for (const auto& content_name : bundle_group_->content_names()) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700702 // An answer that removes m= sections from pre-negotiated BUNDLE group
703 // without rejecting it, is invalid.
704 if (!new_bundle_group ||
705 !new_bundle_group->HasContentName(content_name)) {
706 auto* content_info = description->GetContentByName(content_name);
707 if (!content_info || !content_info->rejected) {
708 return RTCError(RTCErrorType::INVALID_PARAMETER,
709 "Answer cannot remove m= section " + content_name +
710 " from already-established BUNDLE group.");
711 }
712 }
713 }
714 }
715 }
716
717 if (config_.bundle_policy ==
718 PeerConnectionInterface::kBundlePolicyMaxBundle &&
719 !description->HasGroup(cricket::GROUP_TYPE_BUNDLE)) {
720 return RTCError(RTCErrorType::INVALID_PARAMETER,
721 "max-bundle is used but no bundle group found.");
722 }
723
724 if (ShouldUpdateBundleGroup(type, description)) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700725 bundle_group_ = *new_bundle_group;
726 }
Zhi Huange830e682018-03-30 10:48:35 -0700727
728 if (!bundled_mid()) {
729 return RTCError::OK();
730 }
731
732 auto bundled_content = description->GetContentByName(*bundled_mid());
733 if (!bundled_content) {
734 return RTCError(
735 RTCErrorType::INVALID_PARAMETER,
736 "An m= section associated with the BUNDLE-tag doesn't exist.");
737 }
738
739 // If the |bundled_content| is rejected, other contents in the bundle group
740 // should be rejected.
741 if (bundled_content->rejected) {
Mirko Bonadei739baf02019-01-27 17:29:42 +0100742 for (const auto& content_name : bundle_group_->content_names()) {
Zhi Huange830e682018-03-30 10:48:35 -0700743 auto other_content = description->GetContentByName(content_name);
744 if (!other_content->rejected) {
745 return RTCError(
746 RTCErrorType::INVALID_PARAMETER,
747 "The m= section:" + content_name + " should be rejected.");
748 }
749 }
750 }
751
752 return RTCError::OK();
753}
754
755RTCError JsepTransportController::ValidateContent(
756 const cricket::ContentInfo& content_info) {
757 if (config_.rtcp_mux_policy ==
758 PeerConnectionInterface::kRtcpMuxPolicyRequire &&
759 content_info.type == cricket::MediaProtocolType::kRtp &&
760 !content_info.media_description()->rtcp_mux()) {
761 return RTCError(RTCErrorType::INVALID_PARAMETER,
762 "The m= section:" + content_info.name +
763 " is invalid. RTCP-MUX is not "
764 "enabled when it is required.");
765 }
766 return RTCError::OK();
767}
768
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700769void JsepTransportController::HandleRejectedContent(
Zhi Huangd2248f82018-04-10 14:41:03 -0700770 const cricket::ContentInfo& content_info,
771 const cricket::SessionDescription* description) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800772 // If the content is rejected, let the
773 // BaseChannel/SctpTransport change the RtpTransport/DtlsTransport first,
Zhi Huang365381f2018-04-13 16:44:34 -0700774 // then destroy the cricket::JsepTransport.
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700775 RemoveTransportForMid(content_info.name);
Zhi Huange830e682018-03-30 10:48:35 -0700776 if (content_info.name == bundled_mid()) {
Mirko Bonadei739baf02019-01-27 17:29:42 +0100777 for (const auto& content_name : bundle_group_->content_names()) {
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700778 RemoveTransportForMid(content_name);
Zhi Huange830e682018-03-30 10:48:35 -0700779 }
780 bundle_group_.reset();
781 } else if (IsBundled(content_info.name)) {
782 // Remove the rejected content from the |bundle_group_|.
Zhi Huange818b6e2018-02-22 15:26:27 -0800783 bundle_group_->RemoveContentName(content_info.name);
Zhi Huange830e682018-03-30 10:48:35 -0700784 // Reset the bundle group if nothing left.
785 if (!bundle_group_->FirstContentName()) {
786 bundle_group_.reset();
787 }
Zhi Huange818b6e2018-02-22 15:26:27 -0800788 }
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700789 MaybeDestroyJsepTransport(content_info.name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800790}
791
Zhi Huang365381f2018-04-13 16:44:34 -0700792bool JsepTransportController::HandleBundledContent(
Zhi Huange818b6e2018-02-22 15:26:27 -0800793 const cricket::ContentInfo& content_info) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700794 auto jsep_transport = GetJsepTransportByName(*bundled_mid());
795 RTC_DCHECK(jsep_transport);
Zhi Huange818b6e2018-02-22 15:26:27 -0800796 // If the content is bundled, let the
797 // BaseChannel/SctpTransport change the RtpTransport/DtlsTransport first,
Zhi Huang365381f2018-04-13 16:44:34 -0700798 // then destroy the cricket::JsepTransport.
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700799 if (SetTransportForMid(content_info.name, jsep_transport)) {
Piotr (Peter) Slatala10aeb2a2018-11-14 10:57:24 -0800800 // TODO(bugs.webrtc.org/9719) For media transport this is far from ideal,
801 // because it means that we first create media transport and start
802 // connecting it, and then we destroy it. We will need to address it before
803 // video path is enabled.
Zhi Huang365381f2018-04-13 16:44:34 -0700804 MaybeDestroyJsepTransport(content_info.name);
805 return true;
806 }
807 return false;
Zhi Huange818b6e2018-02-22 15:26:27 -0800808}
809
Zhi Huang365381f2018-04-13 16:44:34 -0700810bool JsepTransportController::SetTransportForMid(
Zhi Huangd2248f82018-04-10 14:41:03 -0700811 const std::string& mid,
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700812 cricket::JsepTransport* jsep_transport) {
Zhi Huang365381f2018-04-13 16:44:34 -0700813 RTC_DCHECK(jsep_transport);
Zhi Huangd2248f82018-04-10 14:41:03 -0700814 if (mid_to_transport_[mid] == jsep_transport) {
Zhi Huang365381f2018-04-13 16:44:34 -0700815 return true;
Zhi Huangd2248f82018-04-10 14:41:03 -0700816 }
817
818 mid_to_transport_[mid] = jsep_transport;
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700819 return config_.transport_observer->OnTransportChanged(
Harald Alvestrandc85328f2019-02-28 07:51:00 +0100820 mid, jsep_transport->rtp_transport(), jsep_transport->RtpDtlsTransport(),
821 jsep_transport->media_transport());
Zhi Huangd2248f82018-04-10 14:41:03 -0700822}
823
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700824void JsepTransportController::RemoveTransportForMid(const std::string& mid) {
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -0800825 bool ret = config_.transport_observer->OnTransportChanged(mid, nullptr,
826 nullptr, nullptr);
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700827 // Calling OnTransportChanged with nullptr should always succeed, since it is
828 // only expected to fail when adding media to a transport (not removing).
829 RTC_DCHECK(ret);
Zhi Huangd2248f82018-04-10 14:41:03 -0700830 mid_to_transport_.erase(mid);
831}
832
Zhi Huange818b6e2018-02-22 15:26:27 -0800833cricket::JsepTransportDescription
834JsepTransportController::CreateJsepTransportDescription(
835 cricket::ContentInfo content_info,
836 cricket::TransportInfo transport_info,
Zhi Huange830e682018-03-30 10:48:35 -0700837 const std::vector<int>& encrypted_extension_ids,
838 int rtp_abs_sendtime_extn_id) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800839 const cricket::MediaContentDescription* content_desc =
840 static_cast<const cricket::MediaContentDescription*>(
841 content_info.description);
842 RTC_DCHECK(content_desc);
843 bool rtcp_mux_enabled = content_info.type == cricket::MediaProtocolType::kSctp
844 ? true
845 : content_desc->rtcp_mux();
846
847 return cricket::JsepTransportDescription(
848 rtcp_mux_enabled, content_desc->cryptos(), encrypted_extension_ids,
Zhi Huange830e682018-03-30 10:48:35 -0700849 rtp_abs_sendtime_extn_id, transport_info.description);
Zhi Huange818b6e2018-02-22 15:26:27 -0800850}
851
852bool JsepTransportController::ShouldUpdateBundleGroup(
853 SdpType type,
854 const cricket::SessionDescription* description) {
855 if (config_.bundle_policy ==
856 PeerConnectionInterface::kBundlePolicyMaxBundle) {
857 return true;
858 }
859
860 if (type != SdpType::kAnswer) {
861 return false;
862 }
863
864 RTC_DCHECK(local_desc_ && remote_desc_);
865 const cricket::ContentGroup* local_bundle =
866 local_desc_->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
867 const cricket::ContentGroup* remote_bundle =
868 remote_desc_->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
869 return local_bundle && remote_bundle;
870}
871
872std::vector<int> JsepTransportController::GetEncryptedHeaderExtensionIds(
873 const cricket::ContentInfo& content_info) {
874 const cricket::MediaContentDescription* content_desc =
875 static_cast<const cricket::MediaContentDescription*>(
876 content_info.description);
877
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700878 if (!config_.crypto_options.srtp.enable_encrypted_rtp_header_extensions) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800879 return std::vector<int>();
880 }
881
882 std::vector<int> encrypted_header_extension_ids;
Mirko Bonadei739baf02019-01-27 17:29:42 +0100883 for (const auto& extension : content_desc->rtp_header_extensions()) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800884 if (!extension.encrypt) {
885 continue;
886 }
Steve Anton64b626b2019-01-28 17:25:26 -0800887 if (!absl::c_linear_search(encrypted_header_extension_ids, extension.id)) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800888 encrypted_header_extension_ids.push_back(extension.id);
889 }
890 }
891 return encrypted_header_extension_ids;
892}
893
894std::vector<int>
895JsepTransportController::MergeEncryptedHeaderExtensionIdsForBundle(
896 const cricket::SessionDescription* description) {
897 RTC_DCHECK(description);
898 RTC_DCHECK(bundle_group_);
899
900 std::vector<int> merged_ids;
901 // Union the encrypted header IDs in the group when bundle is enabled.
902 for (const cricket::ContentInfo& content_info : description->contents()) {
903 if (bundle_group_->HasContentName(content_info.name)) {
904 std::vector<int> extension_ids =
905 GetEncryptedHeaderExtensionIds(content_info);
906 for (int id : extension_ids) {
Steve Anton64b626b2019-01-28 17:25:26 -0800907 if (!absl::c_linear_search(merged_ids, id)) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800908 merged_ids.push_back(id);
909 }
910 }
911 }
912 }
913 return merged_ids;
914}
915
Zhi Huange830e682018-03-30 10:48:35 -0700916int JsepTransportController::GetRtpAbsSendTimeHeaderExtensionId(
Zhi Huange818b6e2018-02-22 15:26:27 -0800917 const cricket::ContentInfo& content_info) {
Zhi Huange830e682018-03-30 10:48:35 -0700918 if (!config_.enable_external_auth) {
919 return -1;
Zhi Huange818b6e2018-02-22 15:26:27 -0800920 }
921
922 const cricket::MediaContentDescription* content_desc =
923 static_cast<const cricket::MediaContentDescription*>(
924 content_info.description);
Zhi Huange830e682018-03-30 10:48:35 -0700925
926 const webrtc::RtpExtension* send_time_extension =
927 webrtc::RtpExtension::FindHeaderExtensionByUri(
928 content_desc->rtp_header_extensions(),
929 webrtc::RtpExtension::kAbsSendTimeUri);
930 return send_time_extension ? send_time_extension->id : -1;
931}
932
Zhi Huang365381f2018-04-13 16:44:34 -0700933const cricket::JsepTransport* JsepTransportController::GetJsepTransportForMid(
Zhi Huange830e682018-03-30 10:48:35 -0700934 const std::string& mid) const {
Zhi Huangd2248f82018-04-10 14:41:03 -0700935 auto it = mid_to_transport_.find(mid);
936 return it == mid_to_transport_.end() ? nullptr : it->second;
Zhi Huange830e682018-03-30 10:48:35 -0700937}
938
Zhi Huang365381f2018-04-13 16:44:34 -0700939cricket::JsepTransport* JsepTransportController::GetJsepTransportForMid(
Zhi Huange830e682018-03-30 10:48:35 -0700940 const std::string& mid) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700941 auto it = mid_to_transport_.find(mid);
942 return it == mid_to_transport_.end() ? nullptr : it->second;
Zhi Huange830e682018-03-30 10:48:35 -0700943}
944
Zhi Huang365381f2018-04-13 16:44:34 -0700945const cricket::JsepTransport* JsepTransportController::GetJsepTransportByName(
Zhi Huange830e682018-03-30 10:48:35 -0700946 const std::string& transport_name) const {
947 auto it = jsep_transports_by_name_.find(transport_name);
948 return (it == jsep_transports_by_name_.end()) ? nullptr : it->second.get();
949}
950
Zhi Huang365381f2018-04-13 16:44:34 -0700951cricket::JsepTransport* JsepTransportController::GetJsepTransportByName(
Zhi Huange830e682018-03-30 10:48:35 -0700952 const std::string& transport_name) {
953 auto it = jsep_transports_by_name_.find(transport_name);
954 return (it == jsep_transports_by_name_.end()) ? nullptr : it->second.get();
955}
956
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -0800957std::unique_ptr<webrtc::MediaTransportInterface>
958JsepTransportController::MaybeCreateMediaTransport(
959 const cricket::ContentInfo& content_info,
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -0800960 const cricket::SessionDescription& description,
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800961 bool local) {
Piotr (Peter) Slatala63a176b2019-01-25 08:25:33 -0800962 if (config_.media_transport_factory == nullptr) {
963 return nullptr;
964 }
965
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800966 if (!config_.use_media_transport_for_media &&
967 !config_.use_media_transport_for_data_channels) {
968 return nullptr;
969 }
970
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800971 // Caller (offerer) media transport.
972 if (local) {
973 if (offer_media_transport_) {
974 RTC_LOG(LS_INFO) << "Offered media transport has now been activated.";
975 return std::move(offer_media_transport_);
976 } else {
977 RTC_LOG(LS_INFO)
978 << "Not returning media transport. Either SDES wasn't enabled, or "
979 "media transport didn't return an offer earlier.";
980 // Offer wasn't generated. Either because media transport didn't want it,
981 // or because SDES wasn't enabled.
982 return nullptr;
983 }
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700984 }
985
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800986 // Remote offer. If no x-mt lines, do not create media transport.
987 if (description.MediaTransportSettings().empty()) {
Piotr (Peter) Slatala63a176b2019-01-25 08:25:33 -0800988 return nullptr;
Anton Sukhanov7940da02018-10-10 10:34:49 -0700989 }
990
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800991 // When bundle is enabled, two JsepTransports are created, and then
992 // the second transport is destroyed (right away).
993 // For media transport, we don't want to create the second
994 // media transport in the first place.
995 RTC_LOG(LS_INFO) << "Returning new, client media transport.";
Piotr (Peter) Slatala63a176b2019-01-25 08:25:33 -0800996
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -0800997 RTC_DCHECK(!local)
998 << "If media transport is used, you must call "
999 "GenerateOrGetLastMediaTransportOffer before SetLocalDescription. You "
1000 "also "
1001 "must use kRtcpMuxPolicyRequire and kBundlePolicyMaxBundle with media "
1002 "transport.";
Piotr (Peter) Slatala63a176b2019-01-25 08:25:33 -08001003 MediaTransportSettings settings;
1004 settings.is_caller = local;
Piotr (Peter) Slatala01fe3092019-02-15 12:05:50 -08001005 if (config_.use_media_transport_for_media) {
1006 settings.event_log = config_.event_log;
1007 }
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -08001008
1009 // Assume there is only one media transport (or if more, use the first one).
1010 if (!local && !description.MediaTransportSettings().empty() &&
1011 config_.media_transport_factory->GetTransportName() ==
1012 description.MediaTransportSettings()[0].transport_name) {
1013 settings.remote_transport_parameters =
1014 description.MediaTransportSettings()[0].transport_setting;
1015 }
1016
Piotr (Peter) Slatala63a176b2019-01-25 08:25:33 -08001017 auto media_transport_result =
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001018 config_.media_transport_factory->CreateMediaTransport(network_thread_,
1019 settings);
Piotr (Peter) Slatala63a176b2019-01-25 08:25:33 -08001020
1021 // TODO(sukhanov): Proper error handling.
1022 RTC_CHECK(media_transport_result.ok());
1023
1024 return media_transport_result.MoveValue();
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001025}
1026
1027RTCError JsepTransportController::MaybeCreateJsepTransport(
1028 bool local,
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -08001029 const cricket::ContentInfo& content_info,
1030 const cricket::SessionDescription& description) {
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001031 RTC_DCHECK(network_thread_->IsCurrent());
1032 cricket::JsepTransport* transport = GetJsepTransportByName(content_info.name);
1033 if (transport) {
1034 return RTCError::OK();
1035 }
1036
1037 const cricket::MediaContentDescription* content_desc =
1038 static_cast<const cricket::MediaContentDescription*>(
1039 content_info.description);
1040 if (certificate_ && !content_desc->cryptos().empty()) {
1041 return RTCError(RTCErrorType::INVALID_PARAMETER,
1042 "SDES and DTLS-SRTP cannot be enabled at the same time.");
1043 }
1044
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001045 std::unique_ptr<cricket::IceTransportInternal> ice =
1046 CreateIceTransport(content_info.name, /*rtcp=*/false);
1047
1048 std::unique_ptr<MediaTransportInterface> media_transport =
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001049 MaybeCreateMediaTransport(content_info, description, local);
1050 if (media_transport) {
1051 media_transport_created_once_ = true;
1052 media_transport->Connect(ice.get());
1053 }
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001054
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001055 std::unique_ptr<cricket::DtlsTransportInternal> rtp_dtls_transport =
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001056 CreateDtlsTransport(std::move(ice));
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001057
1058 std::unique_ptr<cricket::DtlsTransportInternal> rtcp_dtls_transport;
1059 std::unique_ptr<RtpTransport> unencrypted_rtp_transport;
1060 std::unique_ptr<SrtpTransport> sdes_transport;
1061 std::unique_ptr<DtlsSrtpTransport> dtls_srtp_transport;
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001062
1063 if (config_.rtcp_mux_policy !=
1064 PeerConnectionInterface::kRtcpMuxPolicyRequire &&
1065 content_info.type == cricket::MediaProtocolType::kRtp) {
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001066 RTC_DCHECK(media_transport == nullptr);
1067 rtcp_dtls_transport = CreateDtlsTransport(
1068 CreateIceTransport(content_info.name, /*rtcp=*/true));
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001069 }
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001070
Anton Sukhanov7940da02018-10-10 10:34:49 -07001071 // TODO(sukhanov): Do not create RTP/RTCP transports if media transport is
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001072 // used, and remove the no-op dtls transport when that's done.
Zhi Huange818b6e2018-02-22 15:26:27 -08001073 if (config_.disable_encryption) {
1074 unencrypted_rtp_transport = CreateUnencryptedRtpTransport(
Zhi Huangd2248f82018-04-10 14:41:03 -07001075 content_info.name, rtp_dtls_transport.get(), rtcp_dtls_transport.get());
Zhi Huange818b6e2018-02-22 15:26:27 -08001076 } else if (!content_desc->cryptos().empty()) {
Zhi Huangd2248f82018-04-10 14:41:03 -07001077 sdes_transport = CreateSdesTransport(
1078 content_info.name, rtp_dtls_transport.get(), rtcp_dtls_transport.get());
Zhi Huange818b6e2018-02-22 15:26:27 -08001079 } else {
Zhi Huangd2248f82018-04-10 14:41:03 -07001080 dtls_srtp_transport = CreateDtlsSrtpTransport(
1081 content_info.name, rtp_dtls_transport.get(), rtcp_dtls_transport.get());
Zhi Huange818b6e2018-02-22 15:26:27 -08001082 }
1083
Zhi Huang365381f2018-04-13 16:44:34 -07001084 std::unique_ptr<cricket::JsepTransport> jsep_transport =
Karl Wiberg918f50c2018-07-05 11:40:33 +02001085 absl::make_unique<cricket::JsepTransport>(
Zhi Huangd2248f82018-04-10 14:41:03 -07001086 content_info.name, certificate_, std::move(unencrypted_rtp_transport),
Zhi Huange818b6e2018-02-22 15:26:27 -08001087 std::move(sdes_transport), std::move(dtls_srtp_transport),
Anton Sukhanov7940da02018-10-10 10:34:49 -07001088 std::move(rtp_dtls_transport), std::move(rtcp_dtls_transport),
1089 std::move(media_transport));
Zhi Huange818b6e2018-02-22 15:26:27 -08001090 jsep_transport->SignalRtcpMuxActive.connect(
1091 this, &JsepTransportController::UpdateAggregateStates_n);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001092 jsep_transport->SignalMediaTransportStateChanged.connect(
Bjorn Mellem175aa2e2018-11-08 11:23:22 -08001093 this, &JsepTransportController::OnMediaTransportStateChanged_n);
Taylor Brandstettercbaa2542018-04-16 16:42:14 -07001094 SetTransportForMid(content_info.name, jsep_transport.get());
Zhi Huange830e682018-03-30 10:48:35 -07001095
Zhi Huangd2248f82018-04-10 14:41:03 -07001096 jsep_transports_by_name_[content_info.name] = std::move(jsep_transport);
1097 UpdateAggregateStates_n();
Zhi Huange830e682018-03-30 10:48:35 -07001098 return RTCError::OK();
Zhi Huange818b6e2018-02-22 15:26:27 -08001099}
1100
1101void JsepTransportController::MaybeDestroyJsepTransport(
1102 const std::string& mid) {
Zhi Huangd2248f82018-04-10 14:41:03 -07001103 auto jsep_transport = GetJsepTransportByName(mid);
1104 if (!jsep_transport) {
1105 return;
1106 }
1107
1108 // Don't destroy the JsepTransport if there are still media sections referring
1109 // to it.
1110 for (const auto& kv : mid_to_transport_) {
1111 if (kv.second == jsep_transport) {
1112 return;
1113 }
1114 }
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -08001115
Zhi Huange830e682018-03-30 10:48:35 -07001116 jsep_transports_by_name_.erase(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -08001117 UpdateAggregateStates_n();
1118}
1119
1120void JsepTransportController::DestroyAllJsepTransports_n() {
1121 RTC_DCHECK(network_thread_->IsCurrent());
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -08001122
1123 for (const auto& jsep_transport : jsep_transports_by_name_) {
1124 config_.transport_observer->OnTransportChanged(jsep_transport.first,
1125 nullptr, nullptr, nullptr);
1126 }
1127
Zhi Huange830e682018-03-30 10:48:35 -07001128 jsep_transports_by_name_.clear();
Zhi Huange818b6e2018-02-22 15:26:27 -08001129}
1130
1131void JsepTransportController::SetIceRole_n(cricket::IceRole ice_role) {
1132 RTC_DCHECK(network_thread_->IsCurrent());
1133
1134 ice_role_ = ice_role;
1135 for (auto& dtls : GetDtlsTransports()) {
1136 dtls->ice_transport()->SetIceRole(ice_role_);
1137 }
1138}
1139
1140cricket::IceRole JsepTransportController::DetermineIceRole(
Zhi Huang365381f2018-04-13 16:44:34 -07001141 cricket::JsepTransport* jsep_transport,
Zhi Huange818b6e2018-02-22 15:26:27 -08001142 const cricket::TransportInfo& transport_info,
1143 SdpType type,
1144 bool local) {
1145 cricket::IceRole ice_role = ice_role_;
1146 auto tdesc = transport_info.description;
1147 if (local) {
1148 // The initial offer side may use ICE Lite, in which case, per RFC5245
1149 // Section 5.1.1, the answer side should take the controlling role if it is
1150 // in the full ICE mode.
1151 //
1152 // When both sides use ICE Lite, the initial offer side must take the
1153 // controlling role, and this is the default logic implemented in
1154 // SetLocalDescription in JsepTransportController.
1155 if (jsep_transport->remote_description() &&
1156 jsep_transport->remote_description()->transport_desc.ice_mode ==
1157 cricket::ICEMODE_LITE &&
1158 ice_role_ == cricket::ICEROLE_CONTROLLED &&
1159 tdesc.ice_mode == cricket::ICEMODE_FULL) {
1160 ice_role = cricket::ICEROLE_CONTROLLING;
1161 }
1162
1163 // Older versions of Chrome expect the ICE role to be re-determined when an
1164 // ICE restart occurs, and also don't perform conflict resolution correctly,
1165 // so for now we can't safely stop doing this, unless the application opts
1166 // in by setting |config_.redetermine_role_on_ice_restart_| to false. See:
1167 // https://bugs.chromium.org/p/chromium/issues/detail?id=628676
1168 // TODO(deadbeef): Remove this when these old versions of Chrome reach a low
1169 // enough population.
1170 if (config_.redetermine_role_on_ice_restart &&
1171 jsep_transport->local_description() &&
1172 cricket::IceCredentialsChanged(
1173 jsep_transport->local_description()->transport_desc.ice_ufrag,
1174 jsep_transport->local_description()->transport_desc.ice_pwd,
1175 tdesc.ice_ufrag, tdesc.ice_pwd) &&
1176 // Don't change the ICE role if the remote endpoint is ICE lite; we
1177 // should always be controlling in that case.
1178 (!jsep_transport->remote_description() ||
1179 jsep_transport->remote_description()->transport_desc.ice_mode !=
1180 cricket::ICEMODE_LITE)) {
1181 ice_role = (type == SdpType::kOffer) ? cricket::ICEROLE_CONTROLLING
1182 : cricket::ICEROLE_CONTROLLED;
1183 }
1184 } else {
1185 // If our role is cricket::ICEROLE_CONTROLLED and the remote endpoint
1186 // supports only ice_lite, this local endpoint should take the CONTROLLING
1187 // role.
1188 // TODO(deadbeef): This is a session-level attribute, so it really shouldn't
1189 // be in a TransportDescription in the first place...
1190 if (ice_role_ == cricket::ICEROLE_CONTROLLED &&
1191 tdesc.ice_mode == cricket::ICEMODE_LITE) {
1192 ice_role = cricket::ICEROLE_CONTROLLING;
1193 }
1194
1195 // If we use ICE Lite and the remote endpoint uses the full implementation
1196 // of ICE, the local endpoint must take the controlled role, and the other
1197 // side must be the controlling role.
1198 if (jsep_transport->local_description() &&
1199 jsep_transport->local_description()->transport_desc.ice_mode ==
1200 cricket::ICEMODE_LITE &&
1201 ice_role_ == cricket::ICEROLE_CONTROLLING &&
Zhi Huange830e682018-03-30 10:48:35 -07001202 tdesc.ice_mode == cricket::ICEMODE_FULL) {
Zhi Huange818b6e2018-02-22 15:26:27 -08001203 ice_role = cricket::ICEROLE_CONTROLLED;
1204 }
1205 }
1206
1207 return ice_role;
1208}
1209
1210void JsepTransportController::OnTransportWritableState_n(
1211 rtc::PacketTransportInternal* transport) {
1212 RTC_DCHECK(network_thread_->IsCurrent());
1213 RTC_LOG(LS_INFO) << " Transport " << transport->transport_name()
1214 << " writability changed to " << transport->writable()
1215 << ".";
1216 UpdateAggregateStates_n();
1217}
1218
1219void JsepTransportController::OnTransportReceivingState_n(
1220 rtc::PacketTransportInternal* transport) {
1221 RTC_DCHECK(network_thread_->IsCurrent());
1222 UpdateAggregateStates_n();
1223}
1224
1225void JsepTransportController::OnTransportGatheringState_n(
1226 cricket::IceTransportInternal* transport) {
1227 RTC_DCHECK(network_thread_->IsCurrent());
1228 UpdateAggregateStates_n();
1229}
1230
1231void JsepTransportController::OnTransportCandidateGathered_n(
1232 cricket::IceTransportInternal* transport,
1233 const cricket::Candidate& candidate) {
1234 RTC_DCHECK(network_thread_->IsCurrent());
1235
1236 // We should never signal peer-reflexive candidates.
1237 if (candidate.type() == cricket::PRFLX_PORT_TYPE) {
1238 RTC_NOTREACHED();
1239 return;
1240 }
Steve Antond25828a2018-08-31 13:06:05 -07001241 std::string transport_name = transport->transport_name();
1242 invoker_.AsyncInvoke<void>(
1243 RTC_FROM_HERE, signaling_thread_, [this, transport_name, candidate] {
1244 SignalIceCandidatesGathered(transport_name, {candidate});
1245 });
Zhi Huange818b6e2018-02-22 15:26:27 -08001246}
1247
1248void JsepTransportController::OnTransportCandidatesRemoved_n(
1249 cricket::IceTransportInternal* transport,
1250 const cricket::Candidates& candidates) {
1251 invoker_.AsyncInvoke<void>(
1252 RTC_FROM_HERE, signaling_thread_,
Steve Antond25828a2018-08-31 13:06:05 -07001253 [this, candidates] { SignalIceCandidatesRemoved(candidates); });
Zhi Huange818b6e2018-02-22 15:26:27 -08001254}
1255
1256void JsepTransportController::OnTransportRoleConflict_n(
1257 cricket::IceTransportInternal* transport) {
1258 RTC_DCHECK(network_thread_->IsCurrent());
1259 // Note: since the role conflict is handled entirely on the network thread,
1260 // we don't need to worry about role conflicts occurring on two ports at
1261 // once. The first one encountered should immediately reverse the role.
1262 cricket::IceRole reversed_role = (ice_role_ == cricket::ICEROLE_CONTROLLING)
1263 ? cricket::ICEROLE_CONTROLLED
1264 : cricket::ICEROLE_CONTROLLING;
1265 RTC_LOG(LS_INFO) << "Got role conflict; switching to "
1266 << (reversed_role == cricket::ICEROLE_CONTROLLING
1267 ? "controlling"
1268 : "controlled")
1269 << " role.";
1270 SetIceRole_n(reversed_role);
1271}
1272
1273void JsepTransportController::OnTransportStateChanged_n(
1274 cricket::IceTransportInternal* transport) {
1275 RTC_DCHECK(network_thread_->IsCurrent());
1276 RTC_LOG(LS_INFO) << transport->transport_name() << " Transport "
1277 << transport->component()
1278 << " state changed. Check if state is complete.";
1279 UpdateAggregateStates_n();
1280}
1281
Bjorn Mellem175aa2e2018-11-08 11:23:22 -08001282void JsepTransportController::OnMediaTransportStateChanged_n() {
1283 SignalMediaTransportStateChanged();
1284 UpdateAggregateStates_n();
1285}
1286
Zhi Huange818b6e2018-02-22 15:26:27 -08001287void JsepTransportController::UpdateAggregateStates_n() {
1288 RTC_DCHECK(network_thread_->IsCurrent());
1289
1290 auto dtls_transports = GetDtlsTransports();
Alex Loiko9289eda2018-11-23 16:18:59 +00001291 cricket::IceConnectionState new_connection_state =
1292 cricket::kIceConnectionConnecting;
Jonas Olsson635474e2018-10-18 15:58:17 +02001293 PeerConnectionInterface::IceConnectionState new_ice_connection_state =
1294 PeerConnectionInterface::IceConnectionState::kIceConnectionNew;
1295 PeerConnectionInterface::PeerConnectionState new_combined_state =
1296 PeerConnectionInterface::PeerConnectionState::kNew;
Zhi Huange818b6e2018-02-22 15:26:27 -08001297 cricket::IceGatheringState new_gathering_state = cricket::kIceGatheringNew;
Alex Loiko9289eda2018-11-23 16:18:59 +00001298 bool any_failed = false;
1299
1300 // TODO(http://bugs.webrtc.org/9719) If(when) media_transport disables
1301 // dtls_transports entirely, the below line will have to be changed to account
1302 // for the fact that dtls transports might be absent.
1303 bool all_connected = !dtls_transports.empty();
1304 bool all_completed = !dtls_transports.empty();
Zhi Huange818b6e2018-02-22 15:26:27 -08001305 bool any_gathering = false;
1306 bool all_done_gathering = !dtls_transports.empty();
Jonas Olsson635474e2018-10-18 15:58:17 +02001307
1308 std::map<IceTransportState, int> ice_state_counts;
1309 std::map<cricket::DtlsTransportState, int> dtls_state_counts;
1310
Zhi Huange818b6e2018-02-22 15:26:27 -08001311 for (const auto& dtls : dtls_transports) {
Alex Loiko9289eda2018-11-23 16:18:59 +00001312 any_failed = any_failed || dtls->ice_transport()->GetState() ==
1313 cricket::IceTransportState::STATE_FAILED;
1314 all_connected = all_connected && dtls->writable();
1315 all_completed =
1316 all_completed && dtls->writable() &&
1317 dtls->ice_transport()->GetState() ==
1318 cricket::IceTransportState::STATE_COMPLETED &&
1319 dtls->ice_transport()->GetIceRole() == cricket::ICEROLE_CONTROLLING &&
1320 dtls->ice_transport()->gathering_state() ==
1321 cricket::kIceGatheringComplete;
Zhi Huange818b6e2018-02-22 15:26:27 -08001322 any_gathering = any_gathering || dtls->ice_transport()->gathering_state() !=
1323 cricket::kIceGatheringNew;
1324 all_done_gathering =
1325 all_done_gathering && dtls->ice_transport()->gathering_state() ==
1326 cricket::kIceGatheringComplete;
Jonas Olsson635474e2018-10-18 15:58:17 +02001327
1328 dtls_state_counts[dtls->dtls_state()]++;
1329 ice_state_counts[dtls->ice_transport()->GetIceTransportState()]++;
Zhi Huange818b6e2018-02-22 15:26:27 -08001330 }
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001331
Alex Loiko9289eda2018-11-23 16:18:59 +00001332 for (auto it = jsep_transports_by_name_.begin();
1333 it != jsep_transports_by_name_.end(); ++it) {
1334 auto jsep_transport = it->second.get();
1335 if (!jsep_transport->media_transport()) {
1336 continue;
1337 }
1338
1339 // There is no 'kIceConnectionDisconnected', so we only need to handle
1340 // connected and completed.
1341 // We treat kClosed as failed, because if it happens before shutting down
1342 // media transports it means that there was a failure.
1343 // MediaTransportInterface allows to flip back and forth between kWritable
1344 // and kPending, but there does not exist an implementation that does that,
1345 // and the contract of jsep transport controller doesn't quite expect that.
1346 // When this happens, we would go from connected to connecting state, but
1347 // this may change in future.
1348 any_failed |= jsep_transport->media_transport_state() ==
1349 webrtc::MediaTransportState::kClosed;
1350 all_completed &= jsep_transport->media_transport_state() ==
1351 webrtc::MediaTransportState::kWritable;
1352 all_connected &= jsep_transport->media_transport_state() ==
1353 webrtc::MediaTransportState::kWritable;
1354 }
1355
1356 if (any_failed) {
1357 new_connection_state = cricket::kIceConnectionFailed;
1358 } else if (all_completed) {
1359 new_connection_state = cricket::kIceConnectionCompleted;
1360 } else if (all_connected) {
1361 new_connection_state = cricket::kIceConnectionConnected;
1362 }
1363 if (ice_connection_state_ != new_connection_state) {
1364 ice_connection_state_ = new_connection_state;
1365 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_,
1366 [this, new_connection_state] {
1367 SignalIceConnectionState(new_connection_state);
1368 });
1369 }
1370
Jonas Olsson635474e2018-10-18 15:58:17 +02001371 // Compute the current RTCIceConnectionState as described in
1372 // https://www.w3.org/TR/webrtc/#dom-rtciceconnectionstate.
1373 // The PeerConnection is responsible for handling the "closed" state.
1374 int total_ice_checking = ice_state_counts[IceTransportState::kChecking];
1375 int total_ice_connected = ice_state_counts[IceTransportState::kConnected];
1376 int total_ice_completed = ice_state_counts[IceTransportState::kCompleted];
1377 int total_ice_failed = ice_state_counts[IceTransportState::kFailed];
1378 int total_ice_disconnected =
1379 ice_state_counts[IceTransportState::kDisconnected];
1380 int total_ice_closed = ice_state_counts[IceTransportState::kClosed];
1381 int total_ice_new = ice_state_counts[IceTransportState::kNew];
1382 int total_ice = dtls_transports.size();
1383
1384 if (total_ice_failed > 0) {
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001385 // Any RTCIceTransports are in the "failed" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001386 new_ice_connection_state = PeerConnectionInterface::kIceConnectionFailed;
Alex Loiko9289eda2018-11-23 16:18:59 +00001387 } else if (total_ice_disconnected > 0) {
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001388 // None of the previous states apply and any RTCIceTransports are in the
1389 // "disconnected" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001390 new_ice_connection_state =
1391 PeerConnectionInterface::kIceConnectionDisconnected;
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001392 } else if (total_ice_new + total_ice_closed == total_ice) {
1393 // None of the previous states apply and all RTCIceTransports are in the
1394 // "new" or "closed" state, or there are no transports.
1395 new_ice_connection_state = PeerConnectionInterface::kIceConnectionNew;
1396 } else if (total_ice_new + total_ice_checking > 0) {
1397 // None of the previous states apply and any RTCIceTransports are in the
1398 // "new" or "checking" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001399 new_ice_connection_state = PeerConnectionInterface::kIceConnectionChecking;
Jonas Olssonacd8ae72019-02-25 15:26:24 +01001400 } else if (total_ice_completed + total_ice_closed == total_ice ||
1401 all_completed) {
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001402 // None of the previous states apply and all RTCIceTransports are in the
1403 // "completed" or "closed" state.
Jonas Olssonacd8ae72019-02-25 15:26:24 +01001404 //
1405 // TODO(https://bugs.webrtc.org/10356): The all_completed condition is added
1406 // to mimic the behavior of the old ICE connection state, and should be
1407 // removed once we get end-of-candidates signaling in place.
Jonas Olsson635474e2018-10-18 15:58:17 +02001408 new_ice_connection_state = PeerConnectionInterface::kIceConnectionCompleted;
1409 } else if (total_ice_connected + total_ice_completed + total_ice_closed ==
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001410 total_ice) {
1411 // None of the previous states apply and all RTCIceTransports are in the
1412 // "connected", "completed" or "closed" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001413 new_ice_connection_state = PeerConnectionInterface::kIceConnectionConnected;
Jonas Olsson635474e2018-10-18 15:58:17 +02001414 } else {
1415 RTC_NOTREACHED();
1416 }
1417
Alex Loiko9289eda2018-11-23 16:18:59 +00001418 if (standardized_ice_connection_state_ != new_ice_connection_state) {
Jonas Olssonacd8ae72019-02-25 15:26:24 +01001419 if (standardized_ice_connection_state_ ==
1420 PeerConnectionInterface::kIceConnectionChecking &&
1421 new_ice_connection_state ==
1422 PeerConnectionInterface::kIceConnectionCompleted) {
1423 // Ensure that we never skip over the "connected" state.
1424 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_, [this] {
1425 SignalStandardizedIceConnectionState(
1426 PeerConnectionInterface::kIceConnectionConnected);
1427 });
1428 }
Alex Loiko9289eda2018-11-23 16:18:59 +00001429 standardized_ice_connection_state_ = new_ice_connection_state;
Jonas Olsson635474e2018-10-18 15:58:17 +02001430 invoker_.AsyncInvoke<void>(
1431 RTC_FROM_HERE, signaling_thread_, [this, new_ice_connection_state] {
Alex Loiko9289eda2018-11-23 16:18:59 +00001432 SignalStandardizedIceConnectionState(new_ice_connection_state);
Jonas Olsson635474e2018-10-18 15:58:17 +02001433 });
1434 }
1435
1436 // Compute the current RTCPeerConnectionState as described in
1437 // https://www.w3.org/TR/webrtc/#dom-rtcpeerconnectionstate.
1438 // The PeerConnection is responsible for handling the "closed" state.
1439 // Note that "connecting" is only a valid state for DTLS transports while
1440 // "checking", "completed" and "disconnected" are only valid for ICE
1441 // transports.
1442 int total_connected = total_ice_connected +
1443 dtls_state_counts[cricket::DTLS_TRANSPORT_CONNECTED];
1444 int total_dtls_connecting =
1445 dtls_state_counts[cricket::DTLS_TRANSPORT_CONNECTING];
1446 int total_failed =
1447 total_ice_failed + dtls_state_counts[cricket::DTLS_TRANSPORT_FAILED];
1448 int total_closed =
1449 total_ice_closed + dtls_state_counts[cricket::DTLS_TRANSPORT_CLOSED];
1450 int total_new =
1451 total_ice_new + dtls_state_counts[cricket::DTLS_TRANSPORT_NEW];
1452 int total_transports = total_ice * 2;
1453
1454 if (total_failed > 0) {
1455 // Any of the RTCIceTransports or RTCDtlsTransports are in a "failed" state.
1456 new_combined_state = PeerConnectionInterface::PeerConnectionState::kFailed;
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001457 } else if (total_ice_disconnected > 0) {
1458 // None of the previous states apply and any RTCIceTransports or
1459 // RTCDtlsTransports are in the "disconnected" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001460 new_combined_state =
1461 PeerConnectionInterface::PeerConnectionState::kDisconnected;
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001462 } else if (total_new + total_closed == total_transports) {
1463 // None of the previous states apply and all RTCIceTransports and
1464 // RTCDtlsTransports are in the "new" or "closed" state, or there are no
1465 // transports.
1466 new_combined_state = PeerConnectionInterface::PeerConnectionState::kNew;
1467 } else if (total_new + total_dtls_connecting + total_ice_checking > 0) {
1468 // None of the previous states apply and all RTCIceTransports or
1469 // RTCDtlsTransports are in the "new", "connecting" or "checking" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001470 new_combined_state =
1471 PeerConnectionInterface::PeerConnectionState::kConnecting;
1472 } else if (total_connected + total_ice_completed + total_closed ==
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001473 total_transports) {
1474 // None of the previous states apply and all RTCIceTransports and
1475 // RTCDtlsTransports are in the "connected", "completed" or "closed" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001476 new_combined_state =
1477 PeerConnectionInterface::PeerConnectionState::kConnected;
Jonas Olsson635474e2018-10-18 15:58:17 +02001478 } else {
1479 RTC_NOTREACHED();
1480 }
1481
1482 if (combined_connection_state_ != new_combined_state) {
1483 combined_connection_state_ = new_combined_state;
1484 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_,
1485 [this, new_combined_state] {
1486 SignalConnectionState(new_combined_state);
1487 });
1488 }
1489
Zhi Huange818b6e2018-02-22 15:26:27 -08001490 if (all_done_gathering) {
1491 new_gathering_state = cricket::kIceGatheringComplete;
1492 } else if (any_gathering) {
1493 new_gathering_state = cricket::kIceGatheringGathering;
1494 }
1495 if (ice_gathering_state_ != new_gathering_state) {
1496 ice_gathering_state_ = new_gathering_state;
Steve Antond25828a2018-08-31 13:06:05 -07001497 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_,
1498 [this, new_gathering_state] {
1499 SignalIceGatheringState(new_gathering_state);
1500 });
Zhi Huange818b6e2018-02-22 15:26:27 -08001501 }
1502}
1503
1504void JsepTransportController::OnDtlsHandshakeError(
1505 rtc::SSLHandshakeError error) {
1506 SignalDtlsHandshakeError(error);
1507}
1508
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001509absl::optional<cricket::SessionDescription::MediaTransportSetting>
1510JsepTransportController::GenerateOrGetLastMediaTransportOffer() {
1511 if (media_transport_created_once_) {
1512 RTC_LOG(LS_INFO) << "Not regenerating media transport for the new offer in "
1513 "existing session.";
1514 return media_transport_offer_settings_;
1515 }
1516
1517 RTC_LOG(LS_INFO) << "Generating media transport offer!";
1518 // Check that media transport is supposed to be used.
1519 if (config_.use_media_transport_for_media ||
1520 config_.use_media_transport_for_data_channels) {
1521 RTC_DCHECK(config_.media_transport_factory != nullptr);
1522 // ICE is not available when media transport is created. It will only be
1523 // available in 'Connect'. This may be a potential server config, if we
1524 // decide to use this peer connection as a caller, not as a callee.
1525 webrtc::MediaTransportSettings settings;
1526 settings.is_caller = true;
1527 settings.pre_shared_key = rtc::CreateRandomString(32);
1528 settings.event_log = config_.event_log;
1529 auto media_transport_or_error =
1530 config_.media_transport_factory->CreateMediaTransport(network_thread_,
1531 settings);
1532
1533 if (media_transport_or_error.ok()) {
1534 offer_media_transport_ = std::move(media_transport_or_error.value());
1535 } else {
1536 RTC_LOG(LS_INFO) << "Unable to create media transport, error="
1537 << media_transport_or_error.error().message();
1538 }
1539 }
1540
1541 if (!offer_media_transport_) {
1542 RTC_LOG(LS_INFO) << "Media transport doesn't exist";
1543 return absl::nullopt;
1544 }
1545
1546 absl::optional<std::string> transport_parameters =
1547 offer_media_transport_->GetTransportParametersOffer();
1548 if (!transport_parameters) {
1549 RTC_LOG(LS_INFO) << "Media transport didn't generate the offer";
1550 // Media transport didn't generate the offer, and is not supposed to be
1551 // used. Destroy the temporary media transport.
1552 offer_media_transport_ = nullptr;
1553 return absl::nullopt;
1554 }
1555
1556 cricket::SessionDescription::MediaTransportSetting setting;
1557 setting.transport_name = config_.media_transport_factory->GetTransportName();
1558 setting.transport_setting = *transport_parameters;
1559 media_transport_offer_settings_ = setting;
1560 return setting;
1561}
1562
Zhi Huange818b6e2018-02-22 15:26:27 -08001563} // namespace webrtc