blob: d83b16e9b39d229ed4594daefb2cb0ce864e6b02 [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"
Niels Möller65f17ca2019-09-12 13:59:36 +020017#include "api/transport/datagram_transport_interface.h"
18#include "api/transport/media/media_transport_interface.h"
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -080019#include "p2p/base/ice_transport_internal.h"
20#include "p2p/base/no_op_dtls_transport.h"
Zhi Huange818b6e2018-02-22 15:26:27 -080021#include "p2p/base/port.h"
Bjorn A Mellem364b2672019-08-20 16:58:03 -070022#include "pc/datagram_rtp_transport.h"
Steve Anton10542f22019-01-11 09:11:00 -080023#include "pc/srtp_filter.h"
Zhi Huange818b6e2018-02-22 15:26:27 -080024#include "rtc_base/bind.h"
25#include "rtc_base/checks.h"
Zhi Huange818b6e2018-02-22 15:26:27 -080026#include "rtc_base/thread.h"
27
28using webrtc::SdpType;
29
30namespace {
31
Zhi Huange818b6e2018-02-22 15:26:27 -080032webrtc::RTCError VerifyCandidate(const cricket::Candidate& cand) {
33 // No address zero.
34 if (cand.address().IsNil() || cand.address().IsAnyIP()) {
35 return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
36 "candidate has address of zero");
37 }
38
39 // Disallow all ports below 1024, except for 80 and 443 on public addresses.
40 int port = cand.address().port();
41 if (cand.protocol() == cricket::TCP_PROTOCOL_NAME &&
42 (cand.tcptype() == cricket::TCPTYPE_ACTIVE_STR || port == 0)) {
43 // Expected for active-only candidates per
44 // http://tools.ietf.org/html/rfc6544#section-4.5 so no error.
45 // Libjingle clients emit port 0, in "active" mode.
46 return webrtc::RTCError::OK();
47 }
48 if (port < 1024) {
49 if ((port != 80) && (port != 443)) {
50 return webrtc::RTCError(
51 webrtc::RTCErrorType::INVALID_PARAMETER,
52 "candidate has port below 1024, but not 80 or 443");
53 }
54
55 if (cand.address().IsPrivateIP()) {
56 return webrtc::RTCError(
57 webrtc::RTCErrorType::INVALID_PARAMETER,
58 "candidate has port of 80 or 443 with private IP address");
59 }
60 }
61
62 return webrtc::RTCError::OK();
63}
64
65webrtc::RTCError VerifyCandidates(const cricket::Candidates& candidates) {
66 for (const cricket::Candidate& candidate : candidates) {
67 webrtc::RTCError error = VerifyCandidate(candidate);
68 if (!error.ok()) {
69 return error;
70 }
71 }
72 return webrtc::RTCError::OK();
73}
74
75} // namespace
76
77namespace webrtc {
78
79JsepTransportController::JsepTransportController(
80 rtc::Thread* signaling_thread,
81 rtc::Thread* network_thread,
82 cricket::PortAllocator* port_allocator,
Zach Steine20867f2018-08-02 13:20:15 -070083 AsyncResolverFactory* async_resolver_factory,
Zhi Huange818b6e2018-02-22 15:26:27 -080084 Config config)
85 : signaling_thread_(signaling_thread),
86 network_thread_(network_thread),
87 port_allocator_(port_allocator),
Zach Steine20867f2018-08-02 13:20:15 -070088 async_resolver_factory_(async_resolver_factory),
Zhi Huang365381f2018-04-13 16:44:34 -070089 config_(config) {
90 // The |transport_observer| is assumed to be non-null.
91 RTC_DCHECK(config_.transport_observer);
Sebastian Jansson1b83a9e2019-09-18 18:22:12 +020092 RTC_DCHECK(config_.rtcp_handler);
Zhi Huang365381f2018-04-13 16:44:34 -070093}
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
Bjorn A Mellemb689af42019-08-21 10:44:59 -0700154 DatagramTransportInterface* datagram_transport = nullptr;
155 if (config_.use_datagram_transport) {
156 datagram_transport = jsep_transport->datagram_transport();
157 }
Anton Sukhanov316f3ac2019-05-23 15:50:38 -0700158
159 // Media transport and datagram transports can not be used together.
160 RTC_DCHECK(!media_transport || !datagram_transport);
161
162 if (media_transport) {
163 return MediaTransportConfig(media_transport);
164 } else if (datagram_transport) {
165 return MediaTransportConfig(
166 /*rtp_max_packet_size=*/datagram_transport->GetLargestDatagramSize());
167 } else {
168 return MediaTransportConfig();
169 }
170}
171
Bjorn A Mellemb689af42019-08-21 10:44:59 -0700172DataChannelTransportInterface* JsepTransportController::GetDataChannelTransport(
Anton Sukhanov316f3ac2019-05-23 15:50:38 -0700173 const std::string& mid) const {
174 auto jsep_transport = GetJsepTransportForMid(mid);
Bjorn A Mellemb689af42019-08-21 10:44:59 -0700175 if (!jsep_transport) {
Anton Sukhanov7940da02018-10-10 10:34:49 -0700176 return nullptr;
177 }
Bjorn A Mellembc3eebc2019-09-23 14:53:54 -0700178 return jsep_transport->data_channel_transport();
Anton Sukhanov7940da02018-10-10 10:34:49 -0700179}
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
Bjorn A Mellembc3eebc2019-09-23 14:53:54 -0700217rtc::scoped_refptr<SctpTransport> JsepTransportController::GetSctpTransport(
218 const std::string& mid) const {
219 auto jsep_transport = GetJsepTransportForMid(mid);
220 if (!jsep_transport) {
221 return nullptr;
222 }
223 return jsep_transport->SctpTransport();
224}
225
Zhi Huange818b6e2018-02-22 15:26:27 -0800226void JsepTransportController::SetIceConfig(const cricket::IceConfig& config) {
227 if (!network_thread_->IsCurrent()) {
228 network_thread_->Invoke<void>(RTC_FROM_HERE, [&] { SetIceConfig(config); });
229 return;
230 }
231
232 ice_config_ = config;
233 for (auto& dtls : GetDtlsTransports()) {
234 dtls->ice_transport()->SetIceConfig(ice_config_);
235 }
236}
237
238void JsepTransportController::SetNeedsIceRestartFlag() {
Zhi Huange830e682018-03-30 10:48:35 -0700239 for (auto& kv : jsep_transports_by_name_) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800240 kv.second->SetNeedsIceRestartFlag();
241 }
242}
243
244bool JsepTransportController::NeedsIceRestart(
245 const std::string& transport_name) const {
Zhi Huang365381f2018-04-13 16:44:34 -0700246 const cricket::JsepTransport* transport =
Zhi Huange830e682018-03-30 10:48:35 -0700247 GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800248 if (!transport) {
249 return false;
250 }
251 return transport->needs_ice_restart();
252}
253
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200254absl::optional<rtc::SSLRole> JsepTransportController::GetDtlsRole(
Zhi Huange830e682018-03-30 10:48:35 -0700255 const std::string& mid) const {
Zhi Huange818b6e2018-02-22 15:26:27 -0800256 if (!network_thread_->IsCurrent()) {
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200257 return network_thread_->Invoke<absl::optional<rtc::SSLRole>>(
Zhi Huange830e682018-03-30 10:48:35 -0700258 RTC_FROM_HERE, [&] { return GetDtlsRole(mid); });
Zhi Huange818b6e2018-02-22 15:26:27 -0800259 }
260
Zhi Huang365381f2018-04-13 16:44:34 -0700261 const cricket::JsepTransport* t = GetJsepTransportForMid(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -0800262 if (!t) {
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200263 return absl::optional<rtc::SSLRole>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800264 }
265 return t->GetDtlsRole();
266}
267
268bool JsepTransportController::SetLocalCertificate(
269 const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) {
270 if (!network_thread_->IsCurrent()) {
271 return network_thread_->Invoke<bool>(
272 RTC_FROM_HERE, [&] { return SetLocalCertificate(certificate); });
273 }
274
275 // Can't change a certificate, or set a null certificate.
276 if (certificate_ || !certificate) {
277 return false;
278 }
279 certificate_ = certificate;
280
281 // Set certificate for JsepTransport, which verifies it matches the
282 // fingerprint in SDP, and DTLS transport.
283 // Fallback from DTLS to SDES is not supported.
Zhi Huange830e682018-03-30 10:48:35 -0700284 for (auto& kv : jsep_transports_by_name_) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800285 kv.second->SetLocalCertificate(certificate_);
286 }
287 for (auto& dtls : GetDtlsTransports()) {
288 bool set_cert_success = dtls->SetLocalCertificate(certificate_);
289 RTC_DCHECK(set_cert_success);
290 }
291 return true;
292}
293
294rtc::scoped_refptr<rtc::RTCCertificate>
295JsepTransportController::GetLocalCertificate(
296 const std::string& transport_name) const {
297 if (!network_thread_->IsCurrent()) {
298 return network_thread_->Invoke<rtc::scoped_refptr<rtc::RTCCertificate>>(
299 RTC_FROM_HERE, [&] { return GetLocalCertificate(transport_name); });
300 }
301
Zhi Huang365381f2018-04-13 16:44:34 -0700302 const cricket::JsepTransport* t = GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800303 if (!t) {
304 return nullptr;
305 }
306 return t->GetLocalCertificate();
307}
308
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800309std::unique_ptr<rtc::SSLCertChain>
310JsepTransportController::GetRemoteSSLCertChain(
Zhi Huange818b6e2018-02-22 15:26:27 -0800311 const std::string& transport_name) const {
312 if (!network_thread_->IsCurrent()) {
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800313 return network_thread_->Invoke<std::unique_ptr<rtc::SSLCertChain>>(
314 RTC_FROM_HERE, [&] { return GetRemoteSSLCertChain(transport_name); });
Zhi Huange818b6e2018-02-22 15:26:27 -0800315 }
316
Zhi Huange830e682018-03-30 10:48:35 -0700317 // Get the certificate from the RTP transport's DTLS handshake. Should be
318 // identical to the RTCP transport's, since they were given the same remote
Zhi Huange818b6e2018-02-22 15:26:27 -0800319 // fingerprint.
Zhi Huange830e682018-03-30 10:48:35 -0700320 auto jsep_transport = GetJsepTransportByName(transport_name);
321 if (!jsep_transport) {
322 return nullptr;
323 }
324 auto dtls = jsep_transport->rtp_dtls_transport();
Zhi Huange818b6e2018-02-22 15:26:27 -0800325 if (!dtls) {
326 return nullptr;
327 }
328
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800329 return dtls->GetRemoteSSLCertChain();
Zhi Huange818b6e2018-02-22 15:26:27 -0800330}
331
332void JsepTransportController::MaybeStartGathering() {
333 if (!network_thread_->IsCurrent()) {
334 network_thread_->Invoke<void>(RTC_FROM_HERE,
335 [&] { MaybeStartGathering(); });
336 return;
337 }
338
339 for (auto& dtls : GetDtlsTransports()) {
340 dtls->ice_transport()->MaybeStartGathering();
341 }
342}
343
344RTCError JsepTransportController::AddRemoteCandidates(
345 const std::string& transport_name,
346 const cricket::Candidates& candidates) {
347 if (!network_thread_->IsCurrent()) {
348 return network_thread_->Invoke<RTCError>(RTC_FROM_HERE, [&] {
349 return AddRemoteCandidates(transport_name, candidates);
350 });
351 }
352
353 // Verify each candidate before passing down to the transport layer.
354 RTCError error = VerifyCandidates(candidates);
355 if (!error.ok()) {
356 return error;
357 }
Zhi Huange830e682018-03-30 10:48:35 -0700358 auto jsep_transport = GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800359 if (!jsep_transport) {
Zhi Huange830e682018-03-30 10:48:35 -0700360 RTC_LOG(LS_WARNING) << "Not adding candidate because the JsepTransport "
361 "doesn't exist. Ignore it.";
362 return RTCError::OK();
Zhi Huange818b6e2018-02-22 15:26:27 -0800363 }
Zhi Huange818b6e2018-02-22 15:26:27 -0800364 return jsep_transport->AddRemoteCandidates(candidates);
365}
366
367RTCError JsepTransportController::RemoveRemoteCandidates(
368 const cricket::Candidates& candidates) {
369 if (!network_thread_->IsCurrent()) {
370 return network_thread_->Invoke<RTCError>(
371 RTC_FROM_HERE, [&] { return RemoveRemoteCandidates(candidates); });
372 }
373
374 // Verify each candidate before passing down to the transport layer.
375 RTCError error = VerifyCandidates(candidates);
376 if (!error.ok()) {
377 return error;
378 }
379
380 std::map<std::string, cricket::Candidates> candidates_by_transport_name;
381 for (const cricket::Candidate& cand : candidates) {
382 if (!cand.transport_name().empty()) {
383 candidates_by_transport_name[cand.transport_name()].push_back(cand);
384 } else {
385 RTC_LOG(LS_ERROR) << "Not removing candidate because it does not have a "
386 "transport name set: "
Qingsi Wang20232a92019-09-06 12:51:17 -0700387 << cand.ToSensitiveString();
Zhi Huange818b6e2018-02-22 15:26:27 -0800388 }
389 }
390
391 for (const auto& kv : candidates_by_transport_name) {
392 const std::string& transport_name = kv.first;
393 const cricket::Candidates& candidates = kv.second;
Zhi Huang365381f2018-04-13 16:44:34 -0700394 cricket::JsepTransport* jsep_transport =
Zhi Huange830e682018-03-30 10:48:35 -0700395 GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800396 if (!jsep_transport) {
Zhi Huange830e682018-03-30 10:48:35 -0700397 RTC_LOG(LS_WARNING)
398 << "Not removing candidate because the JsepTransport doesn't exist.";
399 continue;
Zhi Huange818b6e2018-02-22 15:26:27 -0800400 }
401 for (const cricket::Candidate& candidate : candidates) {
Harald Alvestrandad88c882018-11-28 16:47:46 +0100402 cricket::DtlsTransportInternal* dtls =
403 candidate.component() == cricket::ICE_CANDIDATE_COMPONENT_RTP
404 ? jsep_transport->rtp_dtls_transport()
405 : jsep_transport->rtcp_dtls_transport();
Zhi Huange818b6e2018-02-22 15:26:27 -0800406 if (dtls) {
407 dtls->ice_transport()->RemoveRemoteCandidate(candidate);
408 }
409 }
410 }
411 return RTCError::OK();
412}
413
414bool JsepTransportController::GetStats(const std::string& transport_name,
415 cricket::TransportStats* stats) {
416 if (!network_thread_->IsCurrent()) {
417 return network_thread_->Invoke<bool>(
418 RTC_FROM_HERE, [=] { return GetStats(transport_name, stats); });
419 }
420
Zhi Huang365381f2018-04-13 16:44:34 -0700421 cricket::JsepTransport* transport = GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800422 if (!transport) {
423 return false;
424 }
425 return transport->GetStats(stats);
426}
427
Zhi Huangb57e1692018-06-12 11:41:11 -0700428void JsepTransportController::SetActiveResetSrtpParams(
429 bool active_reset_srtp_params) {
430 if (!network_thread_->IsCurrent()) {
431 network_thread_->Invoke<void>(RTC_FROM_HERE, [=] {
432 SetActiveResetSrtpParams(active_reset_srtp_params);
433 });
434 return;
435 }
436
437 RTC_LOG(INFO)
438 << "Updating the active_reset_srtp_params for JsepTransportController: "
439 << active_reset_srtp_params;
440 config_.active_reset_srtp_params = active_reset_srtp_params;
441 for (auto& kv : jsep_transports_by_name_) {
442 kv.second->SetActiveResetSrtpParams(active_reset_srtp_params);
443 }
444}
445
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800446void JsepTransportController::SetMediaTransportSettings(
447 bool use_media_transport_for_media,
Anton Sukhanov316f3ac2019-05-23 15:50:38 -0700448 bool use_media_transport_for_data_channels,
Bjorn A Mellemb689af42019-08-21 10:44:59 -0700449 bool use_datagram_transport,
Bjorn A Mellem7da4e562019-09-26 11:02:11 -0700450 bool use_datagram_transport_for_data_channels,
451 bool use_datagram_transport_for_data_channels_receive_only) {
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800452 RTC_DCHECK(use_media_transport_for_media ==
453 config_.use_media_transport_for_media ||
Piotr (Peter) Slatala97fc11f2018-10-18 12:57:59 -0700454 jsep_transports_by_name_.empty())
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800455 << "You can only change media transport configuration before creating "
456 "the first transport.";
457
458 RTC_DCHECK(use_media_transport_for_data_channels ==
459 config_.use_media_transport_for_data_channels ||
460 jsep_transports_by_name_.empty())
461 << "You can only change media transport configuration before creating "
462 "the first transport.";
463
464 config_.use_media_transport_for_media = use_media_transport_for_media;
465 config_.use_media_transport_for_data_channels =
466 use_media_transport_for_data_channels;
Anton Sukhanov316f3ac2019-05-23 15:50:38 -0700467 config_.use_datagram_transport = use_datagram_transport;
Bjorn A Mellemb689af42019-08-21 10:44:59 -0700468 config_.use_datagram_transport_for_data_channels =
469 use_datagram_transport_for_data_channels;
Bjorn A Mellem7da4e562019-09-26 11:02:11 -0700470 config_.use_datagram_transport_for_data_channels_receive_only =
471 use_datagram_transport_for_data_channels_receive_only;
Piotr (Peter) Slatala97fc11f2018-10-18 12:57:59 -0700472}
473
Eldar Rello5ab79e62019-10-09 18:29:44 +0300474void JsepTransportController::RollbackTransportForMid(const std::string& mid) {
475 if (!network_thread_->IsCurrent()) {
476 network_thread_->Invoke<void>(RTC_FROM_HERE,
477 [=] { RollbackTransportForMid(mid); });
478 return;
479 }
480 RemoveTransportForMid(mid);
481 MaybeDestroyJsepTransport(mid);
482}
483
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800484std::unique_ptr<cricket::IceTransportInternal>
485JsepTransportController::CreateIceTransport(const std::string transport_name,
486 bool rtcp) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800487 int component = rtcp ? cricket::ICE_CANDIDATE_COMPONENT_RTCP
488 : cricket::ICE_CANDIDATE_COMPONENT_RTP;
489
Zhi Huange818b6e2018-02-22 15:26:27 -0800490 if (config_.external_transport_factory) {
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800491 return config_.external_transport_factory->CreateIceTransport(
Zhi Huange818b6e2018-02-22 15:26:27 -0800492 transport_name, component);
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800493 } else {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200494 return std::make_unique<cricket::P2PTransportChannel>(
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800495 transport_name, component, port_allocator_, async_resolver_factory_,
496 config_.event_log);
497 }
498}
499
500std::unique_ptr<cricket::DtlsTransportInternal>
501JsepTransportController::CreateDtlsTransport(
Anton Sukhanovac6c0962019-07-10 15:44:56 -0700502 const cricket::ContentInfo& content_info,
Bjorn A Mellem0c1c1b42019-05-29 17:34:13 -0700503 cricket::IceTransportInternal* ice,
Anton Sukhanov292ce4e2019-06-03 13:00:24 -0700504 DatagramTransportInterface* datagram_transport) {
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800505 RTC_DCHECK(network_thread_->IsCurrent());
506
507 std::unique_ptr<cricket::DtlsTransportInternal> dtls;
Anton Sukhanov316f3ac2019-05-23 15:50:38 -0700508
509 if (datagram_transport) {
Bjorn A Mellemb689af42019-08-21 10:44:59 -0700510 RTC_DCHECK(config_.use_datagram_transport ||
511 config_.use_datagram_transport_for_data_channels);
Anton Sukhanov316f3ac2019-05-23 15:50:38 -0700512 } else if (config_.media_transport_factory &&
513 config_.use_media_transport_for_media &&
514 config_.use_media_transport_for_data_channels) {
515 // If media transport is used for both media and data channels,
516 // then we don't need to create DTLS.
517 // Otherwise, DTLS is still created.
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200518 dtls = std::make_unique<cricket::NoOpDtlsTransport>(ice,
519 config_.crypto_options);
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800520 } else if (config_.external_transport_factory) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800521 dtls = config_.external_transport_factory->CreateDtlsTransport(
Bjorn A Mellem0c1c1b42019-05-29 17:34:13 -0700522 ice, config_.crypto_options);
Zhi Huange818b6e2018-02-22 15:26:27 -0800523 } else {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200524 dtls = std::make_unique<cricket::DtlsTransport>(ice, config_.crypto_options,
525 config_.event_log);
Zhi Huange818b6e2018-02-22 15:26:27 -0800526 }
527
528 RTC_DCHECK(dtls);
529 dtls->SetSslMaxProtocolVersion(config_.ssl_max_version);
Zhi Huange818b6e2018-02-22 15:26:27 -0800530 dtls->ice_transport()->SetIceRole(ice_role_);
531 dtls->ice_transport()->SetIceTiebreaker(ice_tiebreaker_);
532 dtls->ice_transport()->SetIceConfig(ice_config_);
533 if (certificate_) {
534 bool set_cert_success = dtls->SetLocalCertificate(certificate_);
535 RTC_DCHECK(set_cert_success);
536 }
537
538 // Connect to signals offered by the DTLS and ICE transport.
539 dtls->SignalWritableState.connect(
540 this, &JsepTransportController::OnTransportWritableState_n);
541 dtls->SignalReceivingState.connect(
542 this, &JsepTransportController::OnTransportReceivingState_n);
543 dtls->SignalDtlsHandshakeError.connect(
544 this, &JsepTransportController::OnDtlsHandshakeError);
545 dtls->ice_transport()->SignalGatheringState.connect(
546 this, &JsepTransportController::OnTransportGatheringState_n);
547 dtls->ice_transport()->SignalCandidateGathered.connect(
548 this, &JsepTransportController::OnTransportCandidateGathered_n);
Eldar Relloda13ea22019-06-01 12:23:43 +0300549 dtls->ice_transport()->SignalCandidateError.connect(
550 this, &JsepTransportController::OnTransportCandidateError_n);
Zhi Huange818b6e2018-02-22 15:26:27 -0800551 dtls->ice_transport()->SignalCandidatesRemoved.connect(
552 this, &JsepTransportController::OnTransportCandidatesRemoved_n);
553 dtls->ice_transport()->SignalRoleConflict.connect(
554 this, &JsepTransportController::OnTransportRoleConflict_n);
555 dtls->ice_transport()->SignalStateChanged.connect(
556 this, &JsepTransportController::OnTransportStateChanged_n);
Jonas Olsson7a6739e2019-01-15 16:31:55 +0100557 dtls->ice_transport()->SignalIceTransportStateChanged.connect(
558 this, &JsepTransportController::OnTransportStateChanged_n);
Alex Drake00c7ecf2019-08-06 10:54:47 -0700559 dtls->ice_transport()->SignalCandidatePairChanged.connect(
560 this, &JsepTransportController::OnTransportCandidatePairChanged_n);
Zhi Huange818b6e2018-02-22 15:26:27 -0800561 return dtls;
562}
563
564std::unique_ptr<webrtc::RtpTransport>
565JsepTransportController::CreateUnencryptedRtpTransport(
566 const std::string& transport_name,
567 rtc::PacketTransportInternal* rtp_packet_transport,
568 rtc::PacketTransportInternal* rtcp_packet_transport) {
569 RTC_DCHECK(network_thread_->IsCurrent());
Zhi Huange830e682018-03-30 10:48:35 -0700570 auto unencrypted_rtp_transport =
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200571 std::make_unique<RtpTransport>(rtcp_packet_transport == nullptr);
Zhi Huange830e682018-03-30 10:48:35 -0700572 unencrypted_rtp_transport->SetRtpPacketTransport(rtp_packet_transport);
573 if (rtcp_packet_transport) {
574 unencrypted_rtp_transport->SetRtcpPacketTransport(rtcp_packet_transport);
575 }
576 return unencrypted_rtp_transport;
Zhi Huange818b6e2018-02-22 15:26:27 -0800577}
578
579std::unique_ptr<webrtc::SrtpTransport>
580JsepTransportController::CreateSdesTransport(
581 const std::string& transport_name,
Zhi Huange830e682018-03-30 10:48:35 -0700582 cricket::DtlsTransportInternal* rtp_dtls_transport,
583 cricket::DtlsTransportInternal* rtcp_dtls_transport) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800584 RTC_DCHECK(network_thread_->IsCurrent());
Zhi Huange818b6e2018-02-22 15:26:27 -0800585 auto srtp_transport =
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200586 std::make_unique<webrtc::SrtpTransport>(rtcp_dtls_transport == nullptr);
Zhi Huange830e682018-03-30 10:48:35 -0700587 RTC_DCHECK(rtp_dtls_transport);
588 srtp_transport->SetRtpPacketTransport(rtp_dtls_transport);
589 if (rtcp_dtls_transport) {
590 srtp_transport->SetRtcpPacketTransport(rtcp_dtls_transport);
Zhi Huange818b6e2018-02-22 15:26:27 -0800591 }
592 if (config_.enable_external_auth) {
593 srtp_transport->EnableExternalAuth();
594 }
595 return srtp_transport;
596}
597
598std::unique_ptr<webrtc::DtlsSrtpTransport>
599JsepTransportController::CreateDtlsSrtpTransport(
600 const std::string& transport_name,
601 cricket::DtlsTransportInternal* rtp_dtls_transport,
602 cricket::DtlsTransportInternal* rtcp_dtls_transport) {
603 RTC_DCHECK(network_thread_->IsCurrent());
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200604 auto dtls_srtp_transport = std::make_unique<webrtc::DtlsSrtpTransport>(
Zhi Huang365381f2018-04-13 16:44:34 -0700605 rtcp_dtls_transport == nullptr);
Zhi Huang27f3bf52018-03-26 21:37:23 -0700606 if (config_.enable_external_auth) {
Zhi Huang365381f2018-04-13 16:44:34 -0700607 dtls_srtp_transport->EnableExternalAuth();
Zhi Huang27f3bf52018-03-26 21:37:23 -0700608 }
Zhi Huang97d5e5b2018-03-27 00:09:01 +0000609
Zhi Huange818b6e2018-02-22 15:26:27 -0800610 dtls_srtp_transport->SetDtlsTransports(rtp_dtls_transport,
611 rtcp_dtls_transport);
Zhi Huangb57e1692018-06-12 11:41:11 -0700612 dtls_srtp_transport->SetActiveResetSrtpParams(
613 config_.active_reset_srtp_params);
Jonas Olsson635474e2018-10-18 15:58:17 +0200614 dtls_srtp_transport->SignalDtlsStateChange.connect(
615 this, &JsepTransportController::UpdateAggregateStates_n);
Zhi Huange818b6e2018-02-22 15:26:27 -0800616 return dtls_srtp_transport;
617}
618
619std::vector<cricket::DtlsTransportInternal*>
620JsepTransportController::GetDtlsTransports() {
621 std::vector<cricket::DtlsTransportInternal*> dtls_transports;
Zhi Huange830e682018-03-30 10:48:35 -0700622 for (auto it = jsep_transports_by_name_.begin();
623 it != jsep_transports_by_name_.end(); ++it) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800624 auto jsep_transport = it->second.get();
625 RTC_DCHECK(jsep_transport);
626 if (jsep_transport->rtp_dtls_transport()) {
627 dtls_transports.push_back(jsep_transport->rtp_dtls_transport());
628 }
629
630 if (jsep_transport->rtcp_dtls_transport()) {
631 dtls_transports.push_back(jsep_transport->rtcp_dtls_transport());
632 }
633 }
634 return dtls_transports;
635}
636
Zhi Huange818b6e2018-02-22 15:26:27 -0800637RTCError JsepTransportController::ApplyDescription_n(
638 bool local,
639 SdpType type,
640 const cricket::SessionDescription* description) {
641 RTC_DCHECK(network_thread_->IsCurrent());
642 RTC_DCHECK(description);
643
644 if (local) {
645 local_desc_ = description;
646 } else {
647 remote_desc_ = description;
648 }
649
Zhi Huange830e682018-03-30 10:48:35 -0700650 RTCError error;
Zhi Huangd2248f82018-04-10 14:41:03 -0700651 error = ValidateAndMaybeUpdateBundleGroup(local, type, description);
Zhi Huange830e682018-03-30 10:48:35 -0700652 if (!error.ok()) {
653 return error;
Zhi Huange818b6e2018-02-22 15:26:27 -0800654 }
655
656 std::vector<int> merged_encrypted_extension_ids;
Bjorn A Mellem8e1343a2019-09-30 15:12:47 -0700657 absl::optional<std::string> bundle_media_alt_protocol;
658 absl::optional<std::string> bundle_data_alt_protocol;
Zhi Huange818b6e2018-02-22 15:26:27 -0800659 if (bundle_group_) {
660 merged_encrypted_extension_ids =
661 MergeEncryptedHeaderExtensionIdsForBundle(description);
Bjorn A Mellem8e1343a2019-09-30 15:12:47 -0700662 error = GetAltProtocolsForBundle(description, &bundle_media_alt_protocol,
663 &bundle_data_alt_protocol);
664 if (!error.ok()) {
665 return error;
666 }
Zhi Huange818b6e2018-02-22 15:26:27 -0800667 }
668
669 for (const cricket::ContentInfo& content_info : description->contents()) {
670 // Don't create transports for rejected m-lines and bundled m-lines."
671 if (content_info.rejected ||
672 (IsBundled(content_info.name) && content_info.name != *bundled_mid())) {
673 continue;
674 }
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -0800675 error = MaybeCreateJsepTransport(local, content_info, *description);
Zhi Huange830e682018-03-30 10:48:35 -0700676 if (!error.ok()) {
677 return error;
678 }
Zhi Huange818b6e2018-02-22 15:26:27 -0800679 }
680
681 RTC_DCHECK(description->contents().size() ==
682 description->transport_infos().size());
683 for (size_t i = 0; i < description->contents().size(); ++i) {
684 const cricket::ContentInfo& content_info = description->contents()[i];
Bjorn A Mellem8e1343a2019-09-30 15:12:47 -0700685 const cricket::MediaContentDescription* media_description =
686 content_info.media_description();
Zhi Huange818b6e2018-02-22 15:26:27 -0800687 const cricket::TransportInfo& transport_info =
688 description->transport_infos()[i];
689 if (content_info.rejected) {
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700690 HandleRejectedContent(content_info, description);
Zhi Huange818b6e2018-02-22 15:26:27 -0800691 continue;
692 }
693
694 if (IsBundled(content_info.name) && content_info.name != *bundled_mid()) {
Zhi Huang365381f2018-04-13 16:44:34 -0700695 if (!HandleBundledContent(content_info)) {
696 return RTCError(RTCErrorType::INVALID_PARAMETER,
697 "Failed to process the bundled m= section.");
698 }
Zhi Huange818b6e2018-02-22 15:26:27 -0800699 continue;
700 }
701
Zhi Huange830e682018-03-30 10:48:35 -0700702 error = ValidateContent(content_info);
703 if (!error.ok()) {
704 return error;
705 }
706
Zhi Huange818b6e2018-02-22 15:26:27 -0800707 std::vector<int> extension_ids;
Bjorn A Mellem8e1343a2019-09-30 15:12:47 -0700708 absl::optional<std::string> media_alt_protocol;
709 absl::optional<std::string> data_alt_protocol;
Taylor Brandstetter0ab56512018-04-12 10:30:48 -0700710 if (bundled_mid() && content_info.name == *bundled_mid()) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800711 extension_ids = merged_encrypted_extension_ids;
Bjorn A Mellem8e1343a2019-09-30 15:12:47 -0700712 media_alt_protocol = bundle_media_alt_protocol;
713 data_alt_protocol = bundle_data_alt_protocol;
Zhi Huange818b6e2018-02-22 15:26:27 -0800714 } else {
715 extension_ids = GetEncryptedHeaderExtensionIds(content_info);
Bjorn A Mellem8e1343a2019-09-30 15:12:47 -0700716 switch (media_description->type()) {
717 case cricket::MEDIA_TYPE_AUDIO:
718 case cricket::MEDIA_TYPE_VIDEO:
719 media_alt_protocol = media_description->alt_protocol();
720 break;
721 case cricket::MEDIA_TYPE_DATA:
722 data_alt_protocol = media_description->alt_protocol();
723 break;
724 }
Zhi Huange818b6e2018-02-22 15:26:27 -0800725 }
726
Zhi Huange830e682018-03-30 10:48:35 -0700727 int rtp_abs_sendtime_extn_id =
728 GetRtpAbsSendTimeHeaderExtensionId(content_info);
729
Zhi Huang365381f2018-04-13 16:44:34 -0700730 cricket::JsepTransport* transport =
Zhi Huange830e682018-03-30 10:48:35 -0700731 GetJsepTransportForMid(content_info.name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800732 RTC_DCHECK(transport);
733
734 SetIceRole_n(DetermineIceRole(transport, transport_info, type, local));
735
Zhi Huange818b6e2018-02-22 15:26:27 -0800736 cricket::JsepTransportDescription jsep_description =
737 CreateJsepTransportDescription(content_info, transport_info,
Bjorn A Mellem8e1343a2019-09-30 15:12:47 -0700738 extension_ids, rtp_abs_sendtime_extn_id,
739 media_alt_protocol, data_alt_protocol);
Zhi Huange818b6e2018-02-22 15:26:27 -0800740 if (local) {
741 error =
742 transport->SetLocalJsepTransportDescription(jsep_description, type);
743 } else {
744 error =
745 transport->SetRemoteJsepTransportDescription(jsep_description, type);
746 }
747
748 if (!error.ok()) {
749 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
750 "Failed to apply the description for " +
751 content_info.name + ": " + error.message());
752 }
753 }
754 return RTCError::OK();
755}
756
Zhi Huangd2248f82018-04-10 14:41:03 -0700757RTCError JsepTransportController::ValidateAndMaybeUpdateBundleGroup(
758 bool local,
759 SdpType type,
Zhi Huange830e682018-03-30 10:48:35 -0700760 const cricket::SessionDescription* description) {
761 RTC_DCHECK(description);
Zhi Huangd2248f82018-04-10 14:41:03 -0700762 const cricket::ContentGroup* new_bundle_group =
763 description->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
764
765 // The BUNDLE group containing a MID that no m= section has is invalid.
766 if (new_bundle_group) {
Mirko Bonadei739baf02019-01-27 17:29:42 +0100767 for (const auto& content_name : new_bundle_group->content_names()) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700768 if (!description->GetContentByName(content_name)) {
769 return RTCError(RTCErrorType::INVALID_PARAMETER,
770 "The BUNDLE group contains MID:" + content_name +
771 " matching no m= section.");
772 }
773 }
774 }
775
776 if (type == SdpType::kAnswer) {
777 const cricket::ContentGroup* offered_bundle_group =
778 local ? remote_desc_->GetGroupByName(cricket::GROUP_TYPE_BUNDLE)
779 : local_desc_->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
780
781 if (new_bundle_group) {
782 // The BUNDLE group in answer should be a subset of offered group.
Mirko Bonadei739baf02019-01-27 17:29:42 +0100783 for (const auto& content_name : new_bundle_group->content_names()) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700784 if (!offered_bundle_group ||
785 !offered_bundle_group->HasContentName(content_name)) {
786 return RTCError(RTCErrorType::INVALID_PARAMETER,
787 "The BUNDLE group in answer contains a MID that was "
788 "not in the offered group.");
789 }
790 }
791 }
792
793 if (bundle_group_) {
Mirko Bonadei739baf02019-01-27 17:29:42 +0100794 for (const auto& content_name : bundle_group_->content_names()) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700795 // An answer that removes m= sections from pre-negotiated BUNDLE group
796 // without rejecting it, is invalid.
797 if (!new_bundle_group ||
798 !new_bundle_group->HasContentName(content_name)) {
799 auto* content_info = description->GetContentByName(content_name);
800 if (!content_info || !content_info->rejected) {
801 return RTCError(RTCErrorType::INVALID_PARAMETER,
802 "Answer cannot remove m= section " + content_name +
803 " from already-established BUNDLE group.");
804 }
805 }
806 }
807 }
808 }
809
810 if (config_.bundle_policy ==
811 PeerConnectionInterface::kBundlePolicyMaxBundle &&
812 !description->HasGroup(cricket::GROUP_TYPE_BUNDLE)) {
813 return RTCError(RTCErrorType::INVALID_PARAMETER,
814 "max-bundle is used but no bundle group found.");
815 }
816
817 if (ShouldUpdateBundleGroup(type, description)) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700818 bundle_group_ = *new_bundle_group;
819 }
Zhi Huange830e682018-03-30 10:48:35 -0700820
821 if (!bundled_mid()) {
822 return RTCError::OK();
823 }
824
825 auto bundled_content = description->GetContentByName(*bundled_mid());
826 if (!bundled_content) {
827 return RTCError(
828 RTCErrorType::INVALID_PARAMETER,
829 "An m= section associated with the BUNDLE-tag doesn't exist.");
830 }
831
832 // If the |bundled_content| is rejected, other contents in the bundle group
833 // should be rejected.
834 if (bundled_content->rejected) {
Mirko Bonadei739baf02019-01-27 17:29:42 +0100835 for (const auto& content_name : bundle_group_->content_names()) {
Zhi Huange830e682018-03-30 10:48:35 -0700836 auto other_content = description->GetContentByName(content_name);
837 if (!other_content->rejected) {
838 return RTCError(
839 RTCErrorType::INVALID_PARAMETER,
840 "The m= section:" + content_name + " should be rejected.");
841 }
842 }
843 }
844
845 return RTCError::OK();
846}
847
848RTCError JsepTransportController::ValidateContent(
849 const cricket::ContentInfo& content_info) {
850 if (config_.rtcp_mux_policy ==
851 PeerConnectionInterface::kRtcpMuxPolicyRequire &&
852 content_info.type == cricket::MediaProtocolType::kRtp &&
853 !content_info.media_description()->rtcp_mux()) {
854 return RTCError(RTCErrorType::INVALID_PARAMETER,
855 "The m= section:" + content_info.name +
856 " is invalid. RTCP-MUX is not "
857 "enabled when it is required.");
858 }
859 return RTCError::OK();
860}
861
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700862void JsepTransportController::HandleRejectedContent(
Zhi Huangd2248f82018-04-10 14:41:03 -0700863 const cricket::ContentInfo& content_info,
864 const cricket::SessionDescription* description) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800865 // If the content is rejected, let the
866 // BaseChannel/SctpTransport change the RtpTransport/DtlsTransport first,
Zhi Huang365381f2018-04-13 16:44:34 -0700867 // then destroy the cricket::JsepTransport.
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700868 RemoveTransportForMid(content_info.name);
Zhi Huange830e682018-03-30 10:48:35 -0700869 if (content_info.name == bundled_mid()) {
Mirko Bonadei739baf02019-01-27 17:29:42 +0100870 for (const auto& content_name : bundle_group_->content_names()) {
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700871 RemoveTransportForMid(content_name);
Zhi Huange830e682018-03-30 10:48:35 -0700872 }
873 bundle_group_.reset();
874 } else if (IsBundled(content_info.name)) {
875 // Remove the rejected content from the |bundle_group_|.
Zhi Huange818b6e2018-02-22 15:26:27 -0800876 bundle_group_->RemoveContentName(content_info.name);
Zhi Huange830e682018-03-30 10:48:35 -0700877 // Reset the bundle group if nothing left.
878 if (!bundle_group_->FirstContentName()) {
879 bundle_group_.reset();
880 }
Zhi Huange818b6e2018-02-22 15:26:27 -0800881 }
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700882 MaybeDestroyJsepTransport(content_info.name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800883}
884
Zhi Huang365381f2018-04-13 16:44:34 -0700885bool JsepTransportController::HandleBundledContent(
Zhi Huange818b6e2018-02-22 15:26:27 -0800886 const cricket::ContentInfo& content_info) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700887 auto jsep_transport = GetJsepTransportByName(*bundled_mid());
888 RTC_DCHECK(jsep_transport);
Zhi Huange818b6e2018-02-22 15:26:27 -0800889 // If the content is bundled, let the
890 // BaseChannel/SctpTransport change the RtpTransport/DtlsTransport first,
Zhi Huang365381f2018-04-13 16:44:34 -0700891 // then destroy the cricket::JsepTransport.
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700892 if (SetTransportForMid(content_info.name, jsep_transport)) {
Piotr (Peter) Slatala10aeb2a2018-11-14 10:57:24 -0800893 // TODO(bugs.webrtc.org/9719) For media transport this is far from ideal,
894 // because it means that we first create media transport and start
895 // connecting it, and then we destroy it. We will need to address it before
896 // video path is enabled.
Zhi Huang365381f2018-04-13 16:44:34 -0700897 MaybeDestroyJsepTransport(content_info.name);
898 return true;
899 }
900 return false;
Zhi Huange818b6e2018-02-22 15:26:27 -0800901}
902
Zhi Huang365381f2018-04-13 16:44:34 -0700903bool JsepTransportController::SetTransportForMid(
Zhi Huangd2248f82018-04-10 14:41:03 -0700904 const std::string& mid,
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700905 cricket::JsepTransport* jsep_transport) {
Zhi Huang365381f2018-04-13 16:44:34 -0700906 RTC_DCHECK(jsep_transport);
Zhi Huangd2248f82018-04-10 14:41:03 -0700907 if (mid_to_transport_[mid] == jsep_transport) {
Zhi Huang365381f2018-04-13 16:44:34 -0700908 return true;
Zhi Huangd2248f82018-04-10 14:41:03 -0700909 }
910
911 mid_to_transport_[mid] = jsep_transport;
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700912 return config_.transport_observer->OnTransportChanged(
Harald Alvestrandc85328f2019-02-28 07:51:00 +0100913 mid, jsep_transport->rtp_transport(), jsep_transport->RtpDtlsTransport(),
Bjorn A Mellembc3eebc2019-09-23 14:53:54 -0700914 jsep_transport->media_transport(),
915 jsep_transport->data_channel_transport());
Zhi Huangd2248f82018-04-10 14:41:03 -0700916}
917
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700918void JsepTransportController::RemoveTransportForMid(const std::string& mid) {
Bjorn A Mellemb689af42019-08-21 10:44:59 -0700919 bool ret = config_.transport_observer->OnTransportChanged(
Bjorn A Mellembc3eebc2019-09-23 14:53:54 -0700920 mid, nullptr, nullptr, nullptr, nullptr);
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700921 // Calling OnTransportChanged with nullptr should always succeed, since it is
922 // only expected to fail when adding media to a transport (not removing).
923 RTC_DCHECK(ret);
Zhi Huangd2248f82018-04-10 14:41:03 -0700924 mid_to_transport_.erase(mid);
925}
926
Zhi Huange818b6e2018-02-22 15:26:27 -0800927cricket::JsepTransportDescription
928JsepTransportController::CreateJsepTransportDescription(
Harald Alvestrand1716d392019-06-03 20:35:45 +0200929 const cricket::ContentInfo& content_info,
930 const cricket::TransportInfo& transport_info,
Zhi Huange830e682018-03-30 10:48:35 -0700931 const std::vector<int>& encrypted_extension_ids,
Bjorn A Mellem8e1343a2019-09-30 15:12:47 -0700932 int rtp_abs_sendtime_extn_id,
933 absl::optional<std::string> media_alt_protocol,
934 absl::optional<std::string> data_alt_protocol) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800935 const cricket::MediaContentDescription* content_desc =
Harald Alvestrand1716d392019-06-03 20:35:45 +0200936 content_info.media_description();
Zhi Huange818b6e2018-02-22 15:26:27 -0800937 RTC_DCHECK(content_desc);
938 bool rtcp_mux_enabled = content_info.type == cricket::MediaProtocolType::kSctp
939 ? true
940 : content_desc->rtcp_mux();
941
942 return cricket::JsepTransportDescription(
943 rtcp_mux_enabled, content_desc->cryptos(), encrypted_extension_ids,
Bjorn A Mellem8e1343a2019-09-30 15:12:47 -0700944 rtp_abs_sendtime_extn_id, transport_info.description, media_alt_protocol,
945 data_alt_protocol);
Zhi Huange818b6e2018-02-22 15:26:27 -0800946}
947
948bool JsepTransportController::ShouldUpdateBundleGroup(
949 SdpType type,
950 const cricket::SessionDescription* description) {
951 if (config_.bundle_policy ==
952 PeerConnectionInterface::kBundlePolicyMaxBundle) {
953 return true;
954 }
955
956 if (type != SdpType::kAnswer) {
957 return false;
958 }
959
960 RTC_DCHECK(local_desc_ && remote_desc_);
961 const cricket::ContentGroup* local_bundle =
962 local_desc_->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
963 const cricket::ContentGroup* remote_bundle =
964 remote_desc_->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
965 return local_bundle && remote_bundle;
966}
967
968std::vector<int> JsepTransportController::GetEncryptedHeaderExtensionIds(
969 const cricket::ContentInfo& content_info) {
970 const cricket::MediaContentDescription* content_desc =
Harald Alvestrand1716d392019-06-03 20:35:45 +0200971 content_info.media_description();
Zhi Huange818b6e2018-02-22 15:26:27 -0800972
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700973 if (!config_.crypto_options.srtp.enable_encrypted_rtp_header_extensions) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800974 return std::vector<int>();
975 }
976
977 std::vector<int> encrypted_header_extension_ids;
Mirko Bonadei739baf02019-01-27 17:29:42 +0100978 for (const auto& extension : content_desc->rtp_header_extensions()) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800979 if (!extension.encrypt) {
980 continue;
981 }
Steve Anton64b626b2019-01-28 17:25:26 -0800982 if (!absl::c_linear_search(encrypted_header_extension_ids, extension.id)) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800983 encrypted_header_extension_ids.push_back(extension.id);
984 }
985 }
986 return encrypted_header_extension_ids;
987}
988
989std::vector<int>
990JsepTransportController::MergeEncryptedHeaderExtensionIdsForBundle(
991 const cricket::SessionDescription* description) {
992 RTC_DCHECK(description);
993 RTC_DCHECK(bundle_group_);
994
995 std::vector<int> merged_ids;
996 // Union the encrypted header IDs in the group when bundle is enabled.
997 for (const cricket::ContentInfo& content_info : description->contents()) {
998 if (bundle_group_->HasContentName(content_info.name)) {
999 std::vector<int> extension_ids =
1000 GetEncryptedHeaderExtensionIds(content_info);
1001 for (int id : extension_ids) {
Steve Anton64b626b2019-01-28 17:25:26 -08001002 if (!absl::c_linear_search(merged_ids, id)) {
Zhi Huange818b6e2018-02-22 15:26:27 -08001003 merged_ids.push_back(id);
1004 }
1005 }
1006 }
1007 }
1008 return merged_ids;
1009}
1010
Bjorn A Mellem8e1343a2019-09-30 15:12:47 -07001011RTCError JsepTransportController::GetAltProtocolsForBundle(
1012 const cricket::SessionDescription* description,
1013 absl::optional<std::string>* media_alt_protocol,
1014 absl::optional<std::string>* data_alt_protocol) {
1015 RTC_DCHECK(description);
1016 RTC_DCHECK(bundle_group_);
1017 RTC_DCHECK(media_alt_protocol);
1018 RTC_DCHECK(data_alt_protocol);
1019
1020 bool found_media = false;
1021 bool found_data = false;
1022 for (const cricket::ContentInfo& content : description->contents()) {
1023 if (bundle_group_->HasContentName(content.name)) {
1024 const cricket::MediaContentDescription* media_description =
1025 content.media_description();
1026 switch (media_description->type()) {
1027 case cricket::MEDIA_TYPE_AUDIO:
1028 case cricket::MEDIA_TYPE_VIDEO:
1029 if (found_media &&
1030 *media_alt_protocol != media_description->alt_protocol()) {
1031 return RTCError(RTCErrorType::INVALID_PARAMETER,
1032 "The BUNDLE group contains conflicting "
1033 "alt-protocols for media ('" +
1034 media_alt_protocol->value_or("") + "' and '" +
1035 media_description->alt_protocol().value_or("") +
1036 "')");
1037 }
1038 found_media = true;
1039 *media_alt_protocol = media_description->alt_protocol();
1040 break;
1041 case cricket::MEDIA_TYPE_DATA:
1042 if (found_data &&
1043 *data_alt_protocol != media_description->alt_protocol()) {
1044 return RTCError(RTCErrorType::INVALID_PARAMETER,
1045 "The BUNDLE group contains conflicting "
1046 "alt-protocols for data ('" +
1047 data_alt_protocol->value_or("") + "' and '" +
1048 media_description->alt_protocol().value_or("") +
1049 "')");
1050 }
1051 found_data = true;
1052 *data_alt_protocol = media_description->alt_protocol();
1053 break;
1054 }
1055 }
1056 }
1057 return RTCError::OK();
1058}
1059
Zhi Huange830e682018-03-30 10:48:35 -07001060int JsepTransportController::GetRtpAbsSendTimeHeaderExtensionId(
Zhi Huange818b6e2018-02-22 15:26:27 -08001061 const cricket::ContentInfo& content_info) {
Zhi Huange830e682018-03-30 10:48:35 -07001062 if (!config_.enable_external_auth) {
1063 return -1;
Zhi Huange818b6e2018-02-22 15:26:27 -08001064 }
1065
1066 const cricket::MediaContentDescription* content_desc =
Harald Alvestrand1716d392019-06-03 20:35:45 +02001067 content_info.media_description();
Zhi Huange830e682018-03-30 10:48:35 -07001068
1069 const webrtc::RtpExtension* send_time_extension =
1070 webrtc::RtpExtension::FindHeaderExtensionByUri(
1071 content_desc->rtp_header_extensions(),
1072 webrtc::RtpExtension::kAbsSendTimeUri);
1073 return send_time_extension ? send_time_extension->id : -1;
1074}
1075
Zhi Huang365381f2018-04-13 16:44:34 -07001076const cricket::JsepTransport* JsepTransportController::GetJsepTransportForMid(
Zhi Huange830e682018-03-30 10:48:35 -07001077 const std::string& mid) const {
Zhi Huangd2248f82018-04-10 14:41:03 -07001078 auto it = mid_to_transport_.find(mid);
1079 return it == mid_to_transport_.end() ? nullptr : it->second;
Zhi Huange830e682018-03-30 10:48:35 -07001080}
1081
Zhi Huang365381f2018-04-13 16:44:34 -07001082cricket::JsepTransport* JsepTransportController::GetJsepTransportForMid(
Zhi Huange830e682018-03-30 10:48:35 -07001083 const std::string& mid) {
Zhi Huangd2248f82018-04-10 14:41:03 -07001084 auto it = mid_to_transport_.find(mid);
1085 return it == mid_to_transport_.end() ? nullptr : it->second;
Zhi Huange830e682018-03-30 10:48:35 -07001086}
1087
Zhi Huang365381f2018-04-13 16:44:34 -07001088const cricket::JsepTransport* JsepTransportController::GetJsepTransportByName(
Zhi Huange830e682018-03-30 10:48:35 -07001089 const std::string& transport_name) const {
1090 auto it = jsep_transports_by_name_.find(transport_name);
1091 return (it == jsep_transports_by_name_.end()) ? nullptr : it->second.get();
1092}
1093
Zhi Huang365381f2018-04-13 16:44:34 -07001094cricket::JsepTransport* JsepTransportController::GetJsepTransportByName(
Zhi Huange830e682018-03-30 10:48:35 -07001095 const std::string& transport_name) {
1096 auto it = jsep_transports_by_name_.find(transport_name);
1097 return (it == jsep_transports_by_name_.end()) ? nullptr : it->second.get();
1098}
1099
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001100std::unique_ptr<webrtc::MediaTransportInterface>
1101JsepTransportController::MaybeCreateMediaTransport(
1102 const cricket::ContentInfo& content_info,
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -08001103 const cricket::SessionDescription& description,
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001104 bool local) {
Piotr (Peter) Slatala63a176b2019-01-25 08:25:33 -08001105 if (config_.media_transport_factory == nullptr) {
1106 return nullptr;
1107 }
1108
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001109 if (!config_.use_media_transport_for_media &&
1110 !config_.use_media_transport_for_data_channels) {
1111 return nullptr;
1112 }
1113
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001114 // Caller (offerer) media transport.
1115 if (local) {
1116 if (offer_media_transport_) {
1117 RTC_LOG(LS_INFO) << "Offered media transport has now been activated.";
1118 return std::move(offer_media_transport_);
1119 } else {
1120 RTC_LOG(LS_INFO)
1121 << "Not returning media transport. Either SDES wasn't enabled, or "
1122 "media transport didn't return an offer earlier.";
1123 // Offer wasn't generated. Either because media transport didn't want it,
1124 // or because SDES wasn't enabled.
1125 return nullptr;
1126 }
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -07001127 }
1128
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001129 // Remote offer. If no x-mt lines, do not create media transport.
1130 if (description.MediaTransportSettings().empty()) {
Piotr (Peter) Slatala63a176b2019-01-25 08:25:33 -08001131 return nullptr;
Anton Sukhanov7940da02018-10-10 10:34:49 -07001132 }
1133
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001134 // When bundle is enabled, two JsepTransports are created, and then
1135 // the second transport is destroyed (right away).
1136 // For media transport, we don't want to create the second
1137 // media transport in the first place.
1138 RTC_LOG(LS_INFO) << "Returning new, client media transport.";
Piotr (Peter) Slatala63a176b2019-01-25 08:25:33 -08001139
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001140 RTC_DCHECK(!local)
1141 << "If media transport is used, you must call "
1142 "GenerateOrGetLastMediaTransportOffer before SetLocalDescription. You "
1143 "also "
1144 "must use kRtcpMuxPolicyRequire and kBundlePolicyMaxBundle with media "
1145 "transport.";
Piotr (Peter) Slatala63a176b2019-01-25 08:25:33 -08001146 MediaTransportSettings settings;
1147 settings.is_caller = local;
Piotr (Peter) Slatala01fe3092019-02-15 12:05:50 -08001148 if (config_.use_media_transport_for_media) {
1149 settings.event_log = config_.event_log;
1150 }
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -08001151
1152 // Assume there is only one media transport (or if more, use the first one).
1153 if (!local && !description.MediaTransportSettings().empty() &&
1154 config_.media_transport_factory->GetTransportName() ==
1155 description.MediaTransportSettings()[0].transport_name) {
1156 settings.remote_transport_parameters =
1157 description.MediaTransportSettings()[0].transport_setting;
1158 }
1159
Piotr (Peter) Slatala63a176b2019-01-25 08:25:33 -08001160 auto media_transport_result =
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001161 config_.media_transport_factory->CreateMediaTransport(network_thread_,
1162 settings);
Piotr (Peter) Slatala63a176b2019-01-25 08:25:33 -08001163
1164 // TODO(sukhanov): Proper error handling.
1165 RTC_CHECK(media_transport_result.ok());
1166
1167 return media_transport_result.MoveValue();
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001168}
1169
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001170// TODO(sukhanov): Refactor to avoid code duplication for Media and Datagram
1171// transports setup.
1172std::unique_ptr<webrtc::DatagramTransportInterface>
1173JsepTransportController::MaybeCreateDatagramTransport(
1174 const cricket::ContentInfo& content_info,
1175 const cricket::SessionDescription& description,
1176 bool local) {
1177 if (config_.media_transport_factory == nullptr) {
1178 return nullptr;
1179 }
1180
Bjorn A Mellemb689af42019-08-21 10:44:59 -07001181 if (!(config_.use_datagram_transport ||
1182 config_.use_datagram_transport_for_data_channels)) {
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001183 return nullptr;
1184 }
1185
1186 // Caller (offerer) datagram transport.
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07001187 if (offer_datagram_transport_) {
1188 RTC_DCHECK(local);
1189 RTC_LOG(LS_INFO) << "Offered datagram transport has now been activated.";
1190 return std::move(offer_datagram_transport_);
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001191 }
1192
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07001193 const cricket::TransportDescription* transport_description =
1194 description.GetTransportDescriptionByName(content_info.mid());
1195 RTC_DCHECK(transport_description)
1196 << "Missing transport description for mid=" << content_info.mid();
1197
1198 if (!transport_description->opaque_parameters) {
1199 RTC_LOG(LS_INFO)
1200 << "No opaque transport parameters, not creating datagram transport";
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001201 return nullptr;
1202 }
1203
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07001204 if (transport_description->opaque_parameters->protocol !=
1205 config_.media_transport_factory->GetTransportName()) {
1206 RTC_LOG(LS_INFO) << "Opaque transport parameters for protocol="
1207 << transport_description->opaque_parameters->protocol
1208 << ", which does not match supported protocol="
1209 << config_.media_transport_factory->GetTransportName();
1210 return nullptr;
1211 }
1212
1213 RTC_DCHECK(!local);
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001214 // When bundle is enabled, two JsepTransports are created, and then
1215 // the second transport is destroyed (right away).
1216 // For datagram transport, we don't want to create the second
1217 // datagram transport in the first place.
1218 RTC_LOG(LS_INFO) << "Returning new, client datagram transport.";
1219
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001220 MediaTransportSettings settings;
1221 settings.is_caller = local;
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07001222 settings.remote_transport_parameters =
1223 transport_description->opaque_parameters->parameters;
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001224 settings.event_log = config_.event_log;
1225
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001226 auto datagram_transport_result =
1227 config_.media_transport_factory->CreateDatagramTransport(network_thread_,
1228 settings);
1229
1230 // TODO(sukhanov): Proper error handling.
1231 RTC_CHECK(datagram_transport_result.ok());
1232
1233 return datagram_transport_result.MoveValue();
1234}
1235
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001236RTCError JsepTransportController::MaybeCreateJsepTransport(
1237 bool local,
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -08001238 const cricket::ContentInfo& content_info,
1239 const cricket::SessionDescription& description) {
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001240 RTC_DCHECK(network_thread_->IsCurrent());
1241 cricket::JsepTransport* transport = GetJsepTransportByName(content_info.name);
1242 if (transport) {
1243 return RTCError::OK();
1244 }
1245
1246 const cricket::MediaContentDescription* content_desc =
Harald Alvestrand1716d392019-06-03 20:35:45 +02001247 content_info.media_description();
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001248 if (certificate_ && !content_desc->cryptos().empty()) {
1249 return RTCError(RTCErrorType::INVALID_PARAMETER,
1250 "SDES and DTLS-SRTP cannot be enabled at the same time.");
1251 }
1252
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001253 std::unique_ptr<cricket::IceTransportInternal> ice =
1254 CreateIceTransport(content_info.name, /*rtcp=*/false);
1255
1256 std::unique_ptr<MediaTransportInterface> media_transport =
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001257 MaybeCreateMediaTransport(content_info, description, local);
1258 if (media_transport) {
1259 media_transport_created_once_ = true;
1260 media_transport->Connect(ice.get());
1261 }
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001262
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001263 std::unique_ptr<DatagramTransportInterface> datagram_transport =
1264 MaybeCreateDatagramTransport(content_info, description, local);
1265 if (datagram_transport) {
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001266 datagram_transport->Connect(ice.get());
1267 }
1268
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001269 std::unique_ptr<cricket::DtlsTransportInternal> rtp_dtls_transport =
Anton Sukhanovac6c0962019-07-10 15:44:56 -07001270 CreateDtlsTransport(content_info, ice.get(), nullptr);
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001271
1272 std::unique_ptr<cricket::DtlsTransportInternal> rtcp_dtls_transport;
1273 std::unique_ptr<RtpTransport> unencrypted_rtp_transport;
1274 std::unique_ptr<SrtpTransport> sdes_transport;
1275 std::unique_ptr<DtlsSrtpTransport> dtls_srtp_transport;
Bjorn A Mellem364b2672019-08-20 16:58:03 -07001276 std::unique_ptr<RtpTransportInternal> datagram_rtp_transport;
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001277
Bjorn A Mellem0c1c1b42019-05-29 17:34:13 -07001278 std::unique_ptr<cricket::IceTransportInternal> rtcp_ice;
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001279 if (config_.rtcp_mux_policy !=
1280 PeerConnectionInterface::kRtcpMuxPolicyRequire &&
1281 content_info.type == cricket::MediaProtocolType::kRtp) {
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001282 RTC_DCHECK(media_transport == nullptr);
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001283 RTC_DCHECK(datagram_transport == nullptr);
Bjorn A Mellem0c1c1b42019-05-29 17:34:13 -07001284 rtcp_ice = CreateIceTransport(content_info.name, /*rtcp=*/true);
Anton Sukhanovac6c0962019-07-10 15:44:56 -07001285 rtcp_dtls_transport = CreateDtlsTransport(content_info, rtcp_ice.get(),
Bjorn A Mellem0c1c1b42019-05-29 17:34:13 -07001286 /*datagram_transport=*/nullptr);
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001287 }
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001288
Bjorn A Mellem703ea952019-08-23 10:31:11 -07001289 // Only create a datagram RTP transport if the datagram transport should be
1290 // used for RTP.
1291 if (datagram_transport && config_.use_datagram_transport) {
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001292 // TODO(sukhanov): We use unencrypted RTP transport over DatagramTransport,
1293 // because MediaTransport encrypts. In the future we may want to
1294 // implement our own version of RtpTransport over MediaTransport, because
1295 // it will give us more control over things like:
1296 // - Fusing
1297 // - Rtp header compression
1298 // - Handling Rtcp feedback.
1299 RTC_LOG(LS_INFO) << "Creating UnencryptedRtpTransport, because datagram "
1300 "transport is used.";
1301 RTC_DCHECK(!rtcp_dtls_transport);
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001302 datagram_rtp_transport = std::make_unique<DatagramRtpTransport>(
Bjorn A Mellem364b2672019-08-20 16:58:03 -07001303 content_info.media_description()->rtp_header_extensions(), ice.get(),
1304 datagram_transport.get());
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07001305 }
1306
1307 if (config_.disable_encryption) {
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001308 RTC_LOG(LS_INFO)
1309 << "Creating UnencryptedRtpTransport, becayse encryption is disabled.";
Zhi Huange818b6e2018-02-22 15:26:27 -08001310 unencrypted_rtp_transport = CreateUnencryptedRtpTransport(
Zhi Huangd2248f82018-04-10 14:41:03 -07001311 content_info.name, rtp_dtls_transport.get(), rtcp_dtls_transport.get());
Zhi Huange818b6e2018-02-22 15:26:27 -08001312 } else if (!content_desc->cryptos().empty()) {
Zhi Huangd2248f82018-04-10 14:41:03 -07001313 sdes_transport = CreateSdesTransport(
1314 content_info.name, rtp_dtls_transport.get(), rtcp_dtls_transport.get());
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001315 RTC_LOG(LS_INFO) << "Creating SdesTransport.";
Zhi Huange818b6e2018-02-22 15:26:27 -08001316 } else {
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001317 RTC_LOG(LS_INFO) << "Creating DtlsSrtpTransport.";
Zhi Huangd2248f82018-04-10 14:41:03 -07001318 dtls_srtp_transport = CreateDtlsSrtpTransport(
1319 content_info.name, rtp_dtls_transport.get(), rtcp_dtls_transport.get());
Zhi Huange818b6e2018-02-22 15:26:27 -08001320 }
1321
Bjorn A Mellembc3eebc2019-09-23 14:53:54 -07001322 std::unique_ptr<cricket::SctpTransportInternal> sctp_transport;
1323 if (config_.sctp_factory) {
1324 sctp_transport =
1325 config_.sctp_factory->CreateSctpTransport(rtp_dtls_transport.get());
1326 }
1327
1328 DataChannelTransportInterface* data_channel_transport = nullptr;
1329 if (config_.use_datagram_transport_for_data_channels) {
1330 data_channel_transport = datagram_transport.get();
1331 } else if (config_.use_media_transport_for_data_channels) {
1332 data_channel_transport = media_transport.get();
1333 }
1334
Zhi Huang365381f2018-04-13 16:44:34 -07001335 std::unique_ptr<cricket::JsepTransport> jsep_transport =
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001336 std::make_unique<cricket::JsepTransport>(
Bjorn A Mellem0c1c1b42019-05-29 17:34:13 -07001337 content_info.name, certificate_, std::move(ice), std::move(rtcp_ice),
1338 std::move(unencrypted_rtp_transport), std::move(sdes_transport),
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07001339 std::move(dtls_srtp_transport), std::move(datagram_rtp_transport),
1340 std::move(rtp_dtls_transport), std::move(rtcp_dtls_transport),
Bjorn A Mellembc3eebc2019-09-23 14:53:54 -07001341 std::move(sctp_transport), std::move(media_transport),
1342 std::move(datagram_transport), data_channel_transport);
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001343
Sebastian Jansson1b83a9e2019-09-18 18:22:12 +02001344 jsep_transport->rtp_transport()->SignalRtcpPacketReceived.connect(
1345 this, &JsepTransportController::OnRtcpPacketReceived_n);
1346
Zhi Huange818b6e2018-02-22 15:26:27 -08001347 jsep_transport->SignalRtcpMuxActive.connect(
1348 this, &JsepTransportController::UpdateAggregateStates_n);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001349 jsep_transport->SignalMediaTransportStateChanged.connect(
Bjorn Mellem175aa2e2018-11-08 11:23:22 -08001350 this, &JsepTransportController::OnMediaTransportStateChanged_n);
Bjorn A Mellemb689af42019-08-21 10:44:59 -07001351 jsep_transport->SignalDataChannelTransportNegotiated.connect(
1352 this, &JsepTransportController::OnDataChannelTransportNegotiated_n);
Taylor Brandstettercbaa2542018-04-16 16:42:14 -07001353 SetTransportForMid(content_info.name, jsep_transport.get());
Zhi Huange830e682018-03-30 10:48:35 -07001354
Zhi Huangd2248f82018-04-10 14:41:03 -07001355 jsep_transports_by_name_[content_info.name] = std::move(jsep_transport);
1356 UpdateAggregateStates_n();
Zhi Huange830e682018-03-30 10:48:35 -07001357 return RTCError::OK();
Zhi Huange818b6e2018-02-22 15:26:27 -08001358}
1359
1360void JsepTransportController::MaybeDestroyJsepTransport(
1361 const std::string& mid) {
Zhi Huangd2248f82018-04-10 14:41:03 -07001362 auto jsep_transport = GetJsepTransportByName(mid);
1363 if (!jsep_transport) {
1364 return;
1365 }
1366
1367 // Don't destroy the JsepTransport if there are still media sections referring
1368 // to it.
1369 for (const auto& kv : mid_to_transport_) {
1370 if (kv.second == jsep_transport) {
1371 return;
1372 }
1373 }
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -08001374
Zhi Huange830e682018-03-30 10:48:35 -07001375 jsep_transports_by_name_.erase(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -08001376 UpdateAggregateStates_n();
1377}
1378
1379void JsepTransportController::DestroyAllJsepTransports_n() {
1380 RTC_DCHECK(network_thread_->IsCurrent());
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -08001381
1382 for (const auto& jsep_transport : jsep_transports_by_name_) {
Bjorn A Mellemb689af42019-08-21 10:44:59 -07001383 config_.transport_observer->OnTransportChanged(
Bjorn A Mellembc3eebc2019-09-23 14:53:54 -07001384 jsep_transport.first, nullptr, nullptr, nullptr, nullptr);
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -08001385 }
1386
Zhi Huange830e682018-03-30 10:48:35 -07001387 jsep_transports_by_name_.clear();
Zhi Huange818b6e2018-02-22 15:26:27 -08001388}
1389
1390void JsepTransportController::SetIceRole_n(cricket::IceRole ice_role) {
1391 RTC_DCHECK(network_thread_->IsCurrent());
1392
1393 ice_role_ = ice_role;
1394 for (auto& dtls : GetDtlsTransports()) {
1395 dtls->ice_transport()->SetIceRole(ice_role_);
1396 }
1397}
1398
1399cricket::IceRole JsepTransportController::DetermineIceRole(
Zhi Huang365381f2018-04-13 16:44:34 -07001400 cricket::JsepTransport* jsep_transport,
Zhi Huange818b6e2018-02-22 15:26:27 -08001401 const cricket::TransportInfo& transport_info,
1402 SdpType type,
1403 bool local) {
1404 cricket::IceRole ice_role = ice_role_;
1405 auto tdesc = transport_info.description;
1406 if (local) {
1407 // The initial offer side may use ICE Lite, in which case, per RFC5245
1408 // Section 5.1.1, the answer side should take the controlling role if it is
1409 // in the full ICE mode.
1410 //
1411 // When both sides use ICE Lite, the initial offer side must take the
1412 // controlling role, and this is the default logic implemented in
1413 // SetLocalDescription in JsepTransportController.
1414 if (jsep_transport->remote_description() &&
1415 jsep_transport->remote_description()->transport_desc.ice_mode ==
1416 cricket::ICEMODE_LITE &&
1417 ice_role_ == cricket::ICEROLE_CONTROLLED &&
1418 tdesc.ice_mode == cricket::ICEMODE_FULL) {
1419 ice_role = cricket::ICEROLE_CONTROLLING;
1420 }
1421
1422 // Older versions of Chrome expect the ICE role to be re-determined when an
1423 // ICE restart occurs, and also don't perform conflict resolution correctly,
1424 // so for now we can't safely stop doing this, unless the application opts
1425 // in by setting |config_.redetermine_role_on_ice_restart_| to false. See:
1426 // https://bugs.chromium.org/p/chromium/issues/detail?id=628676
1427 // TODO(deadbeef): Remove this when these old versions of Chrome reach a low
1428 // enough population.
1429 if (config_.redetermine_role_on_ice_restart &&
1430 jsep_transport->local_description() &&
1431 cricket::IceCredentialsChanged(
1432 jsep_transport->local_description()->transport_desc.ice_ufrag,
1433 jsep_transport->local_description()->transport_desc.ice_pwd,
1434 tdesc.ice_ufrag, tdesc.ice_pwd) &&
1435 // Don't change the ICE role if the remote endpoint is ICE lite; we
1436 // should always be controlling in that case.
1437 (!jsep_transport->remote_description() ||
1438 jsep_transport->remote_description()->transport_desc.ice_mode !=
1439 cricket::ICEMODE_LITE)) {
1440 ice_role = (type == SdpType::kOffer) ? cricket::ICEROLE_CONTROLLING
1441 : cricket::ICEROLE_CONTROLLED;
1442 }
1443 } else {
1444 // If our role is cricket::ICEROLE_CONTROLLED and the remote endpoint
1445 // supports only ice_lite, this local endpoint should take the CONTROLLING
1446 // role.
1447 // TODO(deadbeef): This is a session-level attribute, so it really shouldn't
1448 // be in a TransportDescription in the first place...
1449 if (ice_role_ == cricket::ICEROLE_CONTROLLED &&
1450 tdesc.ice_mode == cricket::ICEMODE_LITE) {
1451 ice_role = cricket::ICEROLE_CONTROLLING;
1452 }
1453
1454 // If we use ICE Lite and the remote endpoint uses the full implementation
1455 // of ICE, the local endpoint must take the controlled role, and the other
1456 // side must be the controlling role.
1457 if (jsep_transport->local_description() &&
1458 jsep_transport->local_description()->transport_desc.ice_mode ==
1459 cricket::ICEMODE_LITE &&
1460 ice_role_ == cricket::ICEROLE_CONTROLLING &&
Zhi Huange830e682018-03-30 10:48:35 -07001461 tdesc.ice_mode == cricket::ICEMODE_FULL) {
Zhi Huange818b6e2018-02-22 15:26:27 -08001462 ice_role = cricket::ICEROLE_CONTROLLED;
1463 }
1464 }
1465
1466 return ice_role;
1467}
1468
1469void JsepTransportController::OnTransportWritableState_n(
1470 rtc::PacketTransportInternal* transport) {
1471 RTC_DCHECK(network_thread_->IsCurrent());
1472 RTC_LOG(LS_INFO) << " Transport " << transport->transport_name()
1473 << " writability changed to " << transport->writable()
1474 << ".";
1475 UpdateAggregateStates_n();
1476}
1477
1478void JsepTransportController::OnTransportReceivingState_n(
1479 rtc::PacketTransportInternal* transport) {
1480 RTC_DCHECK(network_thread_->IsCurrent());
1481 UpdateAggregateStates_n();
1482}
1483
1484void JsepTransportController::OnTransportGatheringState_n(
1485 cricket::IceTransportInternal* transport) {
1486 RTC_DCHECK(network_thread_->IsCurrent());
1487 UpdateAggregateStates_n();
1488}
1489
1490void JsepTransportController::OnTransportCandidateGathered_n(
1491 cricket::IceTransportInternal* transport,
1492 const cricket::Candidate& candidate) {
1493 RTC_DCHECK(network_thread_->IsCurrent());
1494
1495 // We should never signal peer-reflexive candidates.
1496 if (candidate.type() == cricket::PRFLX_PORT_TYPE) {
1497 RTC_NOTREACHED();
1498 return;
1499 }
Steve Antond25828a2018-08-31 13:06:05 -07001500 std::string transport_name = transport->transport_name();
1501 invoker_.AsyncInvoke<void>(
1502 RTC_FROM_HERE, signaling_thread_, [this, transport_name, candidate] {
1503 SignalIceCandidatesGathered(transport_name, {candidate});
1504 });
Zhi Huange818b6e2018-02-22 15:26:27 -08001505}
1506
Eldar Relloda13ea22019-06-01 12:23:43 +03001507void JsepTransportController::OnTransportCandidateError_n(
1508 cricket::IceTransportInternal* transport,
1509 const cricket::IceCandidateErrorEvent& event) {
1510 RTC_DCHECK(network_thread_->IsCurrent());
1511
1512 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_,
1513 [this, event] { SignalIceCandidateError(event); });
1514}
Zhi Huange818b6e2018-02-22 15:26:27 -08001515void JsepTransportController::OnTransportCandidatesRemoved_n(
1516 cricket::IceTransportInternal* transport,
1517 const cricket::Candidates& candidates) {
1518 invoker_.AsyncInvoke<void>(
1519 RTC_FROM_HERE, signaling_thread_,
Steve Antond25828a2018-08-31 13:06:05 -07001520 [this, candidates] { SignalIceCandidatesRemoved(candidates); });
Zhi Huange818b6e2018-02-22 15:26:27 -08001521}
Alex Drake00c7ecf2019-08-06 10:54:47 -07001522void JsepTransportController::OnTransportCandidatePairChanged_n(
1523 const cricket::CandidatePairChangeEvent& event) {
1524 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_, [this, event] {
1525 SignalIceCandidatePairChanged(event);
1526 });
1527}
Zhi Huange818b6e2018-02-22 15:26:27 -08001528
1529void JsepTransportController::OnTransportRoleConflict_n(
1530 cricket::IceTransportInternal* transport) {
1531 RTC_DCHECK(network_thread_->IsCurrent());
1532 // Note: since the role conflict is handled entirely on the network thread,
1533 // we don't need to worry about role conflicts occurring on two ports at
1534 // once. The first one encountered should immediately reverse the role.
1535 cricket::IceRole reversed_role = (ice_role_ == cricket::ICEROLE_CONTROLLING)
1536 ? cricket::ICEROLE_CONTROLLED
1537 : cricket::ICEROLE_CONTROLLING;
1538 RTC_LOG(LS_INFO) << "Got role conflict; switching to "
1539 << (reversed_role == cricket::ICEROLE_CONTROLLING
1540 ? "controlling"
1541 : "controlled")
1542 << " role.";
1543 SetIceRole_n(reversed_role);
1544}
1545
1546void JsepTransportController::OnTransportStateChanged_n(
1547 cricket::IceTransportInternal* transport) {
1548 RTC_DCHECK(network_thread_->IsCurrent());
1549 RTC_LOG(LS_INFO) << transport->transport_name() << " Transport "
1550 << transport->component()
1551 << " state changed. Check if state is complete.";
1552 UpdateAggregateStates_n();
1553}
1554
Bjorn Mellem175aa2e2018-11-08 11:23:22 -08001555void JsepTransportController::OnMediaTransportStateChanged_n() {
Bjorn Mellem175aa2e2018-11-08 11:23:22 -08001556 UpdateAggregateStates_n();
1557}
1558
Bjorn A Mellemb689af42019-08-21 10:44:59 -07001559void JsepTransportController::OnDataChannelTransportNegotiated_n(
1560 cricket::JsepTransport* transport,
Bjorn A Mellembc3eebc2019-09-23 14:53:54 -07001561 DataChannelTransportInterface* data_channel_transport) {
Bjorn A Mellemb689af42019-08-21 10:44:59 -07001562 for (auto it : mid_to_transport_) {
1563 if (it.second == transport) {
1564 config_.transport_observer->OnTransportChanged(
1565 it.first, transport->rtp_transport(), transport->RtpDtlsTransport(),
Bjorn A Mellembc3eebc2019-09-23 14:53:54 -07001566 transport->media_transport(), data_channel_transport);
Bjorn A Mellemb689af42019-08-21 10:44:59 -07001567 }
1568 }
1569}
1570
Zhi Huange818b6e2018-02-22 15:26:27 -08001571void JsepTransportController::UpdateAggregateStates_n() {
1572 RTC_DCHECK(network_thread_->IsCurrent());
1573
1574 auto dtls_transports = GetDtlsTransports();
Alex Loiko9289eda2018-11-23 16:18:59 +00001575 cricket::IceConnectionState new_connection_state =
1576 cricket::kIceConnectionConnecting;
Jonas Olsson635474e2018-10-18 15:58:17 +02001577 PeerConnectionInterface::IceConnectionState new_ice_connection_state =
1578 PeerConnectionInterface::IceConnectionState::kIceConnectionNew;
1579 PeerConnectionInterface::PeerConnectionState new_combined_state =
1580 PeerConnectionInterface::PeerConnectionState::kNew;
Zhi Huange818b6e2018-02-22 15:26:27 -08001581 cricket::IceGatheringState new_gathering_state = cricket::kIceGatheringNew;
Alex Loiko9289eda2018-11-23 16:18:59 +00001582 bool any_failed = false;
1583
1584 // TODO(http://bugs.webrtc.org/9719) If(when) media_transport disables
1585 // dtls_transports entirely, the below line will have to be changed to account
1586 // for the fact that dtls transports might be absent.
1587 bool all_connected = !dtls_transports.empty();
1588 bool all_completed = !dtls_transports.empty();
Zhi Huange818b6e2018-02-22 15:26:27 -08001589 bool any_gathering = false;
1590 bool all_done_gathering = !dtls_transports.empty();
Jonas Olsson635474e2018-10-18 15:58:17 +02001591
1592 std::map<IceTransportState, int> ice_state_counts;
1593 std::map<cricket::DtlsTransportState, int> dtls_state_counts;
1594
Zhi Huange818b6e2018-02-22 15:26:27 -08001595 for (const auto& dtls : dtls_transports) {
Alex Loiko9289eda2018-11-23 16:18:59 +00001596 any_failed = any_failed || dtls->ice_transport()->GetState() ==
1597 cricket::IceTransportState::STATE_FAILED;
1598 all_connected = all_connected && dtls->writable();
1599 all_completed =
1600 all_completed && dtls->writable() &&
1601 dtls->ice_transport()->GetState() ==
1602 cricket::IceTransportState::STATE_COMPLETED &&
1603 dtls->ice_transport()->GetIceRole() == cricket::ICEROLE_CONTROLLING &&
1604 dtls->ice_transport()->gathering_state() ==
1605 cricket::kIceGatheringComplete;
Zhi Huange818b6e2018-02-22 15:26:27 -08001606 any_gathering = any_gathering || dtls->ice_transport()->gathering_state() !=
1607 cricket::kIceGatheringNew;
1608 all_done_gathering =
1609 all_done_gathering && dtls->ice_transport()->gathering_state() ==
1610 cricket::kIceGatheringComplete;
Jonas Olsson635474e2018-10-18 15:58:17 +02001611
1612 dtls_state_counts[dtls->dtls_state()]++;
1613 ice_state_counts[dtls->ice_transport()->GetIceTransportState()]++;
Zhi Huange818b6e2018-02-22 15:26:27 -08001614 }
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001615
Bjorn A Mellemfa8f4ee2019-08-16 15:47:45 -07001616 // Don't indicate that the call failed or isn't connected due to media
1617 // transport state unless the media transport is used for media. If it's only
1618 // used for data channels, it will signal those separately.
1619 if (config_.use_media_transport_for_media || config_.use_datagram_transport) {
1620 for (auto it = jsep_transports_by_name_.begin();
1621 it != jsep_transports_by_name_.end(); ++it) {
1622 auto jsep_transport = it->second.get();
1623 if (!jsep_transport->media_transport()) {
1624 continue;
1625 }
Alex Loiko9289eda2018-11-23 16:18:59 +00001626
Bjorn A Mellemfa8f4ee2019-08-16 15:47:45 -07001627 // There is no 'kIceConnectionDisconnected', so we only need to handle
1628 // connected and completed.
1629 // We treat kClosed as failed, because if it happens before shutting down
1630 // media transports it means that there was a failure.
1631 // MediaTransportInterface allows to flip back and forth between kWritable
1632 // and kPending, but there does not exist an implementation that does
1633 // that, and the contract of jsep transport controller doesn't quite
1634 // expect that. When this happens, we would go from connected to
1635 // connecting state, but this may change in future.
1636 any_failed |= jsep_transport->media_transport_state() ==
1637 webrtc::MediaTransportState::kClosed;
1638 all_completed &= jsep_transport->media_transport_state() ==
1639 webrtc::MediaTransportState::kWritable;
1640 all_connected &= jsep_transport->media_transport_state() ==
1641 webrtc::MediaTransportState::kWritable;
1642 }
Alex Loiko9289eda2018-11-23 16:18:59 +00001643 }
1644
1645 if (any_failed) {
1646 new_connection_state = cricket::kIceConnectionFailed;
1647 } else if (all_completed) {
1648 new_connection_state = cricket::kIceConnectionCompleted;
1649 } else if (all_connected) {
1650 new_connection_state = cricket::kIceConnectionConnected;
1651 }
1652 if (ice_connection_state_ != new_connection_state) {
1653 ice_connection_state_ = new_connection_state;
1654 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_,
1655 [this, new_connection_state] {
1656 SignalIceConnectionState(new_connection_state);
1657 });
1658 }
1659
Jonas Olsson635474e2018-10-18 15:58:17 +02001660 // Compute the current RTCIceConnectionState as described in
1661 // https://www.w3.org/TR/webrtc/#dom-rtciceconnectionstate.
1662 // The PeerConnection is responsible for handling the "closed" state.
1663 int total_ice_checking = ice_state_counts[IceTransportState::kChecking];
1664 int total_ice_connected = ice_state_counts[IceTransportState::kConnected];
1665 int total_ice_completed = ice_state_counts[IceTransportState::kCompleted];
1666 int total_ice_failed = ice_state_counts[IceTransportState::kFailed];
1667 int total_ice_disconnected =
1668 ice_state_counts[IceTransportState::kDisconnected];
1669 int total_ice_closed = ice_state_counts[IceTransportState::kClosed];
1670 int total_ice_new = ice_state_counts[IceTransportState::kNew];
1671 int total_ice = dtls_transports.size();
1672
1673 if (total_ice_failed > 0) {
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001674 // Any RTCIceTransports are in the "failed" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001675 new_ice_connection_state = PeerConnectionInterface::kIceConnectionFailed;
Alex Loiko9289eda2018-11-23 16:18:59 +00001676 } else if (total_ice_disconnected > 0) {
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001677 // None of the previous states apply and any RTCIceTransports are in the
1678 // "disconnected" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001679 new_ice_connection_state =
1680 PeerConnectionInterface::kIceConnectionDisconnected;
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001681 } else if (total_ice_new + total_ice_closed == total_ice) {
1682 // None of the previous states apply and all RTCIceTransports are in the
1683 // "new" or "closed" state, or there are no transports.
1684 new_ice_connection_state = PeerConnectionInterface::kIceConnectionNew;
1685 } else if (total_ice_new + total_ice_checking > 0) {
1686 // None of the previous states apply and any RTCIceTransports are in the
1687 // "new" or "checking" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001688 new_ice_connection_state = PeerConnectionInterface::kIceConnectionChecking;
Jonas Olssonacd8ae72019-02-25 15:26:24 +01001689 } else if (total_ice_completed + total_ice_closed == total_ice ||
1690 all_completed) {
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001691 // None of the previous states apply and all RTCIceTransports are in the
1692 // "completed" or "closed" state.
Jonas Olssonacd8ae72019-02-25 15:26:24 +01001693 //
1694 // TODO(https://bugs.webrtc.org/10356): The all_completed condition is added
1695 // to mimic the behavior of the old ICE connection state, and should be
1696 // removed once we get end-of-candidates signaling in place.
Jonas Olsson635474e2018-10-18 15:58:17 +02001697 new_ice_connection_state = PeerConnectionInterface::kIceConnectionCompleted;
1698 } else if (total_ice_connected + total_ice_completed + total_ice_closed ==
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001699 total_ice) {
1700 // None of the previous states apply and all RTCIceTransports are in the
1701 // "connected", "completed" or "closed" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001702 new_ice_connection_state = PeerConnectionInterface::kIceConnectionConnected;
Jonas Olsson635474e2018-10-18 15:58:17 +02001703 } else {
1704 RTC_NOTREACHED();
1705 }
1706
Alex Loiko9289eda2018-11-23 16:18:59 +00001707 if (standardized_ice_connection_state_ != new_ice_connection_state) {
Jonas Olssonacd8ae72019-02-25 15:26:24 +01001708 if (standardized_ice_connection_state_ ==
1709 PeerConnectionInterface::kIceConnectionChecking &&
1710 new_ice_connection_state ==
1711 PeerConnectionInterface::kIceConnectionCompleted) {
1712 // Ensure that we never skip over the "connected" state.
1713 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_, [this] {
1714 SignalStandardizedIceConnectionState(
1715 PeerConnectionInterface::kIceConnectionConnected);
1716 });
1717 }
Alex Loiko9289eda2018-11-23 16:18:59 +00001718 standardized_ice_connection_state_ = new_ice_connection_state;
Jonas Olsson635474e2018-10-18 15:58:17 +02001719 invoker_.AsyncInvoke<void>(
1720 RTC_FROM_HERE, signaling_thread_, [this, new_ice_connection_state] {
Alex Loiko9289eda2018-11-23 16:18:59 +00001721 SignalStandardizedIceConnectionState(new_ice_connection_state);
Jonas Olsson635474e2018-10-18 15:58:17 +02001722 });
1723 }
1724
1725 // Compute the current RTCPeerConnectionState as described in
1726 // https://www.w3.org/TR/webrtc/#dom-rtcpeerconnectionstate.
1727 // The PeerConnection is responsible for handling the "closed" state.
1728 // Note that "connecting" is only a valid state for DTLS transports while
1729 // "checking", "completed" and "disconnected" are only valid for ICE
1730 // transports.
1731 int total_connected = total_ice_connected +
1732 dtls_state_counts[cricket::DTLS_TRANSPORT_CONNECTED];
1733 int total_dtls_connecting =
1734 dtls_state_counts[cricket::DTLS_TRANSPORT_CONNECTING];
1735 int total_failed =
1736 total_ice_failed + dtls_state_counts[cricket::DTLS_TRANSPORT_FAILED];
1737 int total_closed =
1738 total_ice_closed + dtls_state_counts[cricket::DTLS_TRANSPORT_CLOSED];
1739 int total_new =
1740 total_ice_new + dtls_state_counts[cricket::DTLS_TRANSPORT_NEW];
1741 int total_transports = total_ice * 2;
1742
1743 if (total_failed > 0) {
1744 // Any of the RTCIceTransports or RTCDtlsTransports are in a "failed" state.
1745 new_combined_state = PeerConnectionInterface::PeerConnectionState::kFailed;
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001746 } else if (total_ice_disconnected > 0) {
1747 // None of the previous states apply and any RTCIceTransports or
1748 // RTCDtlsTransports are in the "disconnected" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001749 new_combined_state =
1750 PeerConnectionInterface::PeerConnectionState::kDisconnected;
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001751 } else if (total_new + total_closed == total_transports) {
1752 // None of the previous states apply and all RTCIceTransports and
1753 // RTCDtlsTransports are in the "new" or "closed" state, or there are no
1754 // transports.
1755 new_combined_state = PeerConnectionInterface::PeerConnectionState::kNew;
1756 } else if (total_new + total_dtls_connecting + total_ice_checking > 0) {
1757 // None of the previous states apply and all RTCIceTransports or
1758 // RTCDtlsTransports are in the "new", "connecting" or "checking" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001759 new_combined_state =
1760 PeerConnectionInterface::PeerConnectionState::kConnecting;
1761 } else if (total_connected + total_ice_completed + total_closed ==
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001762 total_transports) {
1763 // None of the previous states apply and all RTCIceTransports and
1764 // RTCDtlsTransports are in the "connected", "completed" or "closed" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001765 new_combined_state =
1766 PeerConnectionInterface::PeerConnectionState::kConnected;
Jonas Olsson635474e2018-10-18 15:58:17 +02001767 } else {
1768 RTC_NOTREACHED();
1769 }
1770
1771 if (combined_connection_state_ != new_combined_state) {
1772 combined_connection_state_ = new_combined_state;
1773 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_,
1774 [this, new_combined_state] {
1775 SignalConnectionState(new_combined_state);
1776 });
1777 }
1778
Zhi Huange818b6e2018-02-22 15:26:27 -08001779 if (all_done_gathering) {
1780 new_gathering_state = cricket::kIceGatheringComplete;
1781 } else if (any_gathering) {
1782 new_gathering_state = cricket::kIceGatheringGathering;
1783 }
1784 if (ice_gathering_state_ != new_gathering_state) {
1785 ice_gathering_state_ = new_gathering_state;
Steve Antond25828a2018-08-31 13:06:05 -07001786 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_,
1787 [this, new_gathering_state] {
1788 SignalIceGatheringState(new_gathering_state);
1789 });
Zhi Huange818b6e2018-02-22 15:26:27 -08001790 }
1791}
1792
Sebastian Jansson1b83a9e2019-09-18 18:22:12 +02001793void JsepTransportController::OnRtcpPacketReceived_n(
1794 rtc::CopyOnWriteBuffer* packet,
1795 int64_t packet_time_us) {
1796 RTC_DCHECK(config_.rtcp_handler);
1797 config_.rtcp_handler(*packet, packet_time_us);
1798}
1799
Zhi Huange818b6e2018-02-22 15:26:27 -08001800void JsepTransportController::OnDtlsHandshakeError(
1801 rtc::SSLHandshakeError error) {
1802 SignalDtlsHandshakeError(error);
1803}
1804
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001805absl::optional<cricket::SessionDescription::MediaTransportSetting>
1806JsepTransportController::GenerateOrGetLastMediaTransportOffer() {
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07001807 if (media_transport_created_once_) {
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001808 RTC_LOG(LS_INFO) << "Not regenerating media transport for the new offer in "
1809 "existing session.";
1810 return media_transport_offer_settings_;
1811 }
1812
1813 RTC_LOG(LS_INFO) << "Generating media transport offer!";
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001814
1815 absl::optional<std::string> transport_parameters;
1816
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001817 // Check that media transport is supposed to be used.
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001818 // Note that ICE is not available when media transport is created. It will
1819 // only be available in 'Connect'. This may be a potential server config, if
1820 // we decide to use this peer connection as a caller, not as a callee.
1821 // TODO(sukhanov): Avoid code duplication with CreateMedia/MediaTransport.
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001822 if (config_.use_media_transport_for_media ||
1823 config_.use_media_transport_for_data_channels) {
1824 RTC_DCHECK(config_.media_transport_factory != nullptr);
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001825 RTC_DCHECK(!config_.use_datagram_transport);
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001826 webrtc::MediaTransportSettings settings;
1827 settings.is_caller = true;
1828 settings.pre_shared_key = rtc::CreateRandomString(32);
Bjorn A Mellemb073f1c2019-07-02 09:50:35 -07001829 if (config_.use_media_transport_for_media) {
1830 settings.event_log = config_.event_log;
1831 }
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001832 auto media_transport_or_error =
1833 config_.media_transport_factory->CreateMediaTransport(network_thread_,
1834 settings);
1835
1836 if (media_transport_or_error.ok()) {
1837 offer_media_transport_ = std::move(media_transport_or_error.value());
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001838 transport_parameters =
1839 offer_media_transport_->GetTransportParametersOffer();
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001840 } else {
1841 RTC_LOG(LS_INFO) << "Unable to create media transport, error="
1842 << media_transport_or_error.error().message();
1843 }
1844 }
1845
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07001846 if (!offer_media_transport_) {
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001847 RTC_LOG(LS_INFO) << "Media and data transports do not exist";
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001848 return absl::nullopt;
1849 }
1850
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001851 if (!transport_parameters) {
1852 RTC_LOG(LS_INFO) << "Media transport didn't generate the offer";
1853 // Media transport didn't generate the offer, and is not supposed to be
1854 // used. Destroy the temporary media transport.
1855 offer_media_transport_ = nullptr;
1856 return absl::nullopt;
1857 }
1858
1859 cricket::SessionDescription::MediaTransportSetting setting;
1860 setting.transport_name = config_.media_transport_factory->GetTransportName();
1861 setting.transport_setting = *transport_parameters;
1862 media_transport_offer_settings_ = setting;
1863 return setting;
1864}
1865
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07001866absl::optional<cricket::OpaqueTransportParameters>
1867JsepTransportController::GetTransportParameters(const std::string& mid) {
Bjorn A Mellemb689af42019-08-21 10:44:59 -07001868 if (!(config_.use_datagram_transport ||
1869 config_.use_datagram_transport_for_data_channels)) {
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07001870 return absl::nullopt;
1871 }
1872
1873 cricket::JsepTransport* transport = GetJsepTransportForMid(mid);
1874 if (transport) {
1875 absl::optional<cricket::OpaqueTransportParameters> params =
1876 transport->GetTransportParameters();
1877 if (params) {
1878 params->protocol = config_.media_transport_factory->GetTransportName();
1879 }
1880 return params;
1881 }
1882
1883 RTC_DCHECK(!local_desc_ && !remote_desc_)
1884 << "JsepTransport should exist for every mid once any description is set";
1885
Bjorn A Mellem7da4e562019-09-26 11:02:11 -07001886 if (config_.use_datagram_transport_for_data_channels_receive_only) {
1887 return absl::nullopt;
1888 }
1889
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07001890 // Need to generate a transport for the offer.
1891 if (!offer_datagram_transport_) {
1892 webrtc::MediaTransportSettings settings;
1893 settings.is_caller = true;
1894 settings.pre_shared_key = rtc::CreateRandomString(32);
1895 settings.event_log = config_.event_log;
1896 auto datagram_transport_or_error =
1897 config_.media_transport_factory->CreateDatagramTransport(
1898 network_thread_, settings);
1899
1900 if (datagram_transport_or_error.ok()) {
1901 offer_datagram_transport_ =
1902 std::move(datagram_transport_or_error.value());
1903 } else {
1904 RTC_LOG(LS_INFO) << "Unable to create datagram transport, error="
1905 << datagram_transport_or_error.error().message();
1906 }
1907 }
1908
1909 // We have prepared a transport for the offer, and can now use its parameters.
1910 cricket::OpaqueTransportParameters params;
1911 params.parameters = offer_datagram_transport_->GetTransportParameters();
1912 params.protocol = config_.media_transport_factory->GetTransportName();
1913 return params;
1914}
1915
Zhi Huange818b6e2018-02-22 15:26:27 -08001916} // namespace webrtc