blob: 41907c8f93c7f495f48d3363e0ddb18a2799b950 [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"
Qingsi Wang25ec8882019-11-15 12:33:05 -080017#include "api/ice_transport_factory.h"
Niels Möller65f17ca2019-09-12 13:59:36 +020018#include "api/transport/datagram_transport_interface.h"
19#include "api/transport/media/media_transport_interface.h"
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -080020#include "p2p/base/ice_transport_internal.h"
21#include "p2p/base/no_op_dtls_transport.h"
Zhi Huange818b6e2018-02-22 15:26:27 -080022#include "p2p/base/port.h"
Bjorn A Mellem364b2672019-08-20 16:58:03 -070023#include "pc/datagram_rtp_transport.h"
Steve Anton10542f22019-01-11 09:11:00 -080024#include "pc/srtp_filter.h"
Zhi Huange818b6e2018-02-22 15:26:27 -080025#include "rtc_base/bind.h"
26#include "rtc_base/checks.h"
Zhi Huange818b6e2018-02-22 15:26:27 -080027#include "rtc_base/thread.h"
28
29using webrtc::SdpType;
30
31namespace {
32
Zhi Huange818b6e2018-02-22 15:26:27 -080033webrtc::RTCError VerifyCandidate(const cricket::Candidate& cand) {
34 // No address zero.
35 if (cand.address().IsNil() || cand.address().IsAnyIP()) {
36 return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
37 "candidate has address of zero");
38 }
39
40 // Disallow all ports below 1024, except for 80 and 443 on public addresses.
41 int port = cand.address().port();
42 if (cand.protocol() == cricket::TCP_PROTOCOL_NAME &&
43 (cand.tcptype() == cricket::TCPTYPE_ACTIVE_STR || port == 0)) {
44 // Expected for active-only candidates per
45 // http://tools.ietf.org/html/rfc6544#section-4.5 so no error.
46 // Libjingle clients emit port 0, in "active" mode.
47 return webrtc::RTCError::OK();
48 }
49 if (port < 1024) {
50 if ((port != 80) && (port != 443)) {
51 return webrtc::RTCError(
52 webrtc::RTCErrorType::INVALID_PARAMETER,
53 "candidate has port below 1024, but not 80 or 443");
54 }
55
56 if (cand.address().IsPrivateIP()) {
57 return webrtc::RTCError(
58 webrtc::RTCErrorType::INVALID_PARAMETER,
59 "candidate has port of 80 or 443 with private IP address");
60 }
61 }
62
63 return webrtc::RTCError::OK();
64}
65
66webrtc::RTCError VerifyCandidates(const cricket::Candidates& candidates) {
67 for (const cricket::Candidate& candidate : candidates) {
68 webrtc::RTCError error = VerifyCandidate(candidate);
69 if (!error.ok()) {
70 return error;
71 }
72 }
73 return webrtc::RTCError::OK();
74}
75
76} // namespace
77
78namespace webrtc {
79
80JsepTransportController::JsepTransportController(
81 rtc::Thread* signaling_thread,
82 rtc::Thread* network_thread,
83 cricket::PortAllocator* port_allocator,
Zach Steine20867f2018-08-02 13:20:15 -070084 AsyncResolverFactory* async_resolver_factory,
Zhi Huange818b6e2018-02-22 15:26:27 -080085 Config config)
86 : signaling_thread_(signaling_thread),
87 network_thread_(network_thread),
88 port_allocator_(port_allocator),
Zach Steine20867f2018-08-02 13:20:15 -070089 async_resolver_factory_(async_resolver_factory),
Zhi Huang365381f2018-04-13 16:44:34 -070090 config_(config) {
91 // The |transport_observer| is assumed to be non-null.
92 RTC_DCHECK(config_.transport_observer);
Sebastian Jansson1b83a9e2019-09-18 18:22:12 +020093 RTC_DCHECK(config_.rtcp_handler);
Qingsi Wang25ec8882019-11-15 12:33:05 -080094 RTC_DCHECK(config_.ice_transport_factory);
Zhi Huang365381f2018-04-13 16:44:34 -070095}
Zhi Huange818b6e2018-02-22 15:26:27 -080096
97JsepTransportController::~JsepTransportController() {
98 // Channel destructors may try to send packets, so this needs to happen on
99 // the network thread.
100 network_thread_->Invoke<void>(
101 RTC_FROM_HERE,
102 rtc::Bind(&JsepTransportController::DestroyAllJsepTransports_n, this));
103}
104
105RTCError JsepTransportController::SetLocalDescription(
106 SdpType type,
107 const cricket::SessionDescription* description) {
108 if (!network_thread_->IsCurrent()) {
109 return network_thread_->Invoke<RTCError>(
110 RTC_FROM_HERE, [=] { return SetLocalDescription(type, description); });
111 }
112
113 if (!initial_offerer_.has_value()) {
114 initial_offerer_.emplace(type == SdpType::kOffer);
115 if (*initial_offerer_) {
116 SetIceRole_n(cricket::ICEROLE_CONTROLLING);
117 } else {
118 SetIceRole_n(cricket::ICEROLE_CONTROLLED);
119 }
120 }
121 return ApplyDescription_n(/*local=*/true, type, description);
122}
123
124RTCError JsepTransportController::SetRemoteDescription(
125 SdpType type,
126 const cricket::SessionDescription* description) {
127 if (!network_thread_->IsCurrent()) {
128 return network_thread_->Invoke<RTCError>(
129 RTC_FROM_HERE, [=] { return SetRemoteDescription(type, description); });
130 }
131
132 return ApplyDescription_n(/*local=*/false, type, description);
133}
134
135RtpTransportInternal* JsepTransportController::GetRtpTransport(
136 const std::string& mid) const {
Zhi Huange830e682018-03-30 10:48:35 -0700137 auto jsep_transport = GetJsepTransportForMid(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -0800138 if (!jsep_transport) {
139 return nullptr;
140 }
141 return jsep_transport->rtp_transport();
142}
143
Anton Sukhanov316f3ac2019-05-23 15:50:38 -0700144MediaTransportConfig JsepTransportController::GetMediaTransportConfig(
Anton Sukhanov7940da02018-10-10 10:34:49 -0700145 const std::string& mid) const {
146 auto jsep_transport = GetJsepTransportForMid(mid);
147 if (!jsep_transport) {
Anton Sukhanov316f3ac2019-05-23 15:50:38 -0700148 return MediaTransportConfig();
149 }
150
151 MediaTransportInterface* media_transport = nullptr;
152 if (config_.use_media_transport_for_media) {
153 media_transport = jsep_transport->media_transport();
154 }
155
Bjorn A Mellemb689af42019-08-21 10:44:59 -0700156 DatagramTransportInterface* datagram_transport = nullptr;
157 if (config_.use_datagram_transport) {
158 datagram_transport = jsep_transport->datagram_transport();
159 }
Anton Sukhanov316f3ac2019-05-23 15:50:38 -0700160
161 // Media transport and datagram transports can not be used together.
162 RTC_DCHECK(!media_transport || !datagram_transport);
163
164 if (media_transport) {
165 return MediaTransportConfig(media_transport);
166 } else if (datagram_transport) {
167 return MediaTransportConfig(
168 /*rtp_max_packet_size=*/datagram_transport->GetLargestDatagramSize());
169 } else {
170 return MediaTransportConfig();
171 }
172}
173
Bjorn A Mellemb689af42019-08-21 10:44:59 -0700174DataChannelTransportInterface* JsepTransportController::GetDataChannelTransport(
Anton Sukhanov316f3ac2019-05-23 15:50:38 -0700175 const std::string& mid) const {
176 auto jsep_transport = GetJsepTransportForMid(mid);
Bjorn A Mellemb689af42019-08-21 10:44:59 -0700177 if (!jsep_transport) {
Anton Sukhanov7940da02018-10-10 10:34:49 -0700178 return nullptr;
179 }
Bjorn A Mellembc3eebc2019-09-23 14:53:54 -0700180 return jsep_transport->data_channel_transport();
Anton Sukhanov7940da02018-10-10 10:34:49 -0700181}
182
Bjorn Mellem175aa2e2018-11-08 11:23:22 -0800183MediaTransportState JsepTransportController::GetMediaTransportState(
184 const std::string& mid) const {
185 auto jsep_transport = GetJsepTransportForMid(mid);
186 if (!jsep_transport) {
187 return MediaTransportState::kPending;
188 }
189 return jsep_transport->media_transport_state();
190}
191
Zhi Huange818b6e2018-02-22 15:26:27 -0800192cricket::DtlsTransportInternal* JsepTransportController::GetDtlsTransport(
Harald Alvestrandad88c882018-11-28 16:47:46 +0100193 const std::string& mid) {
Zhi Huange830e682018-03-30 10:48:35 -0700194 auto jsep_transport = GetJsepTransportForMid(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -0800195 if (!jsep_transport) {
196 return nullptr;
197 }
198 return jsep_transport->rtp_dtls_transport();
199}
200
Harald Alvestrandad88c882018-11-28 16:47:46 +0100201const cricket::DtlsTransportInternal*
202JsepTransportController::GetRtcpDtlsTransport(const std::string& mid) const {
Zhi Huange830e682018-03-30 10:48:35 -0700203 auto jsep_transport = GetJsepTransportForMid(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -0800204 if (!jsep_transport) {
205 return nullptr;
206 }
207 return jsep_transport->rtcp_dtls_transport();
208}
209
Harald Alvestrand4a7b3ac2019-01-17 10:39:40 +0100210rtc::scoped_refptr<webrtc::DtlsTransport>
Harald Alvestrandad88c882018-11-28 16:47:46 +0100211JsepTransportController::LookupDtlsTransportByMid(const std::string& mid) {
212 auto jsep_transport = GetJsepTransportForMid(mid);
213 if (!jsep_transport) {
214 return nullptr;
215 }
216 return jsep_transport->RtpDtlsTransport();
217}
218
Bjorn A Mellembc3eebc2019-09-23 14:53:54 -0700219rtc::scoped_refptr<SctpTransport> JsepTransportController::GetSctpTransport(
220 const std::string& mid) const {
221 auto jsep_transport = GetJsepTransportForMid(mid);
222 if (!jsep_transport) {
223 return nullptr;
224 }
225 return jsep_transport->SctpTransport();
226}
227
Zhi Huange818b6e2018-02-22 15:26:27 -0800228void JsepTransportController::SetIceConfig(const cricket::IceConfig& config) {
229 if (!network_thread_->IsCurrent()) {
230 network_thread_->Invoke<void>(RTC_FROM_HERE, [&] { SetIceConfig(config); });
231 return;
232 }
233
234 ice_config_ = config;
235 for (auto& dtls : GetDtlsTransports()) {
236 dtls->ice_transport()->SetIceConfig(ice_config_);
237 }
238}
239
240void JsepTransportController::SetNeedsIceRestartFlag() {
Zhi Huange830e682018-03-30 10:48:35 -0700241 for (auto& kv : jsep_transports_by_name_) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800242 kv.second->SetNeedsIceRestartFlag();
243 }
244}
245
246bool JsepTransportController::NeedsIceRestart(
247 const std::string& transport_name) const {
Zhi Huang365381f2018-04-13 16:44:34 -0700248 const cricket::JsepTransport* transport =
Zhi Huange830e682018-03-30 10:48:35 -0700249 GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800250 if (!transport) {
251 return false;
252 }
253 return transport->needs_ice_restart();
254}
255
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200256absl::optional<rtc::SSLRole> JsepTransportController::GetDtlsRole(
Zhi Huange830e682018-03-30 10:48:35 -0700257 const std::string& mid) const {
Zhi Huange818b6e2018-02-22 15:26:27 -0800258 if (!network_thread_->IsCurrent()) {
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200259 return network_thread_->Invoke<absl::optional<rtc::SSLRole>>(
Zhi Huange830e682018-03-30 10:48:35 -0700260 RTC_FROM_HERE, [&] { return GetDtlsRole(mid); });
Zhi Huange818b6e2018-02-22 15:26:27 -0800261 }
262
Zhi Huang365381f2018-04-13 16:44:34 -0700263 const cricket::JsepTransport* t = GetJsepTransportForMid(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -0800264 if (!t) {
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200265 return absl::optional<rtc::SSLRole>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800266 }
267 return t->GetDtlsRole();
268}
269
270bool JsepTransportController::SetLocalCertificate(
271 const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) {
272 if (!network_thread_->IsCurrent()) {
273 return network_thread_->Invoke<bool>(
274 RTC_FROM_HERE, [&] { return SetLocalCertificate(certificate); });
275 }
276
277 // Can't change a certificate, or set a null certificate.
278 if (certificate_ || !certificate) {
279 return false;
280 }
281 certificate_ = certificate;
282
283 // Set certificate for JsepTransport, which verifies it matches the
284 // fingerprint in SDP, and DTLS transport.
285 // Fallback from DTLS to SDES is not supported.
Zhi Huange830e682018-03-30 10:48:35 -0700286 for (auto& kv : jsep_transports_by_name_) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800287 kv.second->SetLocalCertificate(certificate_);
288 }
289 for (auto& dtls : GetDtlsTransports()) {
290 bool set_cert_success = dtls->SetLocalCertificate(certificate_);
291 RTC_DCHECK(set_cert_success);
292 }
293 return true;
294}
295
296rtc::scoped_refptr<rtc::RTCCertificate>
297JsepTransportController::GetLocalCertificate(
298 const std::string& transport_name) const {
299 if (!network_thread_->IsCurrent()) {
300 return network_thread_->Invoke<rtc::scoped_refptr<rtc::RTCCertificate>>(
301 RTC_FROM_HERE, [&] { return GetLocalCertificate(transport_name); });
302 }
303
Zhi Huang365381f2018-04-13 16:44:34 -0700304 const cricket::JsepTransport* t = GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800305 if (!t) {
306 return nullptr;
307 }
308 return t->GetLocalCertificate();
309}
310
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800311std::unique_ptr<rtc::SSLCertChain>
312JsepTransportController::GetRemoteSSLCertChain(
Zhi Huange818b6e2018-02-22 15:26:27 -0800313 const std::string& transport_name) const {
314 if (!network_thread_->IsCurrent()) {
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800315 return network_thread_->Invoke<std::unique_ptr<rtc::SSLCertChain>>(
316 RTC_FROM_HERE, [&] { return GetRemoteSSLCertChain(transport_name); });
Zhi Huange818b6e2018-02-22 15:26:27 -0800317 }
318
Zhi Huange830e682018-03-30 10:48:35 -0700319 // Get the certificate from the RTP transport's DTLS handshake. Should be
320 // identical to the RTCP transport's, since they were given the same remote
Zhi Huange818b6e2018-02-22 15:26:27 -0800321 // fingerprint.
Zhi Huange830e682018-03-30 10:48:35 -0700322 auto jsep_transport = GetJsepTransportByName(transport_name);
323 if (!jsep_transport) {
324 return nullptr;
325 }
326 auto dtls = jsep_transport->rtp_dtls_transport();
Zhi Huange818b6e2018-02-22 15:26:27 -0800327 if (!dtls) {
328 return nullptr;
329 }
330
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800331 return dtls->GetRemoteSSLCertChain();
Zhi Huange818b6e2018-02-22 15:26:27 -0800332}
333
334void JsepTransportController::MaybeStartGathering() {
335 if (!network_thread_->IsCurrent()) {
336 network_thread_->Invoke<void>(RTC_FROM_HERE,
337 [&] { MaybeStartGathering(); });
338 return;
339 }
340
341 for (auto& dtls : GetDtlsTransports()) {
342 dtls->ice_transport()->MaybeStartGathering();
343 }
344}
345
346RTCError JsepTransportController::AddRemoteCandidates(
347 const std::string& transport_name,
348 const cricket::Candidates& candidates) {
349 if (!network_thread_->IsCurrent()) {
350 return network_thread_->Invoke<RTCError>(RTC_FROM_HERE, [&] {
351 return AddRemoteCandidates(transport_name, candidates);
352 });
353 }
354
355 // Verify each candidate before passing down to the transport layer.
356 RTCError error = VerifyCandidates(candidates);
357 if (!error.ok()) {
358 return error;
359 }
Zhi Huange830e682018-03-30 10:48:35 -0700360 auto jsep_transport = GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800361 if (!jsep_transport) {
Zhi Huange830e682018-03-30 10:48:35 -0700362 RTC_LOG(LS_WARNING) << "Not adding candidate because the JsepTransport "
363 "doesn't exist. Ignore it.";
364 return RTCError::OK();
Zhi Huange818b6e2018-02-22 15:26:27 -0800365 }
Zhi Huange818b6e2018-02-22 15:26:27 -0800366 return jsep_transport->AddRemoteCandidates(candidates);
367}
368
369RTCError JsepTransportController::RemoveRemoteCandidates(
370 const cricket::Candidates& candidates) {
371 if (!network_thread_->IsCurrent()) {
372 return network_thread_->Invoke<RTCError>(
373 RTC_FROM_HERE, [&] { return RemoveRemoteCandidates(candidates); });
374 }
375
376 // Verify each candidate before passing down to the transport layer.
377 RTCError error = VerifyCandidates(candidates);
378 if (!error.ok()) {
379 return error;
380 }
381
382 std::map<std::string, cricket::Candidates> candidates_by_transport_name;
383 for (const cricket::Candidate& cand : candidates) {
384 if (!cand.transport_name().empty()) {
385 candidates_by_transport_name[cand.transport_name()].push_back(cand);
386 } else {
387 RTC_LOG(LS_ERROR) << "Not removing candidate because it does not have a "
388 "transport name set: "
Qingsi Wang20232a92019-09-06 12:51:17 -0700389 << cand.ToSensitiveString();
Zhi Huange818b6e2018-02-22 15:26:27 -0800390 }
391 }
392
393 for (const auto& kv : candidates_by_transport_name) {
394 const std::string& transport_name = kv.first;
395 const cricket::Candidates& candidates = kv.second;
Zhi Huang365381f2018-04-13 16:44:34 -0700396 cricket::JsepTransport* jsep_transport =
Zhi Huange830e682018-03-30 10:48:35 -0700397 GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800398 if (!jsep_transport) {
Zhi Huange830e682018-03-30 10:48:35 -0700399 RTC_LOG(LS_WARNING)
400 << "Not removing candidate because the JsepTransport doesn't exist.";
401 continue;
Zhi Huange818b6e2018-02-22 15:26:27 -0800402 }
403 for (const cricket::Candidate& candidate : candidates) {
Harald Alvestrandad88c882018-11-28 16:47:46 +0100404 cricket::DtlsTransportInternal* dtls =
405 candidate.component() == cricket::ICE_CANDIDATE_COMPONENT_RTP
406 ? jsep_transport->rtp_dtls_transport()
407 : jsep_transport->rtcp_dtls_transport();
Zhi Huange818b6e2018-02-22 15:26:27 -0800408 if (dtls) {
409 dtls->ice_transport()->RemoveRemoteCandidate(candidate);
410 }
411 }
412 }
413 return RTCError::OK();
414}
415
416bool JsepTransportController::GetStats(const std::string& transport_name,
417 cricket::TransportStats* stats) {
418 if (!network_thread_->IsCurrent()) {
419 return network_thread_->Invoke<bool>(
420 RTC_FROM_HERE, [=] { return GetStats(transport_name, stats); });
421 }
422
Zhi Huang365381f2018-04-13 16:44:34 -0700423 cricket::JsepTransport* transport = GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800424 if (!transport) {
425 return false;
426 }
427 return transport->GetStats(stats);
428}
429
Zhi Huangb57e1692018-06-12 11:41:11 -0700430void JsepTransportController::SetActiveResetSrtpParams(
431 bool active_reset_srtp_params) {
432 if (!network_thread_->IsCurrent()) {
433 network_thread_->Invoke<void>(RTC_FROM_HERE, [=] {
434 SetActiveResetSrtpParams(active_reset_srtp_params);
435 });
436 return;
437 }
438
439 RTC_LOG(INFO)
440 << "Updating the active_reset_srtp_params for JsepTransportController: "
441 << active_reset_srtp_params;
442 config_.active_reset_srtp_params = active_reset_srtp_params;
443 for (auto& kv : jsep_transports_by_name_) {
444 kv.second->SetActiveResetSrtpParams(active_reset_srtp_params);
445 }
446}
447
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800448void JsepTransportController::SetMediaTransportSettings(
449 bool use_media_transport_for_media,
Anton Sukhanov316f3ac2019-05-23 15:50:38 -0700450 bool use_media_transport_for_data_channels,
Bjorn A Mellemb689af42019-08-21 10:44:59 -0700451 bool use_datagram_transport,
Bjorn A Mellem7da4e562019-09-26 11:02:11 -0700452 bool use_datagram_transport_for_data_channels,
453 bool use_datagram_transport_for_data_channels_receive_only) {
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800454 RTC_DCHECK(use_media_transport_for_media ==
455 config_.use_media_transport_for_media ||
Piotr (Peter) Slatala97fc11f2018-10-18 12:57:59 -0700456 jsep_transports_by_name_.empty())
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800457 << "You can only change media transport configuration before creating "
458 "the first transport.";
459
460 RTC_DCHECK(use_media_transport_for_data_channels ==
461 config_.use_media_transport_for_data_channels ||
462 jsep_transports_by_name_.empty())
463 << "You can only change media transport configuration before creating "
464 "the first transport.";
465
466 config_.use_media_transport_for_media = use_media_transport_for_media;
467 config_.use_media_transport_for_data_channels =
468 use_media_transport_for_data_channels;
Anton Sukhanov316f3ac2019-05-23 15:50:38 -0700469 config_.use_datagram_transport = use_datagram_transport;
Bjorn A Mellemb689af42019-08-21 10:44:59 -0700470 config_.use_datagram_transport_for_data_channels =
471 use_datagram_transport_for_data_channels;
Bjorn A Mellem7da4e562019-09-26 11:02:11 -0700472 config_.use_datagram_transport_for_data_channels_receive_only =
473 use_datagram_transport_for_data_channels_receive_only;
Piotr (Peter) Slatala97fc11f2018-10-18 12:57:59 -0700474}
475
Eldar Rello5ab79e62019-10-09 18:29:44 +0300476void JsepTransportController::RollbackTransportForMid(const std::string& mid) {
477 if (!network_thread_->IsCurrent()) {
478 network_thread_->Invoke<void>(RTC_FROM_HERE,
479 [=] { RollbackTransportForMid(mid); });
480 return;
481 }
482 RemoveTransportForMid(mid);
483 MaybeDestroyJsepTransport(mid);
484}
485
Qingsi Wang25ec8882019-11-15 12:33:05 -0800486rtc::scoped_refptr<webrtc::IceTransportInterface>
487JsepTransportController::CreateIceTransport(const std::string& transport_name,
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800488 bool rtcp) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800489 int component = rtcp ? cricket::ICE_CANDIDATE_COMPONENT_RTCP
490 : cricket::ICE_CANDIDATE_COMPONENT_RTP;
491
Qingsi Wang25ec8882019-11-15 12:33:05 -0800492 IceTransportInit init;
493 init.set_port_allocator(port_allocator_);
494 init.set_async_resolver_factory(async_resolver_factory_);
495 init.set_event_log(config_.event_log);
496 return config_.ice_transport_factory->CreateIceTransport(
497 transport_name, component, std::move(init));
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800498}
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);
Qingsi Wang25ec8882019-11-15 12:33:05 -0800520 } else if (config_.dtls_transport_factory) {
521 dtls = config_.dtls_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
Qingsi Wang25ec8882019-11-15 12:33:05 -08001253 rtc::scoped_refptr<webrtc::IceTransportInterface> ice =
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001254 CreateIceTransport(content_info.name, /*rtcp=*/false);
Qingsi Wang25ec8882019-11-15 12:33:05 -08001255 RTC_DCHECK(ice);
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001256
1257 std::unique_ptr<MediaTransportInterface> media_transport =
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001258 MaybeCreateMediaTransport(content_info, description, local);
1259 if (media_transport) {
1260 media_transport_created_once_ = true;
Qingsi Wang25ec8882019-11-15 12:33:05 -08001261 media_transport->Connect(ice->internal());
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001262 }
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001263
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001264 std::unique_ptr<DatagramTransportInterface> datagram_transport =
1265 MaybeCreateDatagramTransport(content_info, description, local);
1266 if (datagram_transport) {
Qingsi Wang25ec8882019-11-15 12:33:05 -08001267 datagram_transport->Connect(ice->internal());
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001268 }
1269
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001270 std::unique_ptr<cricket::DtlsTransportInternal> rtp_dtls_transport =
Qingsi Wang25ec8882019-11-15 12:33:05 -08001271 CreateDtlsTransport(content_info, ice->internal(), nullptr);
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001272
1273 std::unique_ptr<cricket::DtlsTransportInternal> rtcp_dtls_transport;
1274 std::unique_ptr<RtpTransport> unencrypted_rtp_transport;
1275 std::unique_ptr<SrtpTransport> sdes_transport;
1276 std::unique_ptr<DtlsSrtpTransport> dtls_srtp_transport;
Bjorn A Mellem364b2672019-08-20 16:58:03 -07001277 std::unique_ptr<RtpTransportInternal> datagram_rtp_transport;
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001278
Qingsi Wang25ec8882019-11-15 12:33:05 -08001279 rtc::scoped_refptr<webrtc::IceTransportInterface> rtcp_ice;
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001280 if (config_.rtcp_mux_policy !=
1281 PeerConnectionInterface::kRtcpMuxPolicyRequire &&
1282 content_info.type == cricket::MediaProtocolType::kRtp) {
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001283 RTC_DCHECK(media_transport == nullptr);
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001284 RTC_DCHECK(datagram_transport == nullptr);
Bjorn A Mellem0c1c1b42019-05-29 17:34:13 -07001285 rtcp_ice = CreateIceTransport(content_info.name, /*rtcp=*/true);
Qingsi Wang25ec8882019-11-15 12:33:05 -08001286 rtcp_dtls_transport =
1287 CreateDtlsTransport(content_info, rtcp_ice->internal(),
1288 /*datagram_transport=*/nullptr);
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001289 }
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001290
Bjorn A Mellem703ea952019-08-23 10:31:11 -07001291 // Only create a datagram RTP transport if the datagram transport should be
1292 // used for RTP.
1293 if (datagram_transport && config_.use_datagram_transport) {
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001294 // TODO(sukhanov): We use unencrypted RTP transport over DatagramTransport,
1295 // because MediaTransport encrypts. In the future we may want to
1296 // implement our own version of RtpTransport over MediaTransport, because
1297 // it will give us more control over things like:
1298 // - Fusing
1299 // - Rtp header compression
1300 // - Handling Rtcp feedback.
1301 RTC_LOG(LS_INFO) << "Creating UnencryptedRtpTransport, because datagram "
1302 "transport is used.";
1303 RTC_DCHECK(!rtcp_dtls_transport);
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001304 datagram_rtp_transport = std::make_unique<DatagramRtpTransport>(
Qingsi Wang25ec8882019-11-15 12:33:05 -08001305 content_info.media_description()->rtp_header_extensions(),
1306 ice->internal(), datagram_transport.get());
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07001307 }
1308
1309 if (config_.disable_encryption) {
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001310 RTC_LOG(LS_INFO)
1311 << "Creating UnencryptedRtpTransport, becayse encryption is disabled.";
Zhi Huange818b6e2018-02-22 15:26:27 -08001312 unencrypted_rtp_transport = CreateUnencryptedRtpTransport(
Zhi Huangd2248f82018-04-10 14:41:03 -07001313 content_info.name, rtp_dtls_transport.get(), rtcp_dtls_transport.get());
Zhi Huange818b6e2018-02-22 15:26:27 -08001314 } else if (!content_desc->cryptos().empty()) {
Zhi Huangd2248f82018-04-10 14:41:03 -07001315 sdes_transport = CreateSdesTransport(
1316 content_info.name, rtp_dtls_transport.get(), rtcp_dtls_transport.get());
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001317 RTC_LOG(LS_INFO) << "Creating SdesTransport.";
Zhi Huange818b6e2018-02-22 15:26:27 -08001318 } else {
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001319 RTC_LOG(LS_INFO) << "Creating DtlsSrtpTransport.";
Zhi Huangd2248f82018-04-10 14:41:03 -07001320 dtls_srtp_transport = CreateDtlsSrtpTransport(
1321 content_info.name, rtp_dtls_transport.get(), rtcp_dtls_transport.get());
Zhi Huange818b6e2018-02-22 15:26:27 -08001322 }
1323
Bjorn A Mellembc3eebc2019-09-23 14:53:54 -07001324 std::unique_ptr<cricket::SctpTransportInternal> sctp_transport;
1325 if (config_.sctp_factory) {
1326 sctp_transport =
1327 config_.sctp_factory->CreateSctpTransport(rtp_dtls_transport.get());
1328 }
1329
1330 DataChannelTransportInterface* data_channel_transport = nullptr;
1331 if (config_.use_datagram_transport_for_data_channels) {
1332 data_channel_transport = datagram_transport.get();
1333 } else if (config_.use_media_transport_for_data_channels) {
1334 data_channel_transport = media_transport.get();
1335 }
1336
Zhi Huang365381f2018-04-13 16:44:34 -07001337 std::unique_ptr<cricket::JsepTransport> jsep_transport =
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001338 std::make_unique<cricket::JsepTransport>(
Bjorn A Mellem0c1c1b42019-05-29 17:34:13 -07001339 content_info.name, certificate_, std::move(ice), std::move(rtcp_ice),
1340 std::move(unencrypted_rtp_transport), std::move(sdes_transport),
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07001341 std::move(dtls_srtp_transport), std::move(datagram_rtp_transport),
1342 std::move(rtp_dtls_transport), std::move(rtcp_dtls_transport),
Bjorn A Mellembc3eebc2019-09-23 14:53:54 -07001343 std::move(sctp_transport), std::move(media_transport),
1344 std::move(datagram_transport), data_channel_transport);
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001345
Sebastian Jansson1b83a9e2019-09-18 18:22:12 +02001346 jsep_transport->rtp_transport()->SignalRtcpPacketReceived.connect(
1347 this, &JsepTransportController::OnRtcpPacketReceived_n);
1348
Zhi Huange818b6e2018-02-22 15:26:27 -08001349 jsep_transport->SignalRtcpMuxActive.connect(
1350 this, &JsepTransportController::UpdateAggregateStates_n);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001351 jsep_transport->SignalMediaTransportStateChanged.connect(
Bjorn Mellem175aa2e2018-11-08 11:23:22 -08001352 this, &JsepTransportController::OnMediaTransportStateChanged_n);
Bjorn A Mellemb689af42019-08-21 10:44:59 -07001353 jsep_transport->SignalDataChannelTransportNegotiated.connect(
1354 this, &JsepTransportController::OnDataChannelTransportNegotiated_n);
Taylor Brandstettercbaa2542018-04-16 16:42:14 -07001355 SetTransportForMid(content_info.name, jsep_transport.get());
Zhi Huange830e682018-03-30 10:48:35 -07001356
Zhi Huangd2248f82018-04-10 14:41:03 -07001357 jsep_transports_by_name_[content_info.name] = std::move(jsep_transport);
1358 UpdateAggregateStates_n();
Zhi Huange830e682018-03-30 10:48:35 -07001359 return RTCError::OK();
Zhi Huange818b6e2018-02-22 15:26:27 -08001360}
1361
1362void JsepTransportController::MaybeDestroyJsepTransport(
1363 const std::string& mid) {
Zhi Huangd2248f82018-04-10 14:41:03 -07001364 auto jsep_transport = GetJsepTransportByName(mid);
1365 if (!jsep_transport) {
1366 return;
1367 }
1368
1369 // Don't destroy the JsepTransport if there are still media sections referring
1370 // to it.
1371 for (const auto& kv : mid_to_transport_) {
1372 if (kv.second == jsep_transport) {
1373 return;
1374 }
1375 }
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -08001376
Zhi Huange830e682018-03-30 10:48:35 -07001377 jsep_transports_by_name_.erase(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -08001378 UpdateAggregateStates_n();
1379}
1380
1381void JsepTransportController::DestroyAllJsepTransports_n() {
1382 RTC_DCHECK(network_thread_->IsCurrent());
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -08001383
1384 for (const auto& jsep_transport : jsep_transports_by_name_) {
Bjorn A Mellemb689af42019-08-21 10:44:59 -07001385 config_.transport_observer->OnTransportChanged(
Bjorn A Mellembc3eebc2019-09-23 14:53:54 -07001386 jsep_transport.first, nullptr, nullptr, nullptr, nullptr);
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -08001387 }
1388
Zhi Huange830e682018-03-30 10:48:35 -07001389 jsep_transports_by_name_.clear();
Zhi Huange818b6e2018-02-22 15:26:27 -08001390}
1391
1392void JsepTransportController::SetIceRole_n(cricket::IceRole ice_role) {
1393 RTC_DCHECK(network_thread_->IsCurrent());
1394
1395 ice_role_ = ice_role;
1396 for (auto& dtls : GetDtlsTransports()) {
1397 dtls->ice_transport()->SetIceRole(ice_role_);
1398 }
1399}
1400
1401cricket::IceRole JsepTransportController::DetermineIceRole(
Zhi Huang365381f2018-04-13 16:44:34 -07001402 cricket::JsepTransport* jsep_transport,
Zhi Huange818b6e2018-02-22 15:26:27 -08001403 const cricket::TransportInfo& transport_info,
1404 SdpType type,
1405 bool local) {
1406 cricket::IceRole ice_role = ice_role_;
1407 auto tdesc = transport_info.description;
1408 if (local) {
1409 // The initial offer side may use ICE Lite, in which case, per RFC5245
1410 // Section 5.1.1, the answer side should take the controlling role if it is
1411 // in the full ICE mode.
1412 //
1413 // When both sides use ICE Lite, the initial offer side must take the
1414 // controlling role, and this is the default logic implemented in
1415 // SetLocalDescription in JsepTransportController.
1416 if (jsep_transport->remote_description() &&
1417 jsep_transport->remote_description()->transport_desc.ice_mode ==
1418 cricket::ICEMODE_LITE &&
1419 ice_role_ == cricket::ICEROLE_CONTROLLED &&
1420 tdesc.ice_mode == cricket::ICEMODE_FULL) {
1421 ice_role = cricket::ICEROLE_CONTROLLING;
1422 }
1423
1424 // Older versions of Chrome expect the ICE role to be re-determined when an
1425 // ICE restart occurs, and also don't perform conflict resolution correctly,
1426 // so for now we can't safely stop doing this, unless the application opts
1427 // in by setting |config_.redetermine_role_on_ice_restart_| to false. See:
1428 // https://bugs.chromium.org/p/chromium/issues/detail?id=628676
1429 // TODO(deadbeef): Remove this when these old versions of Chrome reach a low
1430 // enough population.
1431 if (config_.redetermine_role_on_ice_restart &&
1432 jsep_transport->local_description() &&
1433 cricket::IceCredentialsChanged(
1434 jsep_transport->local_description()->transport_desc.ice_ufrag,
1435 jsep_transport->local_description()->transport_desc.ice_pwd,
1436 tdesc.ice_ufrag, tdesc.ice_pwd) &&
1437 // Don't change the ICE role if the remote endpoint is ICE lite; we
1438 // should always be controlling in that case.
1439 (!jsep_transport->remote_description() ||
1440 jsep_transport->remote_description()->transport_desc.ice_mode !=
1441 cricket::ICEMODE_LITE)) {
1442 ice_role = (type == SdpType::kOffer) ? cricket::ICEROLE_CONTROLLING
1443 : cricket::ICEROLE_CONTROLLED;
1444 }
1445 } else {
1446 // If our role is cricket::ICEROLE_CONTROLLED and the remote endpoint
1447 // supports only ice_lite, this local endpoint should take the CONTROLLING
1448 // role.
1449 // TODO(deadbeef): This is a session-level attribute, so it really shouldn't
1450 // be in a TransportDescription in the first place...
1451 if (ice_role_ == cricket::ICEROLE_CONTROLLED &&
1452 tdesc.ice_mode == cricket::ICEMODE_LITE) {
1453 ice_role = cricket::ICEROLE_CONTROLLING;
1454 }
1455
1456 // If we use ICE Lite and the remote endpoint uses the full implementation
1457 // of ICE, the local endpoint must take the controlled role, and the other
1458 // side must be the controlling role.
1459 if (jsep_transport->local_description() &&
1460 jsep_transport->local_description()->transport_desc.ice_mode ==
1461 cricket::ICEMODE_LITE &&
1462 ice_role_ == cricket::ICEROLE_CONTROLLING &&
Zhi Huange830e682018-03-30 10:48:35 -07001463 tdesc.ice_mode == cricket::ICEMODE_FULL) {
Zhi Huange818b6e2018-02-22 15:26:27 -08001464 ice_role = cricket::ICEROLE_CONTROLLED;
1465 }
1466 }
1467
1468 return ice_role;
1469}
1470
1471void JsepTransportController::OnTransportWritableState_n(
1472 rtc::PacketTransportInternal* transport) {
1473 RTC_DCHECK(network_thread_->IsCurrent());
1474 RTC_LOG(LS_INFO) << " Transport " << transport->transport_name()
1475 << " writability changed to " << transport->writable()
1476 << ".";
1477 UpdateAggregateStates_n();
1478}
1479
1480void JsepTransportController::OnTransportReceivingState_n(
1481 rtc::PacketTransportInternal* transport) {
1482 RTC_DCHECK(network_thread_->IsCurrent());
1483 UpdateAggregateStates_n();
1484}
1485
1486void JsepTransportController::OnTransportGatheringState_n(
1487 cricket::IceTransportInternal* transport) {
1488 RTC_DCHECK(network_thread_->IsCurrent());
1489 UpdateAggregateStates_n();
1490}
1491
1492void JsepTransportController::OnTransportCandidateGathered_n(
1493 cricket::IceTransportInternal* transport,
1494 const cricket::Candidate& candidate) {
1495 RTC_DCHECK(network_thread_->IsCurrent());
1496
1497 // We should never signal peer-reflexive candidates.
1498 if (candidate.type() == cricket::PRFLX_PORT_TYPE) {
1499 RTC_NOTREACHED();
1500 return;
1501 }
Steve Antond25828a2018-08-31 13:06:05 -07001502 std::string transport_name = transport->transport_name();
1503 invoker_.AsyncInvoke<void>(
1504 RTC_FROM_HERE, signaling_thread_, [this, transport_name, candidate] {
1505 SignalIceCandidatesGathered(transport_name, {candidate});
1506 });
Zhi Huange818b6e2018-02-22 15:26:27 -08001507}
1508
Eldar Relloda13ea22019-06-01 12:23:43 +03001509void JsepTransportController::OnTransportCandidateError_n(
1510 cricket::IceTransportInternal* transport,
1511 const cricket::IceCandidateErrorEvent& event) {
1512 RTC_DCHECK(network_thread_->IsCurrent());
1513
1514 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_,
1515 [this, event] { SignalIceCandidateError(event); });
1516}
Zhi Huange818b6e2018-02-22 15:26:27 -08001517void JsepTransportController::OnTransportCandidatesRemoved_n(
1518 cricket::IceTransportInternal* transport,
1519 const cricket::Candidates& candidates) {
1520 invoker_.AsyncInvoke<void>(
1521 RTC_FROM_HERE, signaling_thread_,
Steve Antond25828a2018-08-31 13:06:05 -07001522 [this, candidates] { SignalIceCandidatesRemoved(candidates); });
Zhi Huange818b6e2018-02-22 15:26:27 -08001523}
Alex Drake00c7ecf2019-08-06 10:54:47 -07001524void JsepTransportController::OnTransportCandidatePairChanged_n(
1525 const cricket::CandidatePairChangeEvent& event) {
1526 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_, [this, event] {
1527 SignalIceCandidatePairChanged(event);
1528 });
1529}
Zhi Huange818b6e2018-02-22 15:26:27 -08001530
1531void JsepTransportController::OnTransportRoleConflict_n(
1532 cricket::IceTransportInternal* transport) {
1533 RTC_DCHECK(network_thread_->IsCurrent());
1534 // Note: since the role conflict is handled entirely on the network thread,
1535 // we don't need to worry about role conflicts occurring on two ports at
1536 // once. The first one encountered should immediately reverse the role.
1537 cricket::IceRole reversed_role = (ice_role_ == cricket::ICEROLE_CONTROLLING)
1538 ? cricket::ICEROLE_CONTROLLED
1539 : cricket::ICEROLE_CONTROLLING;
1540 RTC_LOG(LS_INFO) << "Got role conflict; switching to "
1541 << (reversed_role == cricket::ICEROLE_CONTROLLING
1542 ? "controlling"
1543 : "controlled")
1544 << " role.";
1545 SetIceRole_n(reversed_role);
1546}
1547
1548void JsepTransportController::OnTransportStateChanged_n(
1549 cricket::IceTransportInternal* transport) {
1550 RTC_DCHECK(network_thread_->IsCurrent());
1551 RTC_LOG(LS_INFO) << transport->transport_name() << " Transport "
1552 << transport->component()
1553 << " state changed. Check if state is complete.";
1554 UpdateAggregateStates_n();
1555}
1556
Bjorn Mellem175aa2e2018-11-08 11:23:22 -08001557void JsepTransportController::OnMediaTransportStateChanged_n() {
Bjorn Mellem175aa2e2018-11-08 11:23:22 -08001558 UpdateAggregateStates_n();
1559}
1560
Bjorn A Mellemb689af42019-08-21 10:44:59 -07001561void JsepTransportController::OnDataChannelTransportNegotiated_n(
1562 cricket::JsepTransport* transport,
Bjorn A Mellembc3eebc2019-09-23 14:53:54 -07001563 DataChannelTransportInterface* data_channel_transport) {
Bjorn A Mellemb689af42019-08-21 10:44:59 -07001564 for (auto it : mid_to_transport_) {
1565 if (it.second == transport) {
1566 config_.transport_observer->OnTransportChanged(
1567 it.first, transport->rtp_transport(), transport->RtpDtlsTransport(),
Bjorn A Mellembc3eebc2019-09-23 14:53:54 -07001568 transport->media_transport(), data_channel_transport);
Bjorn A Mellemb689af42019-08-21 10:44:59 -07001569 }
1570 }
1571}
1572
Zhi Huange818b6e2018-02-22 15:26:27 -08001573void JsepTransportController::UpdateAggregateStates_n() {
1574 RTC_DCHECK(network_thread_->IsCurrent());
1575
1576 auto dtls_transports = GetDtlsTransports();
Alex Loiko9289eda2018-11-23 16:18:59 +00001577 cricket::IceConnectionState new_connection_state =
1578 cricket::kIceConnectionConnecting;
Jonas Olsson635474e2018-10-18 15:58:17 +02001579 PeerConnectionInterface::IceConnectionState new_ice_connection_state =
1580 PeerConnectionInterface::IceConnectionState::kIceConnectionNew;
1581 PeerConnectionInterface::PeerConnectionState new_combined_state =
1582 PeerConnectionInterface::PeerConnectionState::kNew;
Zhi Huange818b6e2018-02-22 15:26:27 -08001583 cricket::IceGatheringState new_gathering_state = cricket::kIceGatheringNew;
Alex Loiko9289eda2018-11-23 16:18:59 +00001584 bool any_failed = false;
1585
1586 // TODO(http://bugs.webrtc.org/9719) If(when) media_transport disables
1587 // dtls_transports entirely, the below line will have to be changed to account
1588 // for the fact that dtls transports might be absent.
1589 bool all_connected = !dtls_transports.empty();
1590 bool all_completed = !dtls_transports.empty();
Zhi Huange818b6e2018-02-22 15:26:27 -08001591 bool any_gathering = false;
1592 bool all_done_gathering = !dtls_transports.empty();
Jonas Olsson635474e2018-10-18 15:58:17 +02001593
1594 std::map<IceTransportState, int> ice_state_counts;
1595 std::map<cricket::DtlsTransportState, int> dtls_state_counts;
1596
Zhi Huange818b6e2018-02-22 15:26:27 -08001597 for (const auto& dtls : dtls_transports) {
Alex Loiko9289eda2018-11-23 16:18:59 +00001598 any_failed = any_failed || dtls->ice_transport()->GetState() ==
1599 cricket::IceTransportState::STATE_FAILED;
1600 all_connected = all_connected && dtls->writable();
1601 all_completed =
1602 all_completed && dtls->writable() &&
1603 dtls->ice_transport()->GetState() ==
1604 cricket::IceTransportState::STATE_COMPLETED &&
1605 dtls->ice_transport()->GetIceRole() == cricket::ICEROLE_CONTROLLING &&
1606 dtls->ice_transport()->gathering_state() ==
1607 cricket::kIceGatheringComplete;
Zhi Huange818b6e2018-02-22 15:26:27 -08001608 any_gathering = any_gathering || dtls->ice_transport()->gathering_state() !=
1609 cricket::kIceGatheringNew;
1610 all_done_gathering =
1611 all_done_gathering && dtls->ice_transport()->gathering_state() ==
1612 cricket::kIceGatheringComplete;
Jonas Olsson635474e2018-10-18 15:58:17 +02001613
1614 dtls_state_counts[dtls->dtls_state()]++;
1615 ice_state_counts[dtls->ice_transport()->GetIceTransportState()]++;
Zhi Huange818b6e2018-02-22 15:26:27 -08001616 }
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001617
Bjorn A Mellemfa8f4ee2019-08-16 15:47:45 -07001618 // Don't indicate that the call failed or isn't connected due to media
1619 // transport state unless the media transport is used for media. If it's only
1620 // used for data channels, it will signal those separately.
1621 if (config_.use_media_transport_for_media || config_.use_datagram_transport) {
1622 for (auto it = jsep_transports_by_name_.begin();
1623 it != jsep_transports_by_name_.end(); ++it) {
1624 auto jsep_transport = it->second.get();
1625 if (!jsep_transport->media_transport()) {
1626 continue;
1627 }
Alex Loiko9289eda2018-11-23 16:18:59 +00001628
Bjorn A Mellemfa8f4ee2019-08-16 15:47:45 -07001629 // There is no 'kIceConnectionDisconnected', so we only need to handle
1630 // connected and completed.
1631 // We treat kClosed as failed, because if it happens before shutting down
1632 // media transports it means that there was a failure.
1633 // MediaTransportInterface allows to flip back and forth between kWritable
1634 // and kPending, but there does not exist an implementation that does
1635 // that, and the contract of jsep transport controller doesn't quite
1636 // expect that. When this happens, we would go from connected to
1637 // connecting state, but this may change in future.
1638 any_failed |= jsep_transport->media_transport_state() ==
1639 webrtc::MediaTransportState::kClosed;
1640 all_completed &= jsep_transport->media_transport_state() ==
1641 webrtc::MediaTransportState::kWritable;
1642 all_connected &= jsep_transport->media_transport_state() ==
1643 webrtc::MediaTransportState::kWritable;
1644 }
Alex Loiko9289eda2018-11-23 16:18:59 +00001645 }
1646
1647 if (any_failed) {
1648 new_connection_state = cricket::kIceConnectionFailed;
1649 } else if (all_completed) {
1650 new_connection_state = cricket::kIceConnectionCompleted;
1651 } else if (all_connected) {
1652 new_connection_state = cricket::kIceConnectionConnected;
1653 }
1654 if (ice_connection_state_ != new_connection_state) {
1655 ice_connection_state_ = new_connection_state;
1656 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_,
1657 [this, new_connection_state] {
1658 SignalIceConnectionState(new_connection_state);
1659 });
1660 }
1661
Jonas Olsson635474e2018-10-18 15:58:17 +02001662 // Compute the current RTCIceConnectionState as described in
1663 // https://www.w3.org/TR/webrtc/#dom-rtciceconnectionstate.
1664 // The PeerConnection is responsible for handling the "closed" state.
1665 int total_ice_checking = ice_state_counts[IceTransportState::kChecking];
1666 int total_ice_connected = ice_state_counts[IceTransportState::kConnected];
1667 int total_ice_completed = ice_state_counts[IceTransportState::kCompleted];
1668 int total_ice_failed = ice_state_counts[IceTransportState::kFailed];
1669 int total_ice_disconnected =
1670 ice_state_counts[IceTransportState::kDisconnected];
1671 int total_ice_closed = ice_state_counts[IceTransportState::kClosed];
1672 int total_ice_new = ice_state_counts[IceTransportState::kNew];
1673 int total_ice = dtls_transports.size();
1674
1675 if (total_ice_failed > 0) {
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001676 // Any RTCIceTransports are in the "failed" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001677 new_ice_connection_state = PeerConnectionInterface::kIceConnectionFailed;
Alex Loiko9289eda2018-11-23 16:18:59 +00001678 } else if (total_ice_disconnected > 0) {
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001679 // None of the previous states apply and any RTCIceTransports are in the
1680 // "disconnected" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001681 new_ice_connection_state =
1682 PeerConnectionInterface::kIceConnectionDisconnected;
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001683 } else if (total_ice_new + total_ice_closed == total_ice) {
1684 // None of the previous states apply and all RTCIceTransports are in the
1685 // "new" or "closed" state, or there are no transports.
1686 new_ice_connection_state = PeerConnectionInterface::kIceConnectionNew;
1687 } else if (total_ice_new + total_ice_checking > 0) {
1688 // None of the previous states apply and any RTCIceTransports are in the
1689 // "new" or "checking" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001690 new_ice_connection_state = PeerConnectionInterface::kIceConnectionChecking;
Jonas Olssonacd8ae72019-02-25 15:26:24 +01001691 } else if (total_ice_completed + total_ice_closed == total_ice ||
1692 all_completed) {
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001693 // None of the previous states apply and all RTCIceTransports are in the
1694 // "completed" or "closed" state.
Jonas Olssonacd8ae72019-02-25 15:26:24 +01001695 //
1696 // TODO(https://bugs.webrtc.org/10356): The all_completed condition is added
1697 // to mimic the behavior of the old ICE connection state, and should be
1698 // removed once we get end-of-candidates signaling in place.
Jonas Olsson635474e2018-10-18 15:58:17 +02001699 new_ice_connection_state = PeerConnectionInterface::kIceConnectionCompleted;
1700 } else if (total_ice_connected + total_ice_completed + total_ice_closed ==
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001701 total_ice) {
1702 // None of the previous states apply and all RTCIceTransports are in the
1703 // "connected", "completed" or "closed" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001704 new_ice_connection_state = PeerConnectionInterface::kIceConnectionConnected;
Jonas Olsson635474e2018-10-18 15:58:17 +02001705 } else {
1706 RTC_NOTREACHED();
1707 }
1708
Alex Loiko9289eda2018-11-23 16:18:59 +00001709 if (standardized_ice_connection_state_ != new_ice_connection_state) {
Jonas Olssonacd8ae72019-02-25 15:26:24 +01001710 if (standardized_ice_connection_state_ ==
1711 PeerConnectionInterface::kIceConnectionChecking &&
1712 new_ice_connection_state ==
1713 PeerConnectionInterface::kIceConnectionCompleted) {
1714 // Ensure that we never skip over the "connected" state.
1715 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_, [this] {
1716 SignalStandardizedIceConnectionState(
1717 PeerConnectionInterface::kIceConnectionConnected);
1718 });
1719 }
Alex Loiko9289eda2018-11-23 16:18:59 +00001720 standardized_ice_connection_state_ = new_ice_connection_state;
Jonas Olsson635474e2018-10-18 15:58:17 +02001721 invoker_.AsyncInvoke<void>(
1722 RTC_FROM_HERE, signaling_thread_, [this, new_ice_connection_state] {
Alex Loiko9289eda2018-11-23 16:18:59 +00001723 SignalStandardizedIceConnectionState(new_ice_connection_state);
Jonas Olsson635474e2018-10-18 15:58:17 +02001724 });
1725 }
1726
1727 // Compute the current RTCPeerConnectionState as described in
1728 // https://www.w3.org/TR/webrtc/#dom-rtcpeerconnectionstate.
1729 // The PeerConnection is responsible for handling the "closed" state.
1730 // Note that "connecting" is only a valid state for DTLS transports while
1731 // "checking", "completed" and "disconnected" are only valid for ICE
1732 // transports.
1733 int total_connected = total_ice_connected +
1734 dtls_state_counts[cricket::DTLS_TRANSPORT_CONNECTED];
1735 int total_dtls_connecting =
1736 dtls_state_counts[cricket::DTLS_TRANSPORT_CONNECTING];
1737 int total_failed =
1738 total_ice_failed + dtls_state_counts[cricket::DTLS_TRANSPORT_FAILED];
1739 int total_closed =
1740 total_ice_closed + dtls_state_counts[cricket::DTLS_TRANSPORT_CLOSED];
1741 int total_new =
1742 total_ice_new + dtls_state_counts[cricket::DTLS_TRANSPORT_NEW];
1743 int total_transports = total_ice * 2;
1744
1745 if (total_failed > 0) {
1746 // Any of the RTCIceTransports or RTCDtlsTransports are in a "failed" state.
1747 new_combined_state = PeerConnectionInterface::PeerConnectionState::kFailed;
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001748 } else if (total_ice_disconnected > 0) {
1749 // None of the previous states apply and any RTCIceTransports or
1750 // RTCDtlsTransports are in the "disconnected" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001751 new_combined_state =
1752 PeerConnectionInterface::PeerConnectionState::kDisconnected;
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001753 } else if (total_new + total_closed == total_transports) {
1754 // None of the previous states apply and all RTCIceTransports and
1755 // RTCDtlsTransports are in the "new" or "closed" state, or there are no
1756 // transports.
1757 new_combined_state = PeerConnectionInterface::PeerConnectionState::kNew;
1758 } else if (total_new + total_dtls_connecting + total_ice_checking > 0) {
1759 // None of the previous states apply and all RTCIceTransports or
1760 // RTCDtlsTransports are in the "new", "connecting" or "checking" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001761 new_combined_state =
1762 PeerConnectionInterface::PeerConnectionState::kConnecting;
1763 } else if (total_connected + total_ice_completed + total_closed ==
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001764 total_transports) {
1765 // None of the previous states apply and all RTCIceTransports and
1766 // RTCDtlsTransports are in the "connected", "completed" or "closed" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001767 new_combined_state =
1768 PeerConnectionInterface::PeerConnectionState::kConnected;
Jonas Olsson635474e2018-10-18 15:58:17 +02001769 } else {
1770 RTC_NOTREACHED();
1771 }
1772
1773 if (combined_connection_state_ != new_combined_state) {
1774 combined_connection_state_ = new_combined_state;
1775 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_,
1776 [this, new_combined_state] {
1777 SignalConnectionState(new_combined_state);
1778 });
1779 }
1780
Zhi Huange818b6e2018-02-22 15:26:27 -08001781 if (all_done_gathering) {
1782 new_gathering_state = cricket::kIceGatheringComplete;
1783 } else if (any_gathering) {
1784 new_gathering_state = cricket::kIceGatheringGathering;
1785 }
1786 if (ice_gathering_state_ != new_gathering_state) {
1787 ice_gathering_state_ = new_gathering_state;
Steve Antond25828a2018-08-31 13:06:05 -07001788 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_,
1789 [this, new_gathering_state] {
1790 SignalIceGatheringState(new_gathering_state);
1791 });
Zhi Huange818b6e2018-02-22 15:26:27 -08001792 }
1793}
1794
Sebastian Jansson1b83a9e2019-09-18 18:22:12 +02001795void JsepTransportController::OnRtcpPacketReceived_n(
1796 rtc::CopyOnWriteBuffer* packet,
1797 int64_t packet_time_us) {
1798 RTC_DCHECK(config_.rtcp_handler);
1799 config_.rtcp_handler(*packet, packet_time_us);
1800}
1801
Zhi Huange818b6e2018-02-22 15:26:27 -08001802void JsepTransportController::OnDtlsHandshakeError(
1803 rtc::SSLHandshakeError error) {
1804 SignalDtlsHandshakeError(error);
1805}
1806
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001807absl::optional<cricket::SessionDescription::MediaTransportSetting>
1808JsepTransportController::GenerateOrGetLastMediaTransportOffer() {
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07001809 if (media_transport_created_once_) {
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001810 RTC_LOG(LS_INFO) << "Not regenerating media transport for the new offer in "
1811 "existing session.";
1812 return media_transport_offer_settings_;
1813 }
1814
1815 RTC_LOG(LS_INFO) << "Generating media transport offer!";
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001816
1817 absl::optional<std::string> transport_parameters;
1818
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001819 // Check that media transport is supposed to be used.
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001820 // Note that ICE is not available when media transport is created. It will
1821 // only be available in 'Connect'. This may be a potential server config, if
1822 // we decide to use this peer connection as a caller, not as a callee.
1823 // TODO(sukhanov): Avoid code duplication with CreateMedia/MediaTransport.
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001824 if (config_.use_media_transport_for_media ||
1825 config_.use_media_transport_for_data_channels) {
1826 RTC_DCHECK(config_.media_transport_factory != nullptr);
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001827 RTC_DCHECK(!config_.use_datagram_transport);
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001828 webrtc::MediaTransportSettings settings;
1829 settings.is_caller = true;
1830 settings.pre_shared_key = rtc::CreateRandomString(32);
Bjorn A Mellemb073f1c2019-07-02 09:50:35 -07001831 if (config_.use_media_transport_for_media) {
1832 settings.event_log = config_.event_log;
1833 }
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001834 auto media_transport_or_error =
1835 config_.media_transport_factory->CreateMediaTransport(network_thread_,
1836 settings);
1837
1838 if (media_transport_or_error.ok()) {
1839 offer_media_transport_ = std::move(media_transport_or_error.value());
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001840 transport_parameters =
1841 offer_media_transport_->GetTransportParametersOffer();
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001842 } else {
1843 RTC_LOG(LS_INFO) << "Unable to create media transport, error="
1844 << media_transport_or_error.error().message();
1845 }
1846 }
1847
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07001848 if (!offer_media_transport_) {
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001849 RTC_LOG(LS_INFO) << "Media and data transports do not exist";
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001850 return absl::nullopt;
1851 }
1852
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001853 if (!transport_parameters) {
1854 RTC_LOG(LS_INFO) << "Media transport didn't generate the offer";
1855 // Media transport didn't generate the offer, and is not supposed to be
1856 // used. Destroy the temporary media transport.
1857 offer_media_transport_ = nullptr;
1858 return absl::nullopt;
1859 }
1860
1861 cricket::SessionDescription::MediaTransportSetting setting;
1862 setting.transport_name = config_.media_transport_factory->GetTransportName();
1863 setting.transport_setting = *transport_parameters;
1864 media_transport_offer_settings_ = setting;
1865 return setting;
1866}
1867
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07001868absl::optional<cricket::OpaqueTransportParameters>
1869JsepTransportController::GetTransportParameters(const std::string& mid) {
Bjorn A Mellemb689af42019-08-21 10:44:59 -07001870 if (!(config_.use_datagram_transport ||
1871 config_.use_datagram_transport_for_data_channels)) {
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07001872 return absl::nullopt;
1873 }
1874
1875 cricket::JsepTransport* transport = GetJsepTransportForMid(mid);
1876 if (transport) {
1877 absl::optional<cricket::OpaqueTransportParameters> params =
1878 transport->GetTransportParameters();
1879 if (params) {
1880 params->protocol = config_.media_transport_factory->GetTransportName();
1881 }
1882 return params;
1883 }
1884
1885 RTC_DCHECK(!local_desc_ && !remote_desc_)
1886 << "JsepTransport should exist for every mid once any description is set";
1887
Bjorn A Mellem7da4e562019-09-26 11:02:11 -07001888 if (config_.use_datagram_transport_for_data_channels_receive_only) {
1889 return absl::nullopt;
1890 }
1891
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07001892 // Need to generate a transport for the offer.
1893 if (!offer_datagram_transport_) {
1894 webrtc::MediaTransportSettings settings;
1895 settings.is_caller = true;
1896 settings.pre_shared_key = rtc::CreateRandomString(32);
1897 settings.event_log = config_.event_log;
1898 auto datagram_transport_or_error =
1899 config_.media_transport_factory->CreateDatagramTransport(
1900 network_thread_, settings);
1901
1902 if (datagram_transport_or_error.ok()) {
1903 offer_datagram_transport_ =
1904 std::move(datagram_transport_or_error.value());
1905 } else {
1906 RTC_LOG(LS_INFO) << "Unable to create datagram transport, error="
1907 << datagram_transport_or_error.error().message();
1908 }
1909 }
1910
1911 // We have prepared a transport for the offer, and can now use its parameters.
1912 cricket::OpaqueTransportParameters params;
1913 params.parameters = offer_datagram_transport_->GetTransportParameters();
1914 params.protocol = config_.media_transport_factory->GetTransportName();
1915 return params;
1916}
1917
Zhi Huange818b6e2018-02-22 15:26:27 -08001918} // namespace webrtc