blob: 93949c665741d0b52ca74429357d02063709c389 [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"
Anton Sukhanov316f3ac2019-05-23 15:50:38 -070018#include "api/datagram_transport_interface.h"
19#include "api/media_transport_interface.h"
20#include "p2p/base/datagram_dtls_adaptor.h"
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -080021#include "p2p/base/ice_transport_internal.h"
22#include "p2p/base/no_op_dtls_transport.h"
Zhi Huange818b6e2018-02-22 15:26:27 -080023#include "p2p/base/port.h"
Steve Anton10542f22019-01-11 09:11:00 -080024#include "pc/srtp_filter.h"
Zhi Huange818b6e2018-02-22 15:26:27 -080025#include "rtc_base/bind.h"
26#include "rtc_base/checks.h"
Zhi Huange818b6e2018-02-22 15:26:27 -080027#include "rtc_base/thread.h"
28
29using webrtc::SdpType;
30
31namespace {
32
Zhi Huange818b6e2018-02-22 15:26:27 -080033webrtc::RTCError VerifyCandidate(const cricket::Candidate& cand) {
34 // No address zero.
35 if (cand.address().IsNil() || cand.address().IsAnyIP()) {
36 return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
37 "candidate has address of zero");
38 }
39
40 // Disallow all ports below 1024, except for 80 and 443 on public addresses.
41 int port = cand.address().port();
42 if (cand.protocol() == cricket::TCP_PROTOCOL_NAME &&
43 (cand.tcptype() == cricket::TCPTYPE_ACTIVE_STR || port == 0)) {
44 // Expected for active-only candidates per
45 // http://tools.ietf.org/html/rfc6544#section-4.5 so no error.
46 // Libjingle clients emit port 0, in "active" mode.
47 return webrtc::RTCError::OK();
48 }
49 if (port < 1024) {
50 if ((port != 80) && (port != 443)) {
51 return webrtc::RTCError(
52 webrtc::RTCErrorType::INVALID_PARAMETER,
53 "candidate has port below 1024, but not 80 or 443");
54 }
55
56 if (cand.address().IsPrivateIP()) {
57 return webrtc::RTCError(
58 webrtc::RTCErrorType::INVALID_PARAMETER,
59 "candidate has port of 80 or 443 with private IP address");
60 }
61 }
62
63 return webrtc::RTCError::OK();
64}
65
66webrtc::RTCError VerifyCandidates(const cricket::Candidates& candidates) {
67 for (const cricket::Candidate& candidate : candidates) {
68 webrtc::RTCError error = VerifyCandidate(candidate);
69 if (!error.ok()) {
70 return error;
71 }
72 }
73 return webrtc::RTCError::OK();
74}
75
76} // namespace
77
78namespace webrtc {
79
80JsepTransportController::JsepTransportController(
81 rtc::Thread* signaling_thread,
82 rtc::Thread* network_thread,
83 cricket::PortAllocator* port_allocator,
Zach Steine20867f2018-08-02 13:20:15 -070084 AsyncResolverFactory* async_resolver_factory,
Zhi Huange818b6e2018-02-22 15:26:27 -080085 Config config)
86 : signaling_thread_(signaling_thread),
87 network_thread_(network_thread),
88 port_allocator_(port_allocator),
Zach Steine20867f2018-08-02 13:20:15 -070089 async_resolver_factory_(async_resolver_factory),
Zhi Huang365381f2018-04-13 16:44:34 -070090 config_(config) {
91 // The |transport_observer| is assumed to be non-null.
92 RTC_DCHECK(config_.transport_observer);
93}
Zhi Huange818b6e2018-02-22 15:26:27 -080094
95JsepTransportController::~JsepTransportController() {
96 // Channel destructors may try to send packets, so this needs to happen on
97 // the network thread.
98 network_thread_->Invoke<void>(
99 RTC_FROM_HERE,
100 rtc::Bind(&JsepTransportController::DestroyAllJsepTransports_n, this));
101}
102
103RTCError JsepTransportController::SetLocalDescription(
104 SdpType type,
105 const cricket::SessionDescription* description) {
106 if (!network_thread_->IsCurrent()) {
107 return network_thread_->Invoke<RTCError>(
108 RTC_FROM_HERE, [=] { return SetLocalDescription(type, description); });
109 }
110
111 if (!initial_offerer_.has_value()) {
112 initial_offerer_.emplace(type == SdpType::kOffer);
113 if (*initial_offerer_) {
114 SetIceRole_n(cricket::ICEROLE_CONTROLLING);
115 } else {
116 SetIceRole_n(cricket::ICEROLE_CONTROLLED);
117 }
118 }
119 return ApplyDescription_n(/*local=*/true, type, description);
120}
121
122RTCError JsepTransportController::SetRemoteDescription(
123 SdpType type,
124 const cricket::SessionDescription* description) {
125 if (!network_thread_->IsCurrent()) {
126 return network_thread_->Invoke<RTCError>(
127 RTC_FROM_HERE, [=] { return SetRemoteDescription(type, description); });
128 }
129
130 return ApplyDescription_n(/*local=*/false, type, description);
131}
132
133RtpTransportInternal* JsepTransportController::GetRtpTransport(
134 const std::string& mid) const {
Zhi Huange830e682018-03-30 10:48:35 -0700135 auto jsep_transport = GetJsepTransportForMid(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -0800136 if (!jsep_transport) {
137 return nullptr;
138 }
139 return jsep_transport->rtp_transport();
140}
141
Anton Sukhanov316f3ac2019-05-23 15:50:38 -0700142MediaTransportConfig JsepTransportController::GetMediaTransportConfig(
Anton Sukhanov7940da02018-10-10 10:34:49 -0700143 const std::string& mid) const {
144 auto jsep_transport = GetJsepTransportForMid(mid);
145 if (!jsep_transport) {
Anton Sukhanov316f3ac2019-05-23 15:50:38 -0700146 return MediaTransportConfig();
147 }
148
149 MediaTransportInterface* media_transport = nullptr;
150 if (config_.use_media_transport_for_media) {
151 media_transport = jsep_transport->media_transport();
152 }
153
154 DatagramTransportInterface* datagram_transport =
155 jsep_transport->datagram_transport();
156
157 // Media transport and datagram transports can not be used together.
158 RTC_DCHECK(!media_transport || !datagram_transport);
159
160 if (media_transport) {
161 return MediaTransportConfig(media_transport);
162 } else if (datagram_transport) {
163 return MediaTransportConfig(
164 /*rtp_max_packet_size=*/datagram_transport->GetLargestDatagramSize());
165 } else {
166 return MediaTransportConfig();
167 }
168}
169
170MediaTransportInterface*
171JsepTransportController::GetMediaTransportForDataChannel(
172 const std::string& mid) const {
173 auto jsep_transport = GetJsepTransportForMid(mid);
174 if (!jsep_transport || !config_.use_media_transport_for_data_channels) {
Anton Sukhanov7940da02018-10-10 10:34:49 -0700175 return nullptr;
176 }
Anton Sukhanov316f3ac2019-05-23 15:50:38 -0700177
Anton Sukhanov7940da02018-10-10 10:34:49 -0700178 return jsep_transport->media_transport();
179}
180
Bjorn Mellem175aa2e2018-11-08 11:23:22 -0800181MediaTransportState JsepTransportController::GetMediaTransportState(
182 const std::string& mid) const {
183 auto jsep_transport = GetJsepTransportForMid(mid);
184 if (!jsep_transport) {
185 return MediaTransportState::kPending;
186 }
187 return jsep_transport->media_transport_state();
188}
189
Zhi Huange818b6e2018-02-22 15:26:27 -0800190cricket::DtlsTransportInternal* JsepTransportController::GetDtlsTransport(
Harald Alvestrandad88c882018-11-28 16:47:46 +0100191 const std::string& mid) {
Zhi Huange830e682018-03-30 10:48:35 -0700192 auto jsep_transport = GetJsepTransportForMid(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -0800193 if (!jsep_transport) {
194 return nullptr;
195 }
196 return jsep_transport->rtp_dtls_transport();
197}
198
Harald Alvestrandad88c882018-11-28 16:47:46 +0100199const cricket::DtlsTransportInternal*
200JsepTransportController::GetRtcpDtlsTransport(const std::string& mid) const {
Zhi Huange830e682018-03-30 10:48:35 -0700201 auto jsep_transport = GetJsepTransportForMid(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -0800202 if (!jsep_transport) {
203 return nullptr;
204 }
205 return jsep_transport->rtcp_dtls_transport();
206}
207
Harald Alvestrand4a7b3ac2019-01-17 10:39:40 +0100208rtc::scoped_refptr<webrtc::DtlsTransport>
Harald Alvestrandad88c882018-11-28 16:47:46 +0100209JsepTransportController::LookupDtlsTransportByMid(const std::string& mid) {
210 auto jsep_transport = GetJsepTransportForMid(mid);
211 if (!jsep_transport) {
212 return nullptr;
213 }
214 return jsep_transport->RtpDtlsTransport();
215}
216
Zhi Huange818b6e2018-02-22 15:26:27 -0800217void JsepTransportController::SetIceConfig(const cricket::IceConfig& config) {
218 if (!network_thread_->IsCurrent()) {
219 network_thread_->Invoke<void>(RTC_FROM_HERE, [&] { SetIceConfig(config); });
220 return;
221 }
222
223 ice_config_ = config;
224 for (auto& dtls : GetDtlsTransports()) {
225 dtls->ice_transport()->SetIceConfig(ice_config_);
226 }
227}
228
229void JsepTransportController::SetNeedsIceRestartFlag() {
Zhi Huange830e682018-03-30 10:48:35 -0700230 for (auto& kv : jsep_transports_by_name_) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800231 kv.second->SetNeedsIceRestartFlag();
232 }
233}
234
235bool JsepTransportController::NeedsIceRestart(
236 const std::string& transport_name) const {
Zhi Huang365381f2018-04-13 16:44:34 -0700237 const cricket::JsepTransport* transport =
Zhi Huange830e682018-03-30 10:48:35 -0700238 GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800239 if (!transport) {
240 return false;
241 }
242 return transport->needs_ice_restart();
243}
244
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200245absl::optional<rtc::SSLRole> JsepTransportController::GetDtlsRole(
Zhi Huange830e682018-03-30 10:48:35 -0700246 const std::string& mid) const {
Zhi Huange818b6e2018-02-22 15:26:27 -0800247 if (!network_thread_->IsCurrent()) {
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200248 return network_thread_->Invoke<absl::optional<rtc::SSLRole>>(
Zhi Huange830e682018-03-30 10:48:35 -0700249 RTC_FROM_HERE, [&] { return GetDtlsRole(mid); });
Zhi Huange818b6e2018-02-22 15:26:27 -0800250 }
251
Zhi Huang365381f2018-04-13 16:44:34 -0700252 const cricket::JsepTransport* t = GetJsepTransportForMid(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -0800253 if (!t) {
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200254 return absl::optional<rtc::SSLRole>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800255 }
256 return t->GetDtlsRole();
257}
258
259bool JsepTransportController::SetLocalCertificate(
260 const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) {
261 if (!network_thread_->IsCurrent()) {
262 return network_thread_->Invoke<bool>(
263 RTC_FROM_HERE, [&] { return SetLocalCertificate(certificate); });
264 }
265
266 // Can't change a certificate, or set a null certificate.
267 if (certificate_ || !certificate) {
268 return false;
269 }
270 certificate_ = certificate;
271
272 // Set certificate for JsepTransport, which verifies it matches the
273 // fingerprint in SDP, and DTLS transport.
274 // Fallback from DTLS to SDES is not supported.
Zhi Huange830e682018-03-30 10:48:35 -0700275 for (auto& kv : jsep_transports_by_name_) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800276 kv.second->SetLocalCertificate(certificate_);
277 }
278 for (auto& dtls : GetDtlsTransports()) {
279 bool set_cert_success = dtls->SetLocalCertificate(certificate_);
280 RTC_DCHECK(set_cert_success);
281 }
282 return true;
283}
284
285rtc::scoped_refptr<rtc::RTCCertificate>
286JsepTransportController::GetLocalCertificate(
287 const std::string& transport_name) const {
288 if (!network_thread_->IsCurrent()) {
289 return network_thread_->Invoke<rtc::scoped_refptr<rtc::RTCCertificate>>(
290 RTC_FROM_HERE, [&] { return GetLocalCertificate(transport_name); });
291 }
292
Zhi Huang365381f2018-04-13 16:44:34 -0700293 const cricket::JsepTransport* t = GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800294 if (!t) {
295 return nullptr;
296 }
297 return t->GetLocalCertificate();
298}
299
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800300std::unique_ptr<rtc::SSLCertChain>
301JsepTransportController::GetRemoteSSLCertChain(
Zhi Huange818b6e2018-02-22 15:26:27 -0800302 const std::string& transport_name) const {
303 if (!network_thread_->IsCurrent()) {
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800304 return network_thread_->Invoke<std::unique_ptr<rtc::SSLCertChain>>(
305 RTC_FROM_HERE, [&] { return GetRemoteSSLCertChain(transport_name); });
Zhi Huange818b6e2018-02-22 15:26:27 -0800306 }
307
Zhi Huange830e682018-03-30 10:48:35 -0700308 // Get the certificate from the RTP transport's DTLS handshake. Should be
309 // identical to the RTCP transport's, since they were given the same remote
Zhi Huange818b6e2018-02-22 15:26:27 -0800310 // fingerprint.
Zhi Huange830e682018-03-30 10:48:35 -0700311 auto jsep_transport = GetJsepTransportByName(transport_name);
312 if (!jsep_transport) {
313 return nullptr;
314 }
315 auto dtls = jsep_transport->rtp_dtls_transport();
Zhi Huange818b6e2018-02-22 15:26:27 -0800316 if (!dtls) {
317 return nullptr;
318 }
319
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800320 return dtls->GetRemoteSSLCertChain();
Zhi Huange818b6e2018-02-22 15:26:27 -0800321}
322
323void JsepTransportController::MaybeStartGathering() {
324 if (!network_thread_->IsCurrent()) {
325 network_thread_->Invoke<void>(RTC_FROM_HERE,
326 [&] { MaybeStartGathering(); });
327 return;
328 }
329
330 for (auto& dtls : GetDtlsTransports()) {
331 dtls->ice_transport()->MaybeStartGathering();
332 }
333}
334
335RTCError JsepTransportController::AddRemoteCandidates(
336 const std::string& transport_name,
337 const cricket::Candidates& candidates) {
338 if (!network_thread_->IsCurrent()) {
339 return network_thread_->Invoke<RTCError>(RTC_FROM_HERE, [&] {
340 return AddRemoteCandidates(transport_name, candidates);
341 });
342 }
343
344 // Verify each candidate before passing down to the transport layer.
345 RTCError error = VerifyCandidates(candidates);
346 if (!error.ok()) {
347 return error;
348 }
Zhi Huange830e682018-03-30 10:48:35 -0700349 auto jsep_transport = GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800350 if (!jsep_transport) {
Zhi Huange830e682018-03-30 10:48:35 -0700351 RTC_LOG(LS_WARNING) << "Not adding candidate because the JsepTransport "
352 "doesn't exist. Ignore it.";
353 return RTCError::OK();
Zhi Huange818b6e2018-02-22 15:26:27 -0800354 }
Zhi Huange818b6e2018-02-22 15:26:27 -0800355 return jsep_transport->AddRemoteCandidates(candidates);
356}
357
358RTCError JsepTransportController::RemoveRemoteCandidates(
359 const cricket::Candidates& candidates) {
360 if (!network_thread_->IsCurrent()) {
361 return network_thread_->Invoke<RTCError>(
362 RTC_FROM_HERE, [&] { return RemoveRemoteCandidates(candidates); });
363 }
364
365 // Verify each candidate before passing down to the transport layer.
366 RTCError error = VerifyCandidates(candidates);
367 if (!error.ok()) {
368 return error;
369 }
370
371 std::map<std::string, cricket::Candidates> candidates_by_transport_name;
372 for (const cricket::Candidate& cand : candidates) {
373 if (!cand.transport_name().empty()) {
374 candidates_by_transport_name[cand.transport_name()].push_back(cand);
375 } else {
376 RTC_LOG(LS_ERROR) << "Not removing candidate because it does not have a "
377 "transport name set: "
378 << cand.ToString();
379 }
380 }
381
382 for (const auto& kv : candidates_by_transport_name) {
383 const std::string& transport_name = kv.first;
384 const cricket::Candidates& candidates = kv.second;
Zhi Huang365381f2018-04-13 16:44:34 -0700385 cricket::JsepTransport* jsep_transport =
Zhi Huange830e682018-03-30 10:48:35 -0700386 GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800387 if (!jsep_transport) {
Zhi Huange830e682018-03-30 10:48:35 -0700388 RTC_LOG(LS_WARNING)
389 << "Not removing candidate because the JsepTransport doesn't exist.";
390 continue;
Zhi Huange818b6e2018-02-22 15:26:27 -0800391 }
392 for (const cricket::Candidate& candidate : candidates) {
Harald Alvestrandad88c882018-11-28 16:47:46 +0100393 cricket::DtlsTransportInternal* dtls =
394 candidate.component() == cricket::ICE_CANDIDATE_COMPONENT_RTP
395 ? jsep_transport->rtp_dtls_transport()
396 : jsep_transport->rtcp_dtls_transport();
Zhi Huange818b6e2018-02-22 15:26:27 -0800397 if (dtls) {
398 dtls->ice_transport()->RemoveRemoteCandidate(candidate);
399 }
400 }
401 }
402 return RTCError::OK();
403}
404
405bool JsepTransportController::GetStats(const std::string& transport_name,
406 cricket::TransportStats* stats) {
407 if (!network_thread_->IsCurrent()) {
408 return network_thread_->Invoke<bool>(
409 RTC_FROM_HERE, [=] { return GetStats(transport_name, stats); });
410 }
411
Zhi Huang365381f2018-04-13 16:44:34 -0700412 cricket::JsepTransport* transport = GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800413 if (!transport) {
414 return false;
415 }
416 return transport->GetStats(stats);
417}
418
Zhi Huangb57e1692018-06-12 11:41:11 -0700419void JsepTransportController::SetActiveResetSrtpParams(
420 bool active_reset_srtp_params) {
421 if (!network_thread_->IsCurrent()) {
422 network_thread_->Invoke<void>(RTC_FROM_HERE, [=] {
423 SetActiveResetSrtpParams(active_reset_srtp_params);
424 });
425 return;
426 }
427
428 RTC_LOG(INFO)
429 << "Updating the active_reset_srtp_params for JsepTransportController: "
430 << active_reset_srtp_params;
431 config_.active_reset_srtp_params = active_reset_srtp_params;
432 for (auto& kv : jsep_transports_by_name_) {
433 kv.second->SetActiveResetSrtpParams(active_reset_srtp_params);
434 }
435}
436
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800437void JsepTransportController::SetMediaTransportSettings(
438 bool use_media_transport_for_media,
Anton Sukhanov316f3ac2019-05-23 15:50:38 -0700439 bool use_media_transport_for_data_channels,
440 bool use_datagram_transport) {
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800441 RTC_DCHECK(use_media_transport_for_media ==
442 config_.use_media_transport_for_media ||
Piotr (Peter) Slatala97fc11f2018-10-18 12:57:59 -0700443 jsep_transports_by_name_.empty())
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800444 << "You can only change media transport configuration before creating "
445 "the first transport.";
446
447 RTC_DCHECK(use_media_transport_for_data_channels ==
448 config_.use_media_transport_for_data_channels ||
449 jsep_transports_by_name_.empty())
450 << "You can only change media transport configuration before creating "
451 "the first transport.";
452
453 config_.use_media_transport_for_media = use_media_transport_for_media;
454 config_.use_media_transport_for_data_channels =
455 use_media_transport_for_data_channels;
Anton Sukhanov316f3ac2019-05-23 15:50:38 -0700456 config_.use_datagram_transport = use_datagram_transport;
Piotr (Peter) Slatala97fc11f2018-10-18 12:57:59 -0700457}
458
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800459std::unique_ptr<cricket::IceTransportInternal>
460JsepTransportController::CreateIceTransport(const std::string transport_name,
461 bool rtcp) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800462 int component = rtcp ? cricket::ICE_CANDIDATE_COMPONENT_RTCP
463 : cricket::ICE_CANDIDATE_COMPONENT_RTP;
464
Zhi Huange818b6e2018-02-22 15:26:27 -0800465 if (config_.external_transport_factory) {
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800466 return config_.external_transport_factory->CreateIceTransport(
Zhi Huange818b6e2018-02-22 15:26:27 -0800467 transport_name, component);
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800468 } else {
469 return absl::make_unique<cricket::P2PTransportChannel>(
470 transport_name, component, port_allocator_, async_resolver_factory_,
471 config_.event_log);
472 }
473}
474
475std::unique_ptr<cricket::DtlsTransportInternal>
476JsepTransportController::CreateDtlsTransport(
Bjorn A Mellem0c1c1b42019-05-29 17:34:13 -0700477 cricket::IceTransportInternal* ice,
Anton Sukhanov292ce4e2019-06-03 13:00:24 -0700478 DatagramTransportInterface* datagram_transport) {
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800479 RTC_DCHECK(network_thread_->IsCurrent());
480
481 std::unique_ptr<cricket::DtlsTransportInternal> dtls;
Anton Sukhanov316f3ac2019-05-23 15:50:38 -0700482
483 if (datagram_transport) {
484 RTC_DCHECK(config_.use_datagram_transport);
485
486 // Create DTLS wrapper around DatagramTransportInterface.
487 dtls = absl::make_unique<cricket::DatagramDtlsAdaptor>(
Anton Sukhanov292ce4e2019-06-03 13:00:24 -0700488 ice, datagram_transport, config_.crypto_options, config_.event_log);
Anton Sukhanov316f3ac2019-05-23 15:50:38 -0700489 } else if (config_.media_transport_factory &&
490 config_.use_media_transport_for_media &&
491 config_.use_media_transport_for_data_channels) {
492 // If media transport is used for both media and data channels,
493 // then we don't need to create DTLS.
494 // Otherwise, DTLS is still created.
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800495 dtls = absl::make_unique<cricket::NoOpDtlsTransport>(
Bjorn A Mellem0c1c1b42019-05-29 17:34:13 -0700496 ice, config_.crypto_options);
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800497 } else if (config_.external_transport_factory) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800498 dtls = config_.external_transport_factory->CreateDtlsTransport(
Bjorn A Mellem0c1c1b42019-05-29 17:34:13 -0700499 ice, config_.crypto_options);
Zhi Huange818b6e2018-02-22 15:26:27 -0800500 } else {
Zach Steinc64078f2018-11-27 15:53:01 -0800501 dtls = absl::make_unique<cricket::DtlsTransport>(
Bjorn A Mellem0c1c1b42019-05-29 17:34:13 -0700502 ice, config_.crypto_options, config_.event_log);
Zhi Huange818b6e2018-02-22 15:26:27 -0800503 }
504
505 RTC_DCHECK(dtls);
506 dtls->SetSslMaxProtocolVersion(config_.ssl_max_version);
Zhi Huange818b6e2018-02-22 15:26:27 -0800507 dtls->ice_transport()->SetIceRole(ice_role_);
508 dtls->ice_transport()->SetIceTiebreaker(ice_tiebreaker_);
509 dtls->ice_transport()->SetIceConfig(ice_config_);
510 if (certificate_) {
511 bool set_cert_success = dtls->SetLocalCertificate(certificate_);
512 RTC_DCHECK(set_cert_success);
513 }
514
515 // Connect to signals offered by the DTLS and ICE transport.
516 dtls->SignalWritableState.connect(
517 this, &JsepTransportController::OnTransportWritableState_n);
518 dtls->SignalReceivingState.connect(
519 this, &JsepTransportController::OnTransportReceivingState_n);
520 dtls->SignalDtlsHandshakeError.connect(
521 this, &JsepTransportController::OnDtlsHandshakeError);
522 dtls->ice_transport()->SignalGatheringState.connect(
523 this, &JsepTransportController::OnTransportGatheringState_n);
524 dtls->ice_transport()->SignalCandidateGathered.connect(
525 this, &JsepTransportController::OnTransportCandidateGathered_n);
526 dtls->ice_transport()->SignalCandidatesRemoved.connect(
527 this, &JsepTransportController::OnTransportCandidatesRemoved_n);
528 dtls->ice_transport()->SignalRoleConflict.connect(
529 this, &JsepTransportController::OnTransportRoleConflict_n);
530 dtls->ice_transport()->SignalStateChanged.connect(
531 this, &JsepTransportController::OnTransportStateChanged_n);
Jonas Olsson7a6739e2019-01-15 16:31:55 +0100532 dtls->ice_transport()->SignalIceTransportStateChanged.connect(
533 this, &JsepTransportController::OnTransportStateChanged_n);
Zhi Huange818b6e2018-02-22 15:26:27 -0800534 return dtls;
535}
536
537std::unique_ptr<webrtc::RtpTransport>
538JsepTransportController::CreateUnencryptedRtpTransport(
539 const std::string& transport_name,
540 rtc::PacketTransportInternal* rtp_packet_transport,
541 rtc::PacketTransportInternal* rtcp_packet_transport) {
542 RTC_DCHECK(network_thread_->IsCurrent());
Zhi Huange830e682018-03-30 10:48:35 -0700543 auto unencrypted_rtp_transport =
Karl Wiberg918f50c2018-07-05 11:40:33 +0200544 absl::make_unique<RtpTransport>(rtcp_packet_transport == nullptr);
Zhi Huange830e682018-03-30 10:48:35 -0700545 unencrypted_rtp_transport->SetRtpPacketTransport(rtp_packet_transport);
546 if (rtcp_packet_transport) {
547 unencrypted_rtp_transport->SetRtcpPacketTransport(rtcp_packet_transport);
548 }
549 return unencrypted_rtp_transport;
Zhi Huange818b6e2018-02-22 15:26:27 -0800550}
551
552std::unique_ptr<webrtc::SrtpTransport>
553JsepTransportController::CreateSdesTransport(
554 const std::string& transport_name,
Zhi Huange830e682018-03-30 10:48:35 -0700555 cricket::DtlsTransportInternal* rtp_dtls_transport,
556 cricket::DtlsTransportInternal* rtcp_dtls_transport) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800557 RTC_DCHECK(network_thread_->IsCurrent());
Zhi Huange818b6e2018-02-22 15:26:27 -0800558 auto srtp_transport =
Karl Wiberg918f50c2018-07-05 11:40:33 +0200559 absl::make_unique<webrtc::SrtpTransport>(rtcp_dtls_transport == nullptr);
Zhi Huange830e682018-03-30 10:48:35 -0700560 RTC_DCHECK(rtp_dtls_transport);
561 srtp_transport->SetRtpPacketTransport(rtp_dtls_transport);
562 if (rtcp_dtls_transport) {
563 srtp_transport->SetRtcpPacketTransport(rtcp_dtls_transport);
Zhi Huange818b6e2018-02-22 15:26:27 -0800564 }
565 if (config_.enable_external_auth) {
566 srtp_transport->EnableExternalAuth();
567 }
568 return srtp_transport;
569}
570
571std::unique_ptr<webrtc::DtlsSrtpTransport>
572JsepTransportController::CreateDtlsSrtpTransport(
573 const std::string& transport_name,
574 cricket::DtlsTransportInternal* rtp_dtls_transport,
575 cricket::DtlsTransportInternal* rtcp_dtls_transport) {
576 RTC_DCHECK(network_thread_->IsCurrent());
Karl Wiberg918f50c2018-07-05 11:40:33 +0200577 auto dtls_srtp_transport = absl::make_unique<webrtc::DtlsSrtpTransport>(
Zhi Huang365381f2018-04-13 16:44:34 -0700578 rtcp_dtls_transport == nullptr);
Zhi Huang27f3bf52018-03-26 21:37:23 -0700579 if (config_.enable_external_auth) {
Zhi Huang365381f2018-04-13 16:44:34 -0700580 dtls_srtp_transport->EnableExternalAuth();
Zhi Huang27f3bf52018-03-26 21:37:23 -0700581 }
Zhi Huang97d5e5b2018-03-27 00:09:01 +0000582
Zhi Huange818b6e2018-02-22 15:26:27 -0800583 dtls_srtp_transport->SetDtlsTransports(rtp_dtls_transport,
584 rtcp_dtls_transport);
Zhi Huangb57e1692018-06-12 11:41:11 -0700585 dtls_srtp_transport->SetActiveResetSrtpParams(
586 config_.active_reset_srtp_params);
Jonas Olsson635474e2018-10-18 15:58:17 +0200587 dtls_srtp_transport->SignalDtlsStateChange.connect(
588 this, &JsepTransportController::UpdateAggregateStates_n);
Zhi Huange818b6e2018-02-22 15:26:27 -0800589 return dtls_srtp_transport;
590}
591
592std::vector<cricket::DtlsTransportInternal*>
593JsepTransportController::GetDtlsTransports() {
594 std::vector<cricket::DtlsTransportInternal*> dtls_transports;
Zhi Huange830e682018-03-30 10:48:35 -0700595 for (auto it = jsep_transports_by_name_.begin();
596 it != jsep_transports_by_name_.end(); ++it) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800597 auto jsep_transport = it->second.get();
598 RTC_DCHECK(jsep_transport);
599 if (jsep_transport->rtp_dtls_transport()) {
600 dtls_transports.push_back(jsep_transport->rtp_dtls_transport());
601 }
602
603 if (jsep_transport->rtcp_dtls_transport()) {
604 dtls_transports.push_back(jsep_transport->rtcp_dtls_transport());
605 }
606 }
607 return dtls_transports;
608}
609
Zhi Huange818b6e2018-02-22 15:26:27 -0800610RTCError JsepTransportController::ApplyDescription_n(
611 bool local,
612 SdpType type,
613 const cricket::SessionDescription* description) {
614 RTC_DCHECK(network_thread_->IsCurrent());
615 RTC_DCHECK(description);
616
617 if (local) {
618 local_desc_ = description;
619 } else {
620 remote_desc_ = description;
621 }
622
Zhi Huange830e682018-03-30 10:48:35 -0700623 RTCError error;
Zhi Huangd2248f82018-04-10 14:41:03 -0700624 error = ValidateAndMaybeUpdateBundleGroup(local, type, description);
Zhi Huange830e682018-03-30 10:48:35 -0700625 if (!error.ok()) {
626 return error;
Zhi Huange818b6e2018-02-22 15:26:27 -0800627 }
628
629 std::vector<int> merged_encrypted_extension_ids;
630 if (bundle_group_) {
631 merged_encrypted_extension_ids =
632 MergeEncryptedHeaderExtensionIdsForBundle(description);
633 }
634
635 for (const cricket::ContentInfo& content_info : description->contents()) {
636 // Don't create transports for rejected m-lines and bundled m-lines."
637 if (content_info.rejected ||
638 (IsBundled(content_info.name) && content_info.name != *bundled_mid())) {
639 continue;
640 }
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -0800641 error = MaybeCreateJsepTransport(local, content_info, *description);
Zhi Huange830e682018-03-30 10:48:35 -0700642 if (!error.ok()) {
643 return error;
644 }
Zhi Huange818b6e2018-02-22 15:26:27 -0800645 }
646
647 RTC_DCHECK(description->contents().size() ==
648 description->transport_infos().size());
649 for (size_t i = 0; i < description->contents().size(); ++i) {
650 const cricket::ContentInfo& content_info = description->contents()[i];
651 const cricket::TransportInfo& transport_info =
652 description->transport_infos()[i];
653 if (content_info.rejected) {
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700654 HandleRejectedContent(content_info, description);
Zhi Huange818b6e2018-02-22 15:26:27 -0800655 continue;
656 }
657
658 if (IsBundled(content_info.name) && content_info.name != *bundled_mid()) {
Zhi Huang365381f2018-04-13 16:44:34 -0700659 if (!HandleBundledContent(content_info)) {
660 return RTCError(RTCErrorType::INVALID_PARAMETER,
661 "Failed to process the bundled m= section.");
662 }
Zhi Huange818b6e2018-02-22 15:26:27 -0800663 continue;
664 }
665
Zhi Huange830e682018-03-30 10:48:35 -0700666 error = ValidateContent(content_info);
667 if (!error.ok()) {
668 return error;
669 }
670
Zhi Huange818b6e2018-02-22 15:26:27 -0800671 std::vector<int> extension_ids;
Taylor Brandstetter0ab56512018-04-12 10:30:48 -0700672 if (bundled_mid() && content_info.name == *bundled_mid()) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800673 extension_ids = merged_encrypted_extension_ids;
674 } else {
675 extension_ids = GetEncryptedHeaderExtensionIds(content_info);
676 }
677
Zhi Huange830e682018-03-30 10:48:35 -0700678 int rtp_abs_sendtime_extn_id =
679 GetRtpAbsSendTimeHeaderExtensionId(content_info);
680
Zhi Huang365381f2018-04-13 16:44:34 -0700681 cricket::JsepTransport* transport =
Zhi Huange830e682018-03-30 10:48:35 -0700682 GetJsepTransportForMid(content_info.name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800683 RTC_DCHECK(transport);
684
685 SetIceRole_n(DetermineIceRole(transport, transport_info, type, local));
686
Zhi Huange818b6e2018-02-22 15:26:27 -0800687 cricket::JsepTransportDescription jsep_description =
688 CreateJsepTransportDescription(content_info, transport_info,
Zhi Huange830e682018-03-30 10:48:35 -0700689 extension_ids, rtp_abs_sendtime_extn_id);
Zhi Huange818b6e2018-02-22 15:26:27 -0800690 if (local) {
691 error =
692 transport->SetLocalJsepTransportDescription(jsep_description, type);
693 } else {
694 error =
695 transport->SetRemoteJsepTransportDescription(jsep_description, type);
696 }
697
698 if (!error.ok()) {
699 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
700 "Failed to apply the description for " +
701 content_info.name + ": " + error.message());
702 }
703 }
704 return RTCError::OK();
705}
706
Zhi Huangd2248f82018-04-10 14:41:03 -0700707RTCError JsepTransportController::ValidateAndMaybeUpdateBundleGroup(
708 bool local,
709 SdpType type,
Zhi Huange830e682018-03-30 10:48:35 -0700710 const cricket::SessionDescription* description) {
711 RTC_DCHECK(description);
Zhi Huangd2248f82018-04-10 14:41:03 -0700712 const cricket::ContentGroup* new_bundle_group =
713 description->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
714
715 // The BUNDLE group containing a MID that no m= section has is invalid.
716 if (new_bundle_group) {
Mirko Bonadei739baf02019-01-27 17:29:42 +0100717 for (const auto& content_name : new_bundle_group->content_names()) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700718 if (!description->GetContentByName(content_name)) {
719 return RTCError(RTCErrorType::INVALID_PARAMETER,
720 "The BUNDLE group contains MID:" + content_name +
721 " matching no m= section.");
722 }
723 }
724 }
725
726 if (type == SdpType::kAnswer) {
727 const cricket::ContentGroup* offered_bundle_group =
728 local ? remote_desc_->GetGroupByName(cricket::GROUP_TYPE_BUNDLE)
729 : local_desc_->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
730
731 if (new_bundle_group) {
732 // The BUNDLE group in answer should be a subset of offered group.
Mirko Bonadei739baf02019-01-27 17:29:42 +0100733 for (const auto& content_name : new_bundle_group->content_names()) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700734 if (!offered_bundle_group ||
735 !offered_bundle_group->HasContentName(content_name)) {
736 return RTCError(RTCErrorType::INVALID_PARAMETER,
737 "The BUNDLE group in answer contains a MID that was "
738 "not in the offered group.");
739 }
740 }
741 }
742
743 if (bundle_group_) {
Mirko Bonadei739baf02019-01-27 17:29:42 +0100744 for (const auto& content_name : bundle_group_->content_names()) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700745 // An answer that removes m= sections from pre-negotiated BUNDLE group
746 // without rejecting it, is invalid.
747 if (!new_bundle_group ||
748 !new_bundle_group->HasContentName(content_name)) {
749 auto* content_info = description->GetContentByName(content_name);
750 if (!content_info || !content_info->rejected) {
751 return RTCError(RTCErrorType::INVALID_PARAMETER,
752 "Answer cannot remove m= section " + content_name +
753 " from already-established BUNDLE group.");
754 }
755 }
756 }
757 }
758 }
759
760 if (config_.bundle_policy ==
761 PeerConnectionInterface::kBundlePolicyMaxBundle &&
762 !description->HasGroup(cricket::GROUP_TYPE_BUNDLE)) {
763 return RTCError(RTCErrorType::INVALID_PARAMETER,
764 "max-bundle is used but no bundle group found.");
765 }
766
767 if (ShouldUpdateBundleGroup(type, description)) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700768 bundle_group_ = *new_bundle_group;
769 }
Zhi Huange830e682018-03-30 10:48:35 -0700770
771 if (!bundled_mid()) {
772 return RTCError::OK();
773 }
774
775 auto bundled_content = description->GetContentByName(*bundled_mid());
776 if (!bundled_content) {
777 return RTCError(
778 RTCErrorType::INVALID_PARAMETER,
779 "An m= section associated with the BUNDLE-tag doesn't exist.");
780 }
781
782 // If the |bundled_content| is rejected, other contents in the bundle group
783 // should be rejected.
784 if (bundled_content->rejected) {
Mirko Bonadei739baf02019-01-27 17:29:42 +0100785 for (const auto& content_name : bundle_group_->content_names()) {
Zhi Huange830e682018-03-30 10:48:35 -0700786 auto other_content = description->GetContentByName(content_name);
787 if (!other_content->rejected) {
788 return RTCError(
789 RTCErrorType::INVALID_PARAMETER,
790 "The m= section:" + content_name + " should be rejected.");
791 }
792 }
793 }
794
795 return RTCError::OK();
796}
797
798RTCError JsepTransportController::ValidateContent(
799 const cricket::ContentInfo& content_info) {
800 if (config_.rtcp_mux_policy ==
801 PeerConnectionInterface::kRtcpMuxPolicyRequire &&
802 content_info.type == cricket::MediaProtocolType::kRtp &&
803 !content_info.media_description()->rtcp_mux()) {
804 return RTCError(RTCErrorType::INVALID_PARAMETER,
805 "The m= section:" + content_info.name +
806 " is invalid. RTCP-MUX is not "
807 "enabled when it is required.");
808 }
809 return RTCError::OK();
810}
811
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700812void JsepTransportController::HandleRejectedContent(
Zhi Huangd2248f82018-04-10 14:41:03 -0700813 const cricket::ContentInfo& content_info,
814 const cricket::SessionDescription* description) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800815 // If the content is rejected, let the
816 // BaseChannel/SctpTransport change the RtpTransport/DtlsTransport first,
Zhi Huang365381f2018-04-13 16:44:34 -0700817 // then destroy the cricket::JsepTransport.
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700818 RemoveTransportForMid(content_info.name);
Zhi Huange830e682018-03-30 10:48:35 -0700819 if (content_info.name == bundled_mid()) {
Mirko Bonadei739baf02019-01-27 17:29:42 +0100820 for (const auto& content_name : bundle_group_->content_names()) {
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700821 RemoveTransportForMid(content_name);
Zhi Huange830e682018-03-30 10:48:35 -0700822 }
823 bundle_group_.reset();
824 } else if (IsBundled(content_info.name)) {
825 // Remove the rejected content from the |bundle_group_|.
Zhi Huange818b6e2018-02-22 15:26:27 -0800826 bundle_group_->RemoveContentName(content_info.name);
Zhi Huange830e682018-03-30 10:48:35 -0700827 // Reset the bundle group if nothing left.
828 if (!bundle_group_->FirstContentName()) {
829 bundle_group_.reset();
830 }
Zhi Huange818b6e2018-02-22 15:26:27 -0800831 }
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700832 MaybeDestroyJsepTransport(content_info.name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800833}
834
Zhi Huang365381f2018-04-13 16:44:34 -0700835bool JsepTransportController::HandleBundledContent(
Zhi Huange818b6e2018-02-22 15:26:27 -0800836 const cricket::ContentInfo& content_info) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700837 auto jsep_transport = GetJsepTransportByName(*bundled_mid());
838 RTC_DCHECK(jsep_transport);
Zhi Huange818b6e2018-02-22 15:26:27 -0800839 // If the content is bundled, let the
840 // BaseChannel/SctpTransport change the RtpTransport/DtlsTransport first,
Zhi Huang365381f2018-04-13 16:44:34 -0700841 // then destroy the cricket::JsepTransport.
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700842 if (SetTransportForMid(content_info.name, jsep_transport)) {
Piotr (Peter) Slatala10aeb2a2018-11-14 10:57:24 -0800843 // TODO(bugs.webrtc.org/9719) For media transport this is far from ideal,
844 // because it means that we first create media transport and start
845 // connecting it, and then we destroy it. We will need to address it before
846 // video path is enabled.
Zhi Huang365381f2018-04-13 16:44:34 -0700847 MaybeDestroyJsepTransport(content_info.name);
848 return true;
849 }
850 return false;
Zhi Huange818b6e2018-02-22 15:26:27 -0800851}
852
Zhi Huang365381f2018-04-13 16:44:34 -0700853bool JsepTransportController::SetTransportForMid(
Zhi Huangd2248f82018-04-10 14:41:03 -0700854 const std::string& mid,
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700855 cricket::JsepTransport* jsep_transport) {
Zhi Huang365381f2018-04-13 16:44:34 -0700856 RTC_DCHECK(jsep_transport);
Zhi Huangd2248f82018-04-10 14:41:03 -0700857 if (mid_to_transport_[mid] == jsep_transport) {
Zhi Huang365381f2018-04-13 16:44:34 -0700858 return true;
Zhi Huangd2248f82018-04-10 14:41:03 -0700859 }
860
861 mid_to_transport_[mid] = jsep_transport;
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700862 return config_.transport_observer->OnTransportChanged(
Harald Alvestrandc85328f2019-02-28 07:51:00 +0100863 mid, jsep_transport->rtp_transport(), jsep_transport->RtpDtlsTransport(),
864 jsep_transport->media_transport());
Zhi Huangd2248f82018-04-10 14:41:03 -0700865}
866
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700867void JsepTransportController::RemoveTransportForMid(const std::string& mid) {
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -0800868 bool ret = config_.transport_observer->OnTransportChanged(mid, nullptr,
869 nullptr, nullptr);
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700870 // Calling OnTransportChanged with nullptr should always succeed, since it is
871 // only expected to fail when adding media to a transport (not removing).
872 RTC_DCHECK(ret);
Zhi Huangd2248f82018-04-10 14:41:03 -0700873 mid_to_transport_.erase(mid);
874}
875
Zhi Huange818b6e2018-02-22 15:26:27 -0800876cricket::JsepTransportDescription
877JsepTransportController::CreateJsepTransportDescription(
Harald Alvestrand1716d392019-06-03 20:35:45 +0200878 const cricket::ContentInfo& content_info,
879 const cricket::TransportInfo& transport_info,
Zhi Huange830e682018-03-30 10:48:35 -0700880 const std::vector<int>& encrypted_extension_ids,
881 int rtp_abs_sendtime_extn_id) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800882 const cricket::MediaContentDescription* content_desc =
Harald Alvestrand1716d392019-06-03 20:35:45 +0200883 content_info.media_description();
Zhi Huange818b6e2018-02-22 15:26:27 -0800884 RTC_DCHECK(content_desc);
885 bool rtcp_mux_enabled = content_info.type == cricket::MediaProtocolType::kSctp
886 ? true
887 : content_desc->rtcp_mux();
888
889 return cricket::JsepTransportDescription(
890 rtcp_mux_enabled, content_desc->cryptos(), encrypted_extension_ids,
Zhi Huange830e682018-03-30 10:48:35 -0700891 rtp_abs_sendtime_extn_id, transport_info.description);
Zhi Huange818b6e2018-02-22 15:26:27 -0800892}
893
894bool JsepTransportController::ShouldUpdateBundleGroup(
895 SdpType type,
896 const cricket::SessionDescription* description) {
897 if (config_.bundle_policy ==
898 PeerConnectionInterface::kBundlePolicyMaxBundle) {
899 return true;
900 }
901
902 if (type != SdpType::kAnswer) {
903 return false;
904 }
905
906 RTC_DCHECK(local_desc_ && remote_desc_);
907 const cricket::ContentGroup* local_bundle =
908 local_desc_->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
909 const cricket::ContentGroup* remote_bundle =
910 remote_desc_->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
911 return local_bundle && remote_bundle;
912}
913
914std::vector<int> JsepTransportController::GetEncryptedHeaderExtensionIds(
915 const cricket::ContentInfo& content_info) {
916 const cricket::MediaContentDescription* content_desc =
Harald Alvestrand1716d392019-06-03 20:35:45 +0200917 content_info.media_description();
Zhi Huange818b6e2018-02-22 15:26:27 -0800918
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700919 if (!config_.crypto_options.srtp.enable_encrypted_rtp_header_extensions) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800920 return std::vector<int>();
921 }
922
923 std::vector<int> encrypted_header_extension_ids;
Mirko Bonadei739baf02019-01-27 17:29:42 +0100924 for (const auto& extension : content_desc->rtp_header_extensions()) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800925 if (!extension.encrypt) {
926 continue;
927 }
Steve Anton64b626b2019-01-28 17:25:26 -0800928 if (!absl::c_linear_search(encrypted_header_extension_ids, extension.id)) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800929 encrypted_header_extension_ids.push_back(extension.id);
930 }
931 }
932 return encrypted_header_extension_ids;
933}
934
935std::vector<int>
936JsepTransportController::MergeEncryptedHeaderExtensionIdsForBundle(
937 const cricket::SessionDescription* description) {
938 RTC_DCHECK(description);
939 RTC_DCHECK(bundle_group_);
940
941 std::vector<int> merged_ids;
942 // Union the encrypted header IDs in the group when bundle is enabled.
943 for (const cricket::ContentInfo& content_info : description->contents()) {
944 if (bundle_group_->HasContentName(content_info.name)) {
945 std::vector<int> extension_ids =
946 GetEncryptedHeaderExtensionIds(content_info);
947 for (int id : extension_ids) {
Steve Anton64b626b2019-01-28 17:25:26 -0800948 if (!absl::c_linear_search(merged_ids, id)) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800949 merged_ids.push_back(id);
950 }
951 }
952 }
953 }
954 return merged_ids;
955}
956
Zhi Huange830e682018-03-30 10:48:35 -0700957int JsepTransportController::GetRtpAbsSendTimeHeaderExtensionId(
Zhi Huange818b6e2018-02-22 15:26:27 -0800958 const cricket::ContentInfo& content_info) {
Zhi Huange830e682018-03-30 10:48:35 -0700959 if (!config_.enable_external_auth) {
960 return -1;
Zhi Huange818b6e2018-02-22 15:26:27 -0800961 }
962
963 const cricket::MediaContentDescription* content_desc =
Harald Alvestrand1716d392019-06-03 20:35:45 +0200964 content_info.media_description();
Zhi Huange830e682018-03-30 10:48:35 -0700965
966 const webrtc::RtpExtension* send_time_extension =
967 webrtc::RtpExtension::FindHeaderExtensionByUri(
968 content_desc->rtp_header_extensions(),
969 webrtc::RtpExtension::kAbsSendTimeUri);
970 return send_time_extension ? send_time_extension->id : -1;
971}
972
Zhi Huang365381f2018-04-13 16:44:34 -0700973const cricket::JsepTransport* JsepTransportController::GetJsepTransportForMid(
Zhi Huange830e682018-03-30 10:48:35 -0700974 const std::string& mid) const {
Zhi Huangd2248f82018-04-10 14:41:03 -0700975 auto it = mid_to_transport_.find(mid);
976 return it == mid_to_transport_.end() ? nullptr : it->second;
Zhi Huange830e682018-03-30 10:48:35 -0700977}
978
Zhi Huang365381f2018-04-13 16:44:34 -0700979cricket::JsepTransport* JsepTransportController::GetJsepTransportForMid(
Zhi Huange830e682018-03-30 10:48:35 -0700980 const std::string& mid) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700981 auto it = mid_to_transport_.find(mid);
982 return it == mid_to_transport_.end() ? nullptr : it->second;
Zhi Huange830e682018-03-30 10:48:35 -0700983}
984
Zhi Huang365381f2018-04-13 16:44:34 -0700985const cricket::JsepTransport* JsepTransportController::GetJsepTransportByName(
Zhi Huange830e682018-03-30 10:48:35 -0700986 const std::string& transport_name) const {
987 auto it = jsep_transports_by_name_.find(transport_name);
988 return (it == jsep_transports_by_name_.end()) ? nullptr : it->second.get();
989}
990
Zhi Huang365381f2018-04-13 16:44:34 -0700991cricket::JsepTransport* JsepTransportController::GetJsepTransportByName(
Zhi Huange830e682018-03-30 10:48:35 -0700992 const std::string& transport_name) {
993 auto it = jsep_transports_by_name_.find(transport_name);
994 return (it == jsep_transports_by_name_.end()) ? nullptr : it->second.get();
995}
996
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -0800997std::unique_ptr<webrtc::MediaTransportInterface>
998JsepTransportController::MaybeCreateMediaTransport(
999 const cricket::ContentInfo& content_info,
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -08001000 const cricket::SessionDescription& description,
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001001 bool local) {
Piotr (Peter) Slatala63a176b2019-01-25 08:25:33 -08001002 if (config_.media_transport_factory == nullptr) {
1003 return nullptr;
1004 }
1005
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001006 if (!config_.use_media_transport_for_media &&
1007 !config_.use_media_transport_for_data_channels) {
1008 return nullptr;
1009 }
1010
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001011 // Caller (offerer) media transport.
1012 if (local) {
1013 if (offer_media_transport_) {
1014 RTC_LOG(LS_INFO) << "Offered media transport has now been activated.";
1015 return std::move(offer_media_transport_);
1016 } else {
1017 RTC_LOG(LS_INFO)
1018 << "Not returning media transport. Either SDES wasn't enabled, or "
1019 "media transport didn't return an offer earlier.";
1020 // Offer wasn't generated. Either because media transport didn't want it,
1021 // or because SDES wasn't enabled.
1022 return nullptr;
1023 }
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -07001024 }
1025
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001026 // Remote offer. If no x-mt lines, do not create media transport.
1027 if (description.MediaTransportSettings().empty()) {
Piotr (Peter) Slatala63a176b2019-01-25 08:25:33 -08001028 return nullptr;
Anton Sukhanov7940da02018-10-10 10:34:49 -07001029 }
1030
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001031 // When bundle is enabled, two JsepTransports are created, and then
1032 // the second transport is destroyed (right away).
1033 // For media transport, we don't want to create the second
1034 // media transport in the first place.
1035 RTC_LOG(LS_INFO) << "Returning new, client media transport.";
Piotr (Peter) Slatala63a176b2019-01-25 08:25:33 -08001036
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001037 RTC_DCHECK(!local)
1038 << "If media transport is used, you must call "
1039 "GenerateOrGetLastMediaTransportOffer before SetLocalDescription. You "
1040 "also "
1041 "must use kRtcpMuxPolicyRequire and kBundlePolicyMaxBundle with media "
1042 "transport.";
Piotr (Peter) Slatala63a176b2019-01-25 08:25:33 -08001043 MediaTransportSettings settings;
1044 settings.is_caller = local;
Piotr (Peter) Slatala01fe3092019-02-15 12:05:50 -08001045 if (config_.use_media_transport_for_media) {
1046 settings.event_log = config_.event_log;
1047 }
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -08001048
1049 // Assume there is only one media transport (or if more, use the first one).
1050 if (!local && !description.MediaTransportSettings().empty() &&
1051 config_.media_transport_factory->GetTransportName() ==
1052 description.MediaTransportSettings()[0].transport_name) {
1053 settings.remote_transport_parameters =
1054 description.MediaTransportSettings()[0].transport_setting;
1055 }
1056
Piotr (Peter) Slatala63a176b2019-01-25 08:25:33 -08001057 auto media_transport_result =
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001058 config_.media_transport_factory->CreateMediaTransport(network_thread_,
1059 settings);
Piotr (Peter) Slatala63a176b2019-01-25 08:25:33 -08001060
1061 // TODO(sukhanov): Proper error handling.
1062 RTC_CHECK(media_transport_result.ok());
1063
1064 return media_transport_result.MoveValue();
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001065}
1066
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001067// TODO(sukhanov): Refactor to avoid code duplication for Media and Datagram
1068// transports setup.
1069std::unique_ptr<webrtc::DatagramTransportInterface>
1070JsepTransportController::MaybeCreateDatagramTransport(
1071 const cricket::ContentInfo& content_info,
1072 const cricket::SessionDescription& description,
1073 bool local) {
1074 if (config_.media_transport_factory == nullptr) {
1075 return nullptr;
1076 }
1077
1078 if (!config_.use_datagram_transport) {
1079 return nullptr;
1080 }
1081
1082 // Caller (offerer) datagram transport.
1083 if (local) {
1084 if (offer_datagram_transport_) {
1085 RTC_LOG(LS_INFO) << "Offered datagram transport has now been activated.";
1086 return std::move(offer_datagram_transport_);
1087 } else {
1088 RTC_LOG(LS_INFO)
1089 << "Not returning datagram transport. Either SDES wasn't enabled, or "
1090 "datagram transport didn't return an offer earlier.";
1091 return nullptr;
1092 }
1093 }
1094
1095 // Remote offer. If no x-mt lines, do not create datagram transport.
1096 if (description.MediaTransportSettings().empty()) {
1097 return nullptr;
1098 }
1099
1100 // When bundle is enabled, two JsepTransports are created, and then
1101 // the second transport is destroyed (right away).
1102 // For datagram transport, we don't want to create the second
1103 // datagram transport in the first place.
1104 RTC_LOG(LS_INFO) << "Returning new, client datagram transport.";
1105
1106 RTC_DCHECK(!local)
1107 << "If datagram transport is used, you must call "
1108 "GenerateOrGetLastMediaTransportOffer before SetLocalDescription. You "
1109 "also must use kRtcpMuxPolicyRequire and kBundlePolicyMaxBundle with "
1110 "datagram transport.";
1111 MediaTransportSettings settings;
1112 settings.is_caller = local;
1113 settings.event_log = config_.event_log;
1114
1115 // Assume there is only one media transport (or if more, use the first one).
1116 if (!local && !description.MediaTransportSettings().empty() &&
1117 config_.media_transport_factory->GetTransportName() ==
1118 description.MediaTransportSettings()[0].transport_name) {
1119 settings.remote_transport_parameters =
1120 description.MediaTransportSettings()[0].transport_setting;
1121 }
1122
1123 auto datagram_transport_result =
1124 config_.media_transport_factory->CreateDatagramTransport(network_thread_,
1125 settings);
1126
1127 // TODO(sukhanov): Proper error handling.
1128 RTC_CHECK(datagram_transport_result.ok());
1129
1130 return datagram_transport_result.MoveValue();
1131}
1132
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001133RTCError JsepTransportController::MaybeCreateJsepTransport(
1134 bool local,
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -08001135 const cricket::ContentInfo& content_info,
1136 const cricket::SessionDescription& description) {
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001137 RTC_DCHECK(network_thread_->IsCurrent());
1138 cricket::JsepTransport* transport = GetJsepTransportByName(content_info.name);
1139 if (transport) {
1140 return RTCError::OK();
1141 }
1142
1143 const cricket::MediaContentDescription* content_desc =
Harald Alvestrand1716d392019-06-03 20:35:45 +02001144 content_info.media_description();
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001145 if (certificate_ && !content_desc->cryptos().empty()) {
1146 return RTCError(RTCErrorType::INVALID_PARAMETER,
1147 "SDES and DTLS-SRTP cannot be enabled at the same time.");
1148 }
1149
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001150 std::unique_ptr<cricket::IceTransportInternal> ice =
1151 CreateIceTransport(content_info.name, /*rtcp=*/false);
1152
1153 std::unique_ptr<MediaTransportInterface> media_transport =
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001154 MaybeCreateMediaTransport(content_info, description, local);
1155 if (media_transport) {
1156 media_transport_created_once_ = true;
1157 media_transport->Connect(ice.get());
1158 }
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001159
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001160 std::unique_ptr<DatagramTransportInterface> datagram_transport =
1161 MaybeCreateDatagramTransport(content_info, description, local);
1162 if (datagram_transport) {
1163 datagram_transport_created_once_ = true;
1164 datagram_transport->Connect(ice.get());
1165 }
1166
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001167 std::unique_ptr<cricket::DtlsTransportInternal> rtp_dtls_transport =
Anton Sukhanov292ce4e2019-06-03 13:00:24 -07001168 CreateDtlsTransport(ice.get(), datagram_transport.get());
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001169
1170 std::unique_ptr<cricket::DtlsTransportInternal> rtcp_dtls_transport;
1171 std::unique_ptr<RtpTransport> unencrypted_rtp_transport;
1172 std::unique_ptr<SrtpTransport> sdes_transport;
1173 std::unique_ptr<DtlsSrtpTransport> dtls_srtp_transport;
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001174
Bjorn A Mellem0c1c1b42019-05-29 17:34:13 -07001175 std::unique_ptr<cricket::IceTransportInternal> rtcp_ice;
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001176 if (config_.rtcp_mux_policy !=
1177 PeerConnectionInterface::kRtcpMuxPolicyRequire &&
1178 content_info.type == cricket::MediaProtocolType::kRtp) {
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001179 RTC_DCHECK(media_transport == nullptr);
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001180 RTC_DCHECK(datagram_transport == nullptr);
Bjorn A Mellem0c1c1b42019-05-29 17:34:13 -07001181 rtcp_ice = CreateIceTransport(content_info.name, /*rtcp=*/true);
1182 rtcp_dtls_transport = CreateDtlsTransport(rtcp_ice.get(),
1183 /*datagram_transport=*/nullptr);
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001184 }
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001185
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001186 if (datagram_transport) {
1187 // TODO(sukhanov): We use unencrypted RTP transport over DatagramTransport,
1188 // because MediaTransport encrypts. In the future we may want to
1189 // implement our own version of RtpTransport over MediaTransport, because
1190 // it will give us more control over things like:
1191 // - Fusing
1192 // - Rtp header compression
1193 // - Handling Rtcp feedback.
1194 RTC_LOG(LS_INFO) << "Creating UnencryptedRtpTransport, because datagram "
1195 "transport is used.";
1196 RTC_DCHECK(!rtcp_dtls_transport);
1197 unencrypted_rtp_transport = CreateUnencryptedRtpTransport(
1198 content_info.name, rtp_dtls_transport.get(), rtcp_dtls_transport.get());
1199 } else if (config_.disable_encryption) {
1200 RTC_LOG(LS_INFO)
1201 << "Creating UnencryptedRtpTransport, becayse encryption is disabled.";
Zhi Huange818b6e2018-02-22 15:26:27 -08001202 unencrypted_rtp_transport = CreateUnencryptedRtpTransport(
Zhi Huangd2248f82018-04-10 14:41:03 -07001203 content_info.name, rtp_dtls_transport.get(), rtcp_dtls_transport.get());
Zhi Huange818b6e2018-02-22 15:26:27 -08001204 } else if (!content_desc->cryptos().empty()) {
Zhi Huangd2248f82018-04-10 14:41:03 -07001205 sdes_transport = CreateSdesTransport(
1206 content_info.name, rtp_dtls_transport.get(), rtcp_dtls_transport.get());
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001207 RTC_LOG(LS_INFO) << "Creating SdesTransport.";
Zhi Huange818b6e2018-02-22 15:26:27 -08001208 } else {
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001209 RTC_LOG(LS_INFO) << "Creating DtlsSrtpTransport.";
Zhi Huangd2248f82018-04-10 14:41:03 -07001210 dtls_srtp_transport = CreateDtlsSrtpTransport(
1211 content_info.name, rtp_dtls_transport.get(), rtcp_dtls_transport.get());
Zhi Huange818b6e2018-02-22 15:26:27 -08001212 }
1213
Zhi Huang365381f2018-04-13 16:44:34 -07001214 std::unique_ptr<cricket::JsepTransport> jsep_transport =
Karl Wiberg918f50c2018-07-05 11:40:33 +02001215 absl::make_unique<cricket::JsepTransport>(
Bjorn A Mellem0c1c1b42019-05-29 17:34:13 -07001216 content_info.name, certificate_, std::move(ice), std::move(rtcp_ice),
1217 std::move(unencrypted_rtp_transport), std::move(sdes_transport),
1218 std::move(dtls_srtp_transport), std::move(rtp_dtls_transport),
Anton Sukhanov292ce4e2019-06-03 13:00:24 -07001219 std::move(rtcp_dtls_transport), std::move(media_transport),
1220 std::move(datagram_transport));
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001221
Zhi Huange818b6e2018-02-22 15:26:27 -08001222 jsep_transport->SignalRtcpMuxActive.connect(
1223 this, &JsepTransportController::UpdateAggregateStates_n);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001224 jsep_transport->SignalMediaTransportStateChanged.connect(
Bjorn Mellem175aa2e2018-11-08 11:23:22 -08001225 this, &JsepTransportController::OnMediaTransportStateChanged_n);
Taylor Brandstettercbaa2542018-04-16 16:42:14 -07001226 SetTransportForMid(content_info.name, jsep_transport.get());
Zhi Huange830e682018-03-30 10:48:35 -07001227
Zhi Huangd2248f82018-04-10 14:41:03 -07001228 jsep_transports_by_name_[content_info.name] = std::move(jsep_transport);
1229 UpdateAggregateStates_n();
Zhi Huange830e682018-03-30 10:48:35 -07001230 return RTCError::OK();
Zhi Huange818b6e2018-02-22 15:26:27 -08001231}
1232
1233void JsepTransportController::MaybeDestroyJsepTransport(
1234 const std::string& mid) {
Zhi Huangd2248f82018-04-10 14:41:03 -07001235 auto jsep_transport = GetJsepTransportByName(mid);
1236 if (!jsep_transport) {
1237 return;
1238 }
1239
1240 // Don't destroy the JsepTransport if there are still media sections referring
1241 // to it.
1242 for (const auto& kv : mid_to_transport_) {
1243 if (kv.second == jsep_transport) {
1244 return;
1245 }
1246 }
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -08001247
Zhi Huange830e682018-03-30 10:48:35 -07001248 jsep_transports_by_name_.erase(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -08001249 UpdateAggregateStates_n();
1250}
1251
1252void JsepTransportController::DestroyAllJsepTransports_n() {
1253 RTC_DCHECK(network_thread_->IsCurrent());
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -08001254
1255 for (const auto& jsep_transport : jsep_transports_by_name_) {
1256 config_.transport_observer->OnTransportChanged(jsep_transport.first,
1257 nullptr, nullptr, nullptr);
1258 }
1259
Zhi Huange830e682018-03-30 10:48:35 -07001260 jsep_transports_by_name_.clear();
Zhi Huange818b6e2018-02-22 15:26:27 -08001261}
1262
1263void JsepTransportController::SetIceRole_n(cricket::IceRole ice_role) {
1264 RTC_DCHECK(network_thread_->IsCurrent());
1265
1266 ice_role_ = ice_role;
1267 for (auto& dtls : GetDtlsTransports()) {
1268 dtls->ice_transport()->SetIceRole(ice_role_);
1269 }
1270}
1271
1272cricket::IceRole JsepTransportController::DetermineIceRole(
Zhi Huang365381f2018-04-13 16:44:34 -07001273 cricket::JsepTransport* jsep_transport,
Zhi Huange818b6e2018-02-22 15:26:27 -08001274 const cricket::TransportInfo& transport_info,
1275 SdpType type,
1276 bool local) {
1277 cricket::IceRole ice_role = ice_role_;
1278 auto tdesc = transport_info.description;
1279 if (local) {
1280 // The initial offer side may use ICE Lite, in which case, per RFC5245
1281 // Section 5.1.1, the answer side should take the controlling role if it is
1282 // in the full ICE mode.
1283 //
1284 // When both sides use ICE Lite, the initial offer side must take the
1285 // controlling role, and this is the default logic implemented in
1286 // SetLocalDescription in JsepTransportController.
1287 if (jsep_transport->remote_description() &&
1288 jsep_transport->remote_description()->transport_desc.ice_mode ==
1289 cricket::ICEMODE_LITE &&
1290 ice_role_ == cricket::ICEROLE_CONTROLLED &&
1291 tdesc.ice_mode == cricket::ICEMODE_FULL) {
1292 ice_role = cricket::ICEROLE_CONTROLLING;
1293 }
1294
1295 // Older versions of Chrome expect the ICE role to be re-determined when an
1296 // ICE restart occurs, and also don't perform conflict resolution correctly,
1297 // so for now we can't safely stop doing this, unless the application opts
1298 // in by setting |config_.redetermine_role_on_ice_restart_| to false. See:
1299 // https://bugs.chromium.org/p/chromium/issues/detail?id=628676
1300 // TODO(deadbeef): Remove this when these old versions of Chrome reach a low
1301 // enough population.
1302 if (config_.redetermine_role_on_ice_restart &&
1303 jsep_transport->local_description() &&
1304 cricket::IceCredentialsChanged(
1305 jsep_transport->local_description()->transport_desc.ice_ufrag,
1306 jsep_transport->local_description()->transport_desc.ice_pwd,
1307 tdesc.ice_ufrag, tdesc.ice_pwd) &&
1308 // Don't change the ICE role if the remote endpoint is ICE lite; we
1309 // should always be controlling in that case.
1310 (!jsep_transport->remote_description() ||
1311 jsep_transport->remote_description()->transport_desc.ice_mode !=
1312 cricket::ICEMODE_LITE)) {
1313 ice_role = (type == SdpType::kOffer) ? cricket::ICEROLE_CONTROLLING
1314 : cricket::ICEROLE_CONTROLLED;
1315 }
1316 } else {
1317 // If our role is cricket::ICEROLE_CONTROLLED and the remote endpoint
1318 // supports only ice_lite, this local endpoint should take the CONTROLLING
1319 // role.
1320 // TODO(deadbeef): This is a session-level attribute, so it really shouldn't
1321 // be in a TransportDescription in the first place...
1322 if (ice_role_ == cricket::ICEROLE_CONTROLLED &&
1323 tdesc.ice_mode == cricket::ICEMODE_LITE) {
1324 ice_role = cricket::ICEROLE_CONTROLLING;
1325 }
1326
1327 // If we use ICE Lite and the remote endpoint uses the full implementation
1328 // of ICE, the local endpoint must take the controlled role, and the other
1329 // side must be the controlling role.
1330 if (jsep_transport->local_description() &&
1331 jsep_transport->local_description()->transport_desc.ice_mode ==
1332 cricket::ICEMODE_LITE &&
1333 ice_role_ == cricket::ICEROLE_CONTROLLING &&
Zhi Huange830e682018-03-30 10:48:35 -07001334 tdesc.ice_mode == cricket::ICEMODE_FULL) {
Zhi Huange818b6e2018-02-22 15:26:27 -08001335 ice_role = cricket::ICEROLE_CONTROLLED;
1336 }
1337 }
1338
1339 return ice_role;
1340}
1341
1342void JsepTransportController::OnTransportWritableState_n(
1343 rtc::PacketTransportInternal* transport) {
1344 RTC_DCHECK(network_thread_->IsCurrent());
1345 RTC_LOG(LS_INFO) << " Transport " << transport->transport_name()
1346 << " writability changed to " << transport->writable()
1347 << ".";
1348 UpdateAggregateStates_n();
1349}
1350
1351void JsepTransportController::OnTransportReceivingState_n(
1352 rtc::PacketTransportInternal* transport) {
1353 RTC_DCHECK(network_thread_->IsCurrent());
1354 UpdateAggregateStates_n();
1355}
1356
1357void JsepTransportController::OnTransportGatheringState_n(
1358 cricket::IceTransportInternal* transport) {
1359 RTC_DCHECK(network_thread_->IsCurrent());
1360 UpdateAggregateStates_n();
1361}
1362
1363void JsepTransportController::OnTransportCandidateGathered_n(
1364 cricket::IceTransportInternal* transport,
1365 const cricket::Candidate& candidate) {
1366 RTC_DCHECK(network_thread_->IsCurrent());
1367
1368 // We should never signal peer-reflexive candidates.
1369 if (candidate.type() == cricket::PRFLX_PORT_TYPE) {
1370 RTC_NOTREACHED();
1371 return;
1372 }
Steve Antond25828a2018-08-31 13:06:05 -07001373 std::string transport_name = transport->transport_name();
1374 invoker_.AsyncInvoke<void>(
1375 RTC_FROM_HERE, signaling_thread_, [this, transport_name, candidate] {
1376 SignalIceCandidatesGathered(transport_name, {candidate});
1377 });
Zhi Huange818b6e2018-02-22 15:26:27 -08001378}
1379
1380void JsepTransportController::OnTransportCandidatesRemoved_n(
1381 cricket::IceTransportInternal* transport,
1382 const cricket::Candidates& candidates) {
1383 invoker_.AsyncInvoke<void>(
1384 RTC_FROM_HERE, signaling_thread_,
Steve Antond25828a2018-08-31 13:06:05 -07001385 [this, candidates] { SignalIceCandidatesRemoved(candidates); });
Zhi Huange818b6e2018-02-22 15:26:27 -08001386}
1387
1388void JsepTransportController::OnTransportRoleConflict_n(
1389 cricket::IceTransportInternal* transport) {
1390 RTC_DCHECK(network_thread_->IsCurrent());
1391 // Note: since the role conflict is handled entirely on the network thread,
1392 // we don't need to worry about role conflicts occurring on two ports at
1393 // once. The first one encountered should immediately reverse the role.
1394 cricket::IceRole reversed_role = (ice_role_ == cricket::ICEROLE_CONTROLLING)
1395 ? cricket::ICEROLE_CONTROLLED
1396 : cricket::ICEROLE_CONTROLLING;
1397 RTC_LOG(LS_INFO) << "Got role conflict; switching to "
1398 << (reversed_role == cricket::ICEROLE_CONTROLLING
1399 ? "controlling"
1400 : "controlled")
1401 << " role.";
1402 SetIceRole_n(reversed_role);
1403}
1404
1405void JsepTransportController::OnTransportStateChanged_n(
1406 cricket::IceTransportInternal* transport) {
1407 RTC_DCHECK(network_thread_->IsCurrent());
1408 RTC_LOG(LS_INFO) << transport->transport_name() << " Transport "
1409 << transport->component()
1410 << " state changed. Check if state is complete.";
1411 UpdateAggregateStates_n();
1412}
1413
Bjorn Mellem175aa2e2018-11-08 11:23:22 -08001414void JsepTransportController::OnMediaTransportStateChanged_n() {
1415 SignalMediaTransportStateChanged();
1416 UpdateAggregateStates_n();
1417}
1418
Zhi Huange818b6e2018-02-22 15:26:27 -08001419void JsepTransportController::UpdateAggregateStates_n() {
1420 RTC_DCHECK(network_thread_->IsCurrent());
1421
1422 auto dtls_transports = GetDtlsTransports();
Alex Loiko9289eda2018-11-23 16:18:59 +00001423 cricket::IceConnectionState new_connection_state =
1424 cricket::kIceConnectionConnecting;
Jonas Olsson635474e2018-10-18 15:58:17 +02001425 PeerConnectionInterface::IceConnectionState new_ice_connection_state =
1426 PeerConnectionInterface::IceConnectionState::kIceConnectionNew;
1427 PeerConnectionInterface::PeerConnectionState new_combined_state =
1428 PeerConnectionInterface::PeerConnectionState::kNew;
Zhi Huange818b6e2018-02-22 15:26:27 -08001429 cricket::IceGatheringState new_gathering_state = cricket::kIceGatheringNew;
Alex Loiko9289eda2018-11-23 16:18:59 +00001430 bool any_failed = false;
1431
1432 // TODO(http://bugs.webrtc.org/9719) If(when) media_transport disables
1433 // dtls_transports entirely, the below line will have to be changed to account
1434 // for the fact that dtls transports might be absent.
1435 bool all_connected = !dtls_transports.empty();
1436 bool all_completed = !dtls_transports.empty();
Zhi Huange818b6e2018-02-22 15:26:27 -08001437 bool any_gathering = false;
1438 bool all_done_gathering = !dtls_transports.empty();
Jonas Olsson635474e2018-10-18 15:58:17 +02001439
1440 std::map<IceTransportState, int> ice_state_counts;
1441 std::map<cricket::DtlsTransportState, int> dtls_state_counts;
1442
Zhi Huange818b6e2018-02-22 15:26:27 -08001443 for (const auto& dtls : dtls_transports) {
Alex Loiko9289eda2018-11-23 16:18:59 +00001444 any_failed = any_failed || dtls->ice_transport()->GetState() ==
1445 cricket::IceTransportState::STATE_FAILED;
1446 all_connected = all_connected && dtls->writable();
1447 all_completed =
1448 all_completed && dtls->writable() &&
1449 dtls->ice_transport()->GetState() ==
1450 cricket::IceTransportState::STATE_COMPLETED &&
1451 dtls->ice_transport()->GetIceRole() == cricket::ICEROLE_CONTROLLING &&
1452 dtls->ice_transport()->gathering_state() ==
1453 cricket::kIceGatheringComplete;
Zhi Huange818b6e2018-02-22 15:26:27 -08001454 any_gathering = any_gathering || dtls->ice_transport()->gathering_state() !=
1455 cricket::kIceGatheringNew;
1456 all_done_gathering =
1457 all_done_gathering && dtls->ice_transport()->gathering_state() ==
1458 cricket::kIceGatheringComplete;
Jonas Olsson635474e2018-10-18 15:58:17 +02001459
1460 dtls_state_counts[dtls->dtls_state()]++;
1461 ice_state_counts[dtls->ice_transport()->GetIceTransportState()]++;
Zhi Huange818b6e2018-02-22 15:26:27 -08001462 }
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001463
Alex Loiko9289eda2018-11-23 16:18:59 +00001464 for (auto it = jsep_transports_by_name_.begin();
1465 it != jsep_transports_by_name_.end(); ++it) {
1466 auto jsep_transport = it->second.get();
1467 if (!jsep_transport->media_transport()) {
1468 continue;
1469 }
1470
1471 // There is no 'kIceConnectionDisconnected', so we only need to handle
1472 // connected and completed.
1473 // We treat kClosed as failed, because if it happens before shutting down
1474 // media transports it means that there was a failure.
1475 // MediaTransportInterface allows to flip back and forth between kWritable
1476 // and kPending, but there does not exist an implementation that does that,
1477 // and the contract of jsep transport controller doesn't quite expect that.
1478 // When this happens, we would go from connected to connecting state, but
1479 // this may change in future.
1480 any_failed |= jsep_transport->media_transport_state() ==
1481 webrtc::MediaTransportState::kClosed;
1482 all_completed &= jsep_transport->media_transport_state() ==
1483 webrtc::MediaTransportState::kWritable;
1484 all_connected &= jsep_transport->media_transport_state() ==
1485 webrtc::MediaTransportState::kWritable;
1486 }
1487
1488 if (any_failed) {
1489 new_connection_state = cricket::kIceConnectionFailed;
1490 } else if (all_completed) {
1491 new_connection_state = cricket::kIceConnectionCompleted;
1492 } else if (all_connected) {
1493 new_connection_state = cricket::kIceConnectionConnected;
1494 }
1495 if (ice_connection_state_ != new_connection_state) {
1496 ice_connection_state_ = new_connection_state;
1497 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_,
1498 [this, new_connection_state] {
1499 SignalIceConnectionState(new_connection_state);
1500 });
1501 }
1502
Jonas Olsson635474e2018-10-18 15:58:17 +02001503 // Compute the current RTCIceConnectionState as described in
1504 // https://www.w3.org/TR/webrtc/#dom-rtciceconnectionstate.
1505 // The PeerConnection is responsible for handling the "closed" state.
1506 int total_ice_checking = ice_state_counts[IceTransportState::kChecking];
1507 int total_ice_connected = ice_state_counts[IceTransportState::kConnected];
1508 int total_ice_completed = ice_state_counts[IceTransportState::kCompleted];
1509 int total_ice_failed = ice_state_counts[IceTransportState::kFailed];
1510 int total_ice_disconnected =
1511 ice_state_counts[IceTransportState::kDisconnected];
1512 int total_ice_closed = ice_state_counts[IceTransportState::kClosed];
1513 int total_ice_new = ice_state_counts[IceTransportState::kNew];
1514 int total_ice = dtls_transports.size();
1515
1516 if (total_ice_failed > 0) {
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001517 // Any RTCIceTransports are in the "failed" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001518 new_ice_connection_state = PeerConnectionInterface::kIceConnectionFailed;
Alex Loiko9289eda2018-11-23 16:18:59 +00001519 } else if (total_ice_disconnected > 0) {
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001520 // None of the previous states apply and any RTCIceTransports are in the
1521 // "disconnected" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001522 new_ice_connection_state =
1523 PeerConnectionInterface::kIceConnectionDisconnected;
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001524 } else if (total_ice_new + total_ice_closed == total_ice) {
1525 // None of the previous states apply and all RTCIceTransports are in the
1526 // "new" or "closed" state, or there are no transports.
1527 new_ice_connection_state = PeerConnectionInterface::kIceConnectionNew;
1528 } else if (total_ice_new + total_ice_checking > 0) {
1529 // None of the previous states apply and any RTCIceTransports are in the
1530 // "new" or "checking" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001531 new_ice_connection_state = PeerConnectionInterface::kIceConnectionChecking;
Jonas Olssonacd8ae72019-02-25 15:26:24 +01001532 } else if (total_ice_completed + total_ice_closed == total_ice ||
1533 all_completed) {
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001534 // None of the previous states apply and all RTCIceTransports are in the
1535 // "completed" or "closed" state.
Jonas Olssonacd8ae72019-02-25 15:26:24 +01001536 //
1537 // TODO(https://bugs.webrtc.org/10356): The all_completed condition is added
1538 // to mimic the behavior of the old ICE connection state, and should be
1539 // removed once we get end-of-candidates signaling in place.
Jonas Olsson635474e2018-10-18 15:58:17 +02001540 new_ice_connection_state = PeerConnectionInterface::kIceConnectionCompleted;
1541 } else if (total_ice_connected + total_ice_completed + total_ice_closed ==
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001542 total_ice) {
1543 // None of the previous states apply and all RTCIceTransports are in the
1544 // "connected", "completed" or "closed" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001545 new_ice_connection_state = PeerConnectionInterface::kIceConnectionConnected;
Jonas Olsson635474e2018-10-18 15:58:17 +02001546 } else {
1547 RTC_NOTREACHED();
1548 }
1549
Alex Loiko9289eda2018-11-23 16:18:59 +00001550 if (standardized_ice_connection_state_ != new_ice_connection_state) {
Jonas Olssonacd8ae72019-02-25 15:26:24 +01001551 if (standardized_ice_connection_state_ ==
1552 PeerConnectionInterface::kIceConnectionChecking &&
1553 new_ice_connection_state ==
1554 PeerConnectionInterface::kIceConnectionCompleted) {
1555 // Ensure that we never skip over the "connected" state.
1556 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_, [this] {
1557 SignalStandardizedIceConnectionState(
1558 PeerConnectionInterface::kIceConnectionConnected);
1559 });
1560 }
Alex Loiko9289eda2018-11-23 16:18:59 +00001561 standardized_ice_connection_state_ = new_ice_connection_state;
Jonas Olsson635474e2018-10-18 15:58:17 +02001562 invoker_.AsyncInvoke<void>(
1563 RTC_FROM_HERE, signaling_thread_, [this, new_ice_connection_state] {
Alex Loiko9289eda2018-11-23 16:18:59 +00001564 SignalStandardizedIceConnectionState(new_ice_connection_state);
Jonas Olsson635474e2018-10-18 15:58:17 +02001565 });
1566 }
1567
1568 // Compute the current RTCPeerConnectionState as described in
1569 // https://www.w3.org/TR/webrtc/#dom-rtcpeerconnectionstate.
1570 // The PeerConnection is responsible for handling the "closed" state.
1571 // Note that "connecting" is only a valid state for DTLS transports while
1572 // "checking", "completed" and "disconnected" are only valid for ICE
1573 // transports.
1574 int total_connected = total_ice_connected +
1575 dtls_state_counts[cricket::DTLS_TRANSPORT_CONNECTED];
1576 int total_dtls_connecting =
1577 dtls_state_counts[cricket::DTLS_TRANSPORT_CONNECTING];
1578 int total_failed =
1579 total_ice_failed + dtls_state_counts[cricket::DTLS_TRANSPORT_FAILED];
1580 int total_closed =
1581 total_ice_closed + dtls_state_counts[cricket::DTLS_TRANSPORT_CLOSED];
1582 int total_new =
1583 total_ice_new + dtls_state_counts[cricket::DTLS_TRANSPORT_NEW];
1584 int total_transports = total_ice * 2;
1585
1586 if (total_failed > 0) {
1587 // Any of the RTCIceTransports or RTCDtlsTransports are in a "failed" state.
1588 new_combined_state = PeerConnectionInterface::PeerConnectionState::kFailed;
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001589 } else if (total_ice_disconnected > 0) {
1590 // None of the previous states apply and any RTCIceTransports or
1591 // RTCDtlsTransports are in the "disconnected" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001592 new_combined_state =
1593 PeerConnectionInterface::PeerConnectionState::kDisconnected;
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001594 } else if (total_new + total_closed == total_transports) {
1595 // None of the previous states apply and all RTCIceTransports and
1596 // RTCDtlsTransports are in the "new" or "closed" state, or there are no
1597 // transports.
1598 new_combined_state = PeerConnectionInterface::PeerConnectionState::kNew;
1599 } else if (total_new + total_dtls_connecting + total_ice_checking > 0) {
1600 // None of the previous states apply and all RTCIceTransports or
1601 // RTCDtlsTransports are in the "new", "connecting" or "checking" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001602 new_combined_state =
1603 PeerConnectionInterface::PeerConnectionState::kConnecting;
1604 } else if (total_connected + total_ice_completed + total_closed ==
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001605 total_transports) {
1606 // None of the previous states apply and all RTCIceTransports and
1607 // RTCDtlsTransports are in the "connected", "completed" or "closed" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001608 new_combined_state =
1609 PeerConnectionInterface::PeerConnectionState::kConnected;
Jonas Olsson635474e2018-10-18 15:58:17 +02001610 } else {
1611 RTC_NOTREACHED();
1612 }
1613
1614 if (combined_connection_state_ != new_combined_state) {
1615 combined_connection_state_ = new_combined_state;
1616 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_,
1617 [this, new_combined_state] {
1618 SignalConnectionState(new_combined_state);
1619 });
1620 }
1621
Zhi Huange818b6e2018-02-22 15:26:27 -08001622 if (all_done_gathering) {
1623 new_gathering_state = cricket::kIceGatheringComplete;
1624 } else if (any_gathering) {
1625 new_gathering_state = cricket::kIceGatheringGathering;
1626 }
1627 if (ice_gathering_state_ != new_gathering_state) {
1628 ice_gathering_state_ = new_gathering_state;
Steve Antond25828a2018-08-31 13:06:05 -07001629 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_,
1630 [this, new_gathering_state] {
1631 SignalIceGatheringState(new_gathering_state);
1632 });
Zhi Huange818b6e2018-02-22 15:26:27 -08001633 }
1634}
1635
1636void JsepTransportController::OnDtlsHandshakeError(
1637 rtc::SSLHandshakeError error) {
1638 SignalDtlsHandshakeError(error);
1639}
1640
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001641absl::optional<cricket::SessionDescription::MediaTransportSetting>
1642JsepTransportController::GenerateOrGetLastMediaTransportOffer() {
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001643 if (media_transport_created_once_ || datagram_transport_created_once_) {
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001644 RTC_LOG(LS_INFO) << "Not regenerating media transport for the new offer in "
1645 "existing session.";
1646 return media_transport_offer_settings_;
1647 }
1648
1649 RTC_LOG(LS_INFO) << "Generating media transport offer!";
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001650
1651 absl::optional<std::string> transport_parameters;
1652
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001653 // Check that media transport is supposed to be used.
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001654 // Note that ICE is not available when media transport is created. It will
1655 // only be available in 'Connect'. This may be a potential server config, if
1656 // we decide to use this peer connection as a caller, not as a callee.
1657 // TODO(sukhanov): Avoid code duplication with CreateMedia/MediaTransport.
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001658 if (config_.use_media_transport_for_media ||
1659 config_.use_media_transport_for_data_channels) {
1660 RTC_DCHECK(config_.media_transport_factory != nullptr);
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001661 RTC_DCHECK(!config_.use_datagram_transport);
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001662 webrtc::MediaTransportSettings settings;
1663 settings.is_caller = true;
1664 settings.pre_shared_key = rtc::CreateRandomString(32);
1665 settings.event_log = config_.event_log;
1666 auto media_transport_or_error =
1667 config_.media_transport_factory->CreateMediaTransport(network_thread_,
1668 settings);
1669
1670 if (media_transport_or_error.ok()) {
1671 offer_media_transport_ = std::move(media_transport_or_error.value());
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001672 transport_parameters =
1673 offer_media_transport_->GetTransportParametersOffer();
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001674 } else {
1675 RTC_LOG(LS_INFO) << "Unable to create media transport, error="
1676 << media_transport_or_error.error().message();
1677 }
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001678 } else if (config_.use_datagram_transport) {
1679 webrtc::MediaTransportSettings settings;
1680 settings.is_caller = true;
1681 settings.pre_shared_key = rtc::CreateRandomString(32);
1682 settings.event_log = config_.event_log;
1683 auto datagram_transport_or_error =
1684 config_.media_transport_factory->CreateDatagramTransport(
1685 network_thread_, settings);
1686
1687 if (datagram_transport_or_error.ok()) {
1688 offer_datagram_transport_ =
1689 std::move(datagram_transport_or_error.value());
1690 transport_parameters =
1691 offer_datagram_transport_->GetTransportParametersOffer();
1692 } else {
1693 RTC_LOG(LS_INFO) << "Unable to create media transport, error="
1694 << datagram_transport_or_error.error().message();
1695 }
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001696 }
1697
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001698 if (!offer_media_transport_ && !offer_datagram_transport_) {
1699 RTC_LOG(LS_INFO) << "Media and data transports do not exist";
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001700 return absl::nullopt;
1701 }
1702
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001703 if (!transport_parameters) {
1704 RTC_LOG(LS_INFO) << "Media transport didn't generate the offer";
1705 // Media transport didn't generate the offer, and is not supposed to be
1706 // used. Destroy the temporary media transport.
1707 offer_media_transport_ = nullptr;
1708 return absl::nullopt;
1709 }
1710
1711 cricket::SessionDescription::MediaTransportSetting setting;
1712 setting.transport_name = config_.media_transport_factory->GetTransportName();
1713 setting.transport_setting = *transport_parameters;
1714 media_transport_offer_settings_ = setting;
1715 return setting;
1716}
1717
Zhi Huange818b6e2018-02-22 15:26:27 -08001718} // namespace webrtc