blob: c9ed4d573fabe2faad2c53d8d6efef669f1275de [file] [log] [blame]
Zhi Huange818b6e2018-02-22 15:26:27 -08001/*
2 * Copyright 2017 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Steve Anton10542f22019-01-11 09:11:00 -080011#include "pc/jsep_transport_controller.h"
Zhi Huange818b6e2018-02-22 15:26:27 -080012
Zhi Huange818b6e2018-02-22 15:26:27 -080013#include <memory>
14#include <utility>
15
Steve Anton64b626b2019-01-28 17:25:26 -080016#include "absl/algorithm/container.h"
Niels Möller65f17ca2019-09-12 13:59:36 +020017#include "api/transport/datagram_transport_interface.h"
18#include "api/transport/media/media_transport_interface.h"
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -080019#include "p2p/base/ice_transport_internal.h"
20#include "p2p/base/no_op_dtls_transport.h"
Zhi Huange818b6e2018-02-22 15:26:27 -080021#include "p2p/base/port.h"
Bjorn A Mellem364b2672019-08-20 16:58:03 -070022#include "pc/datagram_rtp_transport.h"
Steve Anton10542f22019-01-11 09:11:00 -080023#include "pc/srtp_filter.h"
Zhi Huange818b6e2018-02-22 15:26:27 -080024#include "rtc_base/bind.h"
25#include "rtc_base/checks.h"
Zhi Huange818b6e2018-02-22 15:26:27 -080026#include "rtc_base/thread.h"
27
28using webrtc::SdpType;
29
30namespace {
31
Zhi Huange818b6e2018-02-22 15:26:27 -080032webrtc::RTCError VerifyCandidate(const cricket::Candidate& cand) {
33 // No address zero.
34 if (cand.address().IsNil() || cand.address().IsAnyIP()) {
35 return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
36 "candidate has address of zero");
37 }
38
39 // Disallow all ports below 1024, except for 80 and 443 on public addresses.
40 int port = cand.address().port();
41 if (cand.protocol() == cricket::TCP_PROTOCOL_NAME &&
42 (cand.tcptype() == cricket::TCPTYPE_ACTIVE_STR || port == 0)) {
43 // Expected for active-only candidates per
44 // http://tools.ietf.org/html/rfc6544#section-4.5 so no error.
45 // Libjingle clients emit port 0, in "active" mode.
46 return webrtc::RTCError::OK();
47 }
48 if (port < 1024) {
49 if ((port != 80) && (port != 443)) {
50 return webrtc::RTCError(
51 webrtc::RTCErrorType::INVALID_PARAMETER,
52 "candidate has port below 1024, but not 80 or 443");
53 }
54
55 if (cand.address().IsPrivateIP()) {
56 return webrtc::RTCError(
57 webrtc::RTCErrorType::INVALID_PARAMETER,
58 "candidate has port of 80 or 443 with private IP address");
59 }
60 }
61
62 return webrtc::RTCError::OK();
63}
64
65webrtc::RTCError VerifyCandidates(const cricket::Candidates& candidates) {
66 for (const cricket::Candidate& candidate : candidates) {
67 webrtc::RTCError error = VerifyCandidate(candidate);
68 if (!error.ok()) {
69 return error;
70 }
71 }
72 return webrtc::RTCError::OK();
73}
74
75} // namespace
76
77namespace webrtc {
78
79JsepTransportController::JsepTransportController(
80 rtc::Thread* signaling_thread,
81 rtc::Thread* network_thread,
82 cricket::PortAllocator* port_allocator,
Zach Steine20867f2018-08-02 13:20:15 -070083 AsyncResolverFactory* async_resolver_factory,
Zhi Huange818b6e2018-02-22 15:26:27 -080084 Config config)
85 : signaling_thread_(signaling_thread),
86 network_thread_(network_thread),
87 port_allocator_(port_allocator),
Zach Steine20867f2018-08-02 13:20:15 -070088 async_resolver_factory_(async_resolver_factory),
Zhi Huang365381f2018-04-13 16:44:34 -070089 config_(config) {
90 // The |transport_observer| is assumed to be non-null.
91 RTC_DCHECK(config_.transport_observer);
Sebastian Jansson1b83a9e2019-09-18 18:22:12 +020092 RTC_DCHECK(config_.rtcp_handler);
Zhi Huang365381f2018-04-13 16:44:34 -070093}
Zhi Huange818b6e2018-02-22 15:26:27 -080094
95JsepTransportController::~JsepTransportController() {
96 // Channel destructors may try to send packets, so this needs to happen on
97 // the network thread.
98 network_thread_->Invoke<void>(
99 RTC_FROM_HERE,
100 rtc::Bind(&JsepTransportController::DestroyAllJsepTransports_n, this));
101}
102
103RTCError JsepTransportController::SetLocalDescription(
104 SdpType type,
105 const cricket::SessionDescription* description) {
106 if (!network_thread_->IsCurrent()) {
107 return network_thread_->Invoke<RTCError>(
108 RTC_FROM_HERE, [=] { return SetLocalDescription(type, description); });
109 }
110
111 if (!initial_offerer_.has_value()) {
112 initial_offerer_.emplace(type == SdpType::kOffer);
113 if (*initial_offerer_) {
114 SetIceRole_n(cricket::ICEROLE_CONTROLLING);
115 } else {
116 SetIceRole_n(cricket::ICEROLE_CONTROLLED);
117 }
118 }
119 return ApplyDescription_n(/*local=*/true, type, description);
120}
121
122RTCError JsepTransportController::SetRemoteDescription(
123 SdpType type,
124 const cricket::SessionDescription* description) {
125 if (!network_thread_->IsCurrent()) {
126 return network_thread_->Invoke<RTCError>(
127 RTC_FROM_HERE, [=] { return SetRemoteDescription(type, description); });
128 }
129
130 return ApplyDescription_n(/*local=*/false, type, description);
131}
132
133RtpTransportInternal* JsepTransportController::GetRtpTransport(
134 const std::string& mid) const {
Zhi Huange830e682018-03-30 10:48:35 -0700135 auto jsep_transport = GetJsepTransportForMid(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -0800136 if (!jsep_transport) {
137 return nullptr;
138 }
139 return jsep_transport->rtp_transport();
140}
141
Anton Sukhanov316f3ac2019-05-23 15:50:38 -0700142MediaTransportConfig JsepTransportController::GetMediaTransportConfig(
Anton Sukhanov7940da02018-10-10 10:34:49 -0700143 const std::string& mid) const {
144 auto jsep_transport = GetJsepTransportForMid(mid);
145 if (!jsep_transport) {
Anton Sukhanov316f3ac2019-05-23 15:50:38 -0700146 return MediaTransportConfig();
147 }
148
149 MediaTransportInterface* media_transport = nullptr;
150 if (config_.use_media_transport_for_media) {
151 media_transport = jsep_transport->media_transport();
152 }
153
Bjorn A Mellemb689af42019-08-21 10:44:59 -0700154 DatagramTransportInterface* datagram_transport = nullptr;
155 if (config_.use_datagram_transport) {
156 datagram_transport = jsep_transport->datagram_transport();
157 }
Anton Sukhanov316f3ac2019-05-23 15:50:38 -0700158
159 // Media transport and datagram transports can not be used together.
160 RTC_DCHECK(!media_transport || !datagram_transport);
161
162 if (media_transport) {
163 return MediaTransportConfig(media_transport);
164 } else if (datagram_transport) {
165 return MediaTransportConfig(
166 /*rtp_max_packet_size=*/datagram_transport->GetLargestDatagramSize());
167 } else {
168 return MediaTransportConfig();
169 }
170}
171
Bjorn A Mellemb689af42019-08-21 10:44:59 -0700172DataChannelTransportInterface* JsepTransportController::GetDataChannelTransport(
Anton Sukhanov316f3ac2019-05-23 15:50:38 -0700173 const std::string& mid) const {
174 auto jsep_transport = GetJsepTransportForMid(mid);
Bjorn A Mellemb689af42019-08-21 10:44:59 -0700175 if (!jsep_transport) {
Anton Sukhanov7940da02018-10-10 10:34:49 -0700176 return nullptr;
177 }
Qingsi Wang437077d2019-09-10 17:52:26 +0000178
179 if (config_.use_media_transport_for_data_channels) {
180 return jsep_transport->media_transport();
181 } else if (config_.use_datagram_transport_for_data_channels) {
182 return jsep_transport->datagram_transport();
183 }
184 // Not configured to use a data channel transport.
185 return nullptr;
Anton Sukhanov7940da02018-10-10 10:34:49 -0700186}
187
Bjorn Mellem175aa2e2018-11-08 11:23:22 -0800188MediaTransportState JsepTransportController::GetMediaTransportState(
189 const std::string& mid) const {
190 auto jsep_transport = GetJsepTransportForMid(mid);
191 if (!jsep_transport) {
192 return MediaTransportState::kPending;
193 }
194 return jsep_transport->media_transport_state();
195}
196
Zhi Huange818b6e2018-02-22 15:26:27 -0800197cricket::DtlsTransportInternal* JsepTransportController::GetDtlsTransport(
Harald Alvestrandad88c882018-11-28 16:47:46 +0100198 const std::string& mid) {
Zhi Huange830e682018-03-30 10:48:35 -0700199 auto jsep_transport = GetJsepTransportForMid(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -0800200 if (!jsep_transport) {
201 return nullptr;
202 }
203 return jsep_transport->rtp_dtls_transport();
204}
205
Harald Alvestrandad88c882018-11-28 16:47:46 +0100206const cricket::DtlsTransportInternal*
207JsepTransportController::GetRtcpDtlsTransport(const std::string& mid) const {
Zhi Huange830e682018-03-30 10:48:35 -0700208 auto jsep_transport = GetJsepTransportForMid(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -0800209 if (!jsep_transport) {
210 return nullptr;
211 }
212 return jsep_transport->rtcp_dtls_transport();
213}
214
Harald Alvestrand4a7b3ac2019-01-17 10:39:40 +0100215rtc::scoped_refptr<webrtc::DtlsTransport>
Harald Alvestrandad88c882018-11-28 16:47:46 +0100216JsepTransportController::LookupDtlsTransportByMid(const std::string& mid) {
217 auto jsep_transport = GetJsepTransportForMid(mid);
218 if (!jsep_transport) {
219 return nullptr;
220 }
221 return jsep_transport->RtpDtlsTransport();
222}
223
Zhi Huange818b6e2018-02-22 15:26:27 -0800224void JsepTransportController::SetIceConfig(const cricket::IceConfig& config) {
225 if (!network_thread_->IsCurrent()) {
226 network_thread_->Invoke<void>(RTC_FROM_HERE, [&] { SetIceConfig(config); });
227 return;
228 }
229
230 ice_config_ = config;
231 for (auto& dtls : GetDtlsTransports()) {
232 dtls->ice_transport()->SetIceConfig(ice_config_);
233 }
234}
235
236void JsepTransportController::SetNeedsIceRestartFlag() {
Zhi Huange830e682018-03-30 10:48:35 -0700237 for (auto& kv : jsep_transports_by_name_) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800238 kv.second->SetNeedsIceRestartFlag();
239 }
240}
241
242bool JsepTransportController::NeedsIceRestart(
243 const std::string& transport_name) const {
Zhi Huang365381f2018-04-13 16:44:34 -0700244 const cricket::JsepTransport* transport =
Zhi Huange830e682018-03-30 10:48:35 -0700245 GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800246 if (!transport) {
247 return false;
248 }
249 return transport->needs_ice_restart();
250}
251
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200252absl::optional<rtc::SSLRole> JsepTransportController::GetDtlsRole(
Zhi Huange830e682018-03-30 10:48:35 -0700253 const std::string& mid) const {
Zhi Huange818b6e2018-02-22 15:26:27 -0800254 if (!network_thread_->IsCurrent()) {
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200255 return network_thread_->Invoke<absl::optional<rtc::SSLRole>>(
Zhi Huange830e682018-03-30 10:48:35 -0700256 RTC_FROM_HERE, [&] { return GetDtlsRole(mid); });
Zhi Huange818b6e2018-02-22 15:26:27 -0800257 }
258
Zhi Huang365381f2018-04-13 16:44:34 -0700259 const cricket::JsepTransport* t = GetJsepTransportForMid(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -0800260 if (!t) {
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200261 return absl::optional<rtc::SSLRole>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800262 }
263 return t->GetDtlsRole();
264}
265
266bool JsepTransportController::SetLocalCertificate(
267 const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) {
268 if (!network_thread_->IsCurrent()) {
269 return network_thread_->Invoke<bool>(
270 RTC_FROM_HERE, [&] { return SetLocalCertificate(certificate); });
271 }
272
273 // Can't change a certificate, or set a null certificate.
274 if (certificate_ || !certificate) {
275 return false;
276 }
277 certificate_ = certificate;
278
279 // Set certificate for JsepTransport, which verifies it matches the
280 // fingerprint in SDP, and DTLS transport.
281 // Fallback from DTLS to SDES is not supported.
Zhi Huange830e682018-03-30 10:48:35 -0700282 for (auto& kv : jsep_transports_by_name_) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800283 kv.second->SetLocalCertificate(certificate_);
284 }
285 for (auto& dtls : GetDtlsTransports()) {
286 bool set_cert_success = dtls->SetLocalCertificate(certificate_);
287 RTC_DCHECK(set_cert_success);
288 }
289 return true;
290}
291
292rtc::scoped_refptr<rtc::RTCCertificate>
293JsepTransportController::GetLocalCertificate(
294 const std::string& transport_name) const {
295 if (!network_thread_->IsCurrent()) {
296 return network_thread_->Invoke<rtc::scoped_refptr<rtc::RTCCertificate>>(
297 RTC_FROM_HERE, [&] { return GetLocalCertificate(transport_name); });
298 }
299
Zhi Huang365381f2018-04-13 16:44:34 -0700300 const cricket::JsepTransport* t = GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800301 if (!t) {
302 return nullptr;
303 }
304 return t->GetLocalCertificate();
305}
306
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800307std::unique_ptr<rtc::SSLCertChain>
308JsepTransportController::GetRemoteSSLCertChain(
Zhi Huange818b6e2018-02-22 15:26:27 -0800309 const std::string& transport_name) const {
310 if (!network_thread_->IsCurrent()) {
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800311 return network_thread_->Invoke<std::unique_ptr<rtc::SSLCertChain>>(
312 RTC_FROM_HERE, [&] { return GetRemoteSSLCertChain(transport_name); });
Zhi Huange818b6e2018-02-22 15:26:27 -0800313 }
314
Zhi Huange830e682018-03-30 10:48:35 -0700315 // Get the certificate from the RTP transport's DTLS handshake. Should be
316 // identical to the RTCP transport's, since they were given the same remote
Zhi Huange818b6e2018-02-22 15:26:27 -0800317 // fingerprint.
Zhi Huange830e682018-03-30 10:48:35 -0700318 auto jsep_transport = GetJsepTransportByName(transport_name);
319 if (!jsep_transport) {
320 return nullptr;
321 }
322 auto dtls = jsep_transport->rtp_dtls_transport();
Zhi Huange818b6e2018-02-22 15:26:27 -0800323 if (!dtls) {
324 return nullptr;
325 }
326
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800327 return dtls->GetRemoteSSLCertChain();
Zhi Huange818b6e2018-02-22 15:26:27 -0800328}
329
330void JsepTransportController::MaybeStartGathering() {
331 if (!network_thread_->IsCurrent()) {
332 network_thread_->Invoke<void>(RTC_FROM_HERE,
333 [&] { MaybeStartGathering(); });
334 return;
335 }
336
337 for (auto& dtls : GetDtlsTransports()) {
338 dtls->ice_transport()->MaybeStartGathering();
339 }
340}
341
342RTCError JsepTransportController::AddRemoteCandidates(
343 const std::string& transport_name,
344 const cricket::Candidates& candidates) {
345 if (!network_thread_->IsCurrent()) {
346 return network_thread_->Invoke<RTCError>(RTC_FROM_HERE, [&] {
347 return AddRemoteCandidates(transport_name, candidates);
348 });
349 }
350
351 // Verify each candidate before passing down to the transport layer.
352 RTCError error = VerifyCandidates(candidates);
353 if (!error.ok()) {
354 return error;
355 }
Zhi Huange830e682018-03-30 10:48:35 -0700356 auto jsep_transport = GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800357 if (!jsep_transport) {
Zhi Huange830e682018-03-30 10:48:35 -0700358 RTC_LOG(LS_WARNING) << "Not adding candidate because the JsepTransport "
359 "doesn't exist. Ignore it.";
360 return RTCError::OK();
Zhi Huange818b6e2018-02-22 15:26:27 -0800361 }
Zhi Huange818b6e2018-02-22 15:26:27 -0800362 return jsep_transport->AddRemoteCandidates(candidates);
363}
364
365RTCError JsepTransportController::RemoveRemoteCandidates(
366 const cricket::Candidates& candidates) {
367 if (!network_thread_->IsCurrent()) {
368 return network_thread_->Invoke<RTCError>(
369 RTC_FROM_HERE, [&] { return RemoveRemoteCandidates(candidates); });
370 }
371
372 // Verify each candidate before passing down to the transport layer.
373 RTCError error = VerifyCandidates(candidates);
374 if (!error.ok()) {
375 return error;
376 }
377
378 std::map<std::string, cricket::Candidates> candidates_by_transport_name;
379 for (const cricket::Candidate& cand : candidates) {
380 if (!cand.transport_name().empty()) {
381 candidates_by_transport_name[cand.transport_name()].push_back(cand);
382 } else {
383 RTC_LOG(LS_ERROR) << "Not removing candidate because it does not have a "
384 "transport name set: "
Qingsi Wang20232a92019-09-06 12:51:17 -0700385 << cand.ToSensitiveString();
Zhi Huange818b6e2018-02-22 15:26:27 -0800386 }
387 }
388
389 for (const auto& kv : candidates_by_transport_name) {
390 const std::string& transport_name = kv.first;
391 const cricket::Candidates& candidates = kv.second;
Zhi Huang365381f2018-04-13 16:44:34 -0700392 cricket::JsepTransport* jsep_transport =
Zhi Huange830e682018-03-30 10:48:35 -0700393 GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800394 if (!jsep_transport) {
Zhi Huange830e682018-03-30 10:48:35 -0700395 RTC_LOG(LS_WARNING)
396 << "Not removing candidate because the JsepTransport doesn't exist.";
397 continue;
Zhi Huange818b6e2018-02-22 15:26:27 -0800398 }
399 for (const cricket::Candidate& candidate : candidates) {
Harald Alvestrandad88c882018-11-28 16:47:46 +0100400 cricket::DtlsTransportInternal* dtls =
401 candidate.component() == cricket::ICE_CANDIDATE_COMPONENT_RTP
402 ? jsep_transport->rtp_dtls_transport()
403 : jsep_transport->rtcp_dtls_transport();
Zhi Huange818b6e2018-02-22 15:26:27 -0800404 if (dtls) {
405 dtls->ice_transport()->RemoveRemoteCandidate(candidate);
406 }
407 }
408 }
409 return RTCError::OK();
410}
411
412bool JsepTransportController::GetStats(const std::string& transport_name,
413 cricket::TransportStats* stats) {
414 if (!network_thread_->IsCurrent()) {
415 return network_thread_->Invoke<bool>(
416 RTC_FROM_HERE, [=] { return GetStats(transport_name, stats); });
417 }
418
Zhi Huang365381f2018-04-13 16:44:34 -0700419 cricket::JsepTransport* transport = GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800420 if (!transport) {
421 return false;
422 }
423 return transport->GetStats(stats);
424}
425
Zhi Huangb57e1692018-06-12 11:41:11 -0700426void JsepTransportController::SetActiveResetSrtpParams(
427 bool active_reset_srtp_params) {
428 if (!network_thread_->IsCurrent()) {
429 network_thread_->Invoke<void>(RTC_FROM_HERE, [=] {
430 SetActiveResetSrtpParams(active_reset_srtp_params);
431 });
432 return;
433 }
434
435 RTC_LOG(INFO)
436 << "Updating the active_reset_srtp_params for JsepTransportController: "
437 << active_reset_srtp_params;
438 config_.active_reset_srtp_params = active_reset_srtp_params;
439 for (auto& kv : jsep_transports_by_name_) {
440 kv.second->SetActiveResetSrtpParams(active_reset_srtp_params);
441 }
442}
443
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800444void JsepTransportController::SetMediaTransportSettings(
445 bool use_media_transport_for_media,
Anton Sukhanov316f3ac2019-05-23 15:50:38 -0700446 bool use_media_transport_for_data_channels,
Bjorn A Mellemb689af42019-08-21 10:44:59 -0700447 bool use_datagram_transport,
448 bool use_datagram_transport_for_data_channels) {
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800449 RTC_DCHECK(use_media_transport_for_media ==
450 config_.use_media_transport_for_media ||
Piotr (Peter) Slatala97fc11f2018-10-18 12:57:59 -0700451 jsep_transports_by_name_.empty())
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800452 << "You can only change media transport configuration before creating "
453 "the first transport.";
454
455 RTC_DCHECK(use_media_transport_for_data_channels ==
456 config_.use_media_transport_for_data_channels ||
457 jsep_transports_by_name_.empty())
458 << "You can only change media transport configuration before creating "
459 "the first transport.";
460
461 config_.use_media_transport_for_media = use_media_transport_for_media;
462 config_.use_media_transport_for_data_channels =
463 use_media_transport_for_data_channels;
Anton Sukhanov316f3ac2019-05-23 15:50:38 -0700464 config_.use_datagram_transport = use_datagram_transport;
Bjorn A Mellemb689af42019-08-21 10:44:59 -0700465 config_.use_datagram_transport_for_data_channels =
466 use_datagram_transport_for_data_channels;
Piotr (Peter) Slatala97fc11f2018-10-18 12:57:59 -0700467}
468
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800469std::unique_ptr<cricket::IceTransportInternal>
470JsepTransportController::CreateIceTransport(const std::string transport_name,
471 bool rtcp) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800472 int component = rtcp ? cricket::ICE_CANDIDATE_COMPONENT_RTCP
473 : cricket::ICE_CANDIDATE_COMPONENT_RTP;
474
Zhi Huange818b6e2018-02-22 15:26:27 -0800475 if (config_.external_transport_factory) {
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800476 return config_.external_transport_factory->CreateIceTransport(
Zhi Huange818b6e2018-02-22 15:26:27 -0800477 transport_name, component);
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800478 } else {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200479 return std::make_unique<cricket::P2PTransportChannel>(
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800480 transport_name, component, port_allocator_, async_resolver_factory_,
481 config_.event_log);
482 }
483}
484
485std::unique_ptr<cricket::DtlsTransportInternal>
486JsepTransportController::CreateDtlsTransport(
Anton Sukhanovac6c0962019-07-10 15:44:56 -0700487 const cricket::ContentInfo& content_info,
Bjorn A Mellem0c1c1b42019-05-29 17:34:13 -0700488 cricket::IceTransportInternal* ice,
Anton Sukhanov292ce4e2019-06-03 13:00:24 -0700489 DatagramTransportInterface* datagram_transport) {
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800490 RTC_DCHECK(network_thread_->IsCurrent());
491
492 std::unique_ptr<cricket::DtlsTransportInternal> dtls;
Anton Sukhanov316f3ac2019-05-23 15:50:38 -0700493
494 if (datagram_transport) {
Bjorn A Mellemb689af42019-08-21 10:44:59 -0700495 RTC_DCHECK(config_.use_datagram_transport ||
496 config_.use_datagram_transport_for_data_channels);
Anton Sukhanov316f3ac2019-05-23 15:50:38 -0700497 } else if (config_.media_transport_factory &&
498 config_.use_media_transport_for_media &&
499 config_.use_media_transport_for_data_channels) {
500 // If media transport is used for both media and data channels,
501 // then we don't need to create DTLS.
502 // Otherwise, DTLS is still created.
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200503 dtls = std::make_unique<cricket::NoOpDtlsTransport>(ice,
504 config_.crypto_options);
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800505 } else if (config_.external_transport_factory) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800506 dtls = config_.external_transport_factory->CreateDtlsTransport(
Bjorn A Mellem0c1c1b42019-05-29 17:34:13 -0700507 ice, config_.crypto_options);
Zhi Huange818b6e2018-02-22 15:26:27 -0800508 } else {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200509 dtls = std::make_unique<cricket::DtlsTransport>(ice, config_.crypto_options,
510 config_.event_log);
Zhi Huange818b6e2018-02-22 15:26:27 -0800511 }
512
513 RTC_DCHECK(dtls);
514 dtls->SetSslMaxProtocolVersion(config_.ssl_max_version);
Zhi Huange818b6e2018-02-22 15:26:27 -0800515 dtls->ice_transport()->SetIceRole(ice_role_);
516 dtls->ice_transport()->SetIceTiebreaker(ice_tiebreaker_);
517 dtls->ice_transport()->SetIceConfig(ice_config_);
518 if (certificate_) {
519 bool set_cert_success = dtls->SetLocalCertificate(certificate_);
520 RTC_DCHECK(set_cert_success);
521 }
522
523 // Connect to signals offered by the DTLS and ICE transport.
524 dtls->SignalWritableState.connect(
525 this, &JsepTransportController::OnTransportWritableState_n);
526 dtls->SignalReceivingState.connect(
527 this, &JsepTransportController::OnTransportReceivingState_n);
528 dtls->SignalDtlsHandshakeError.connect(
529 this, &JsepTransportController::OnDtlsHandshakeError);
530 dtls->ice_transport()->SignalGatheringState.connect(
531 this, &JsepTransportController::OnTransportGatheringState_n);
532 dtls->ice_transport()->SignalCandidateGathered.connect(
533 this, &JsepTransportController::OnTransportCandidateGathered_n);
Eldar Relloda13ea22019-06-01 12:23:43 +0300534 dtls->ice_transport()->SignalCandidateError.connect(
535 this, &JsepTransportController::OnTransportCandidateError_n);
Zhi Huange818b6e2018-02-22 15:26:27 -0800536 dtls->ice_transport()->SignalCandidatesRemoved.connect(
537 this, &JsepTransportController::OnTransportCandidatesRemoved_n);
538 dtls->ice_transport()->SignalRoleConflict.connect(
539 this, &JsepTransportController::OnTransportRoleConflict_n);
540 dtls->ice_transport()->SignalStateChanged.connect(
541 this, &JsepTransportController::OnTransportStateChanged_n);
Jonas Olsson7a6739e2019-01-15 16:31:55 +0100542 dtls->ice_transport()->SignalIceTransportStateChanged.connect(
543 this, &JsepTransportController::OnTransportStateChanged_n);
Alex Drake00c7ecf2019-08-06 10:54:47 -0700544 dtls->ice_transport()->SignalCandidatePairChanged.connect(
545 this, &JsepTransportController::OnTransportCandidatePairChanged_n);
Zhi Huange818b6e2018-02-22 15:26:27 -0800546 return dtls;
547}
548
549std::unique_ptr<webrtc::RtpTransport>
550JsepTransportController::CreateUnencryptedRtpTransport(
551 const std::string& transport_name,
552 rtc::PacketTransportInternal* rtp_packet_transport,
553 rtc::PacketTransportInternal* rtcp_packet_transport) {
554 RTC_DCHECK(network_thread_->IsCurrent());
Zhi Huange830e682018-03-30 10:48:35 -0700555 auto unencrypted_rtp_transport =
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200556 std::make_unique<RtpTransport>(rtcp_packet_transport == nullptr);
Zhi Huange830e682018-03-30 10:48:35 -0700557 unencrypted_rtp_transport->SetRtpPacketTransport(rtp_packet_transport);
558 if (rtcp_packet_transport) {
559 unencrypted_rtp_transport->SetRtcpPacketTransport(rtcp_packet_transport);
560 }
561 return unencrypted_rtp_transport;
Zhi Huange818b6e2018-02-22 15:26:27 -0800562}
563
564std::unique_ptr<webrtc::SrtpTransport>
565JsepTransportController::CreateSdesTransport(
566 const std::string& transport_name,
Zhi Huange830e682018-03-30 10:48:35 -0700567 cricket::DtlsTransportInternal* rtp_dtls_transport,
568 cricket::DtlsTransportInternal* rtcp_dtls_transport) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800569 RTC_DCHECK(network_thread_->IsCurrent());
Zhi Huange818b6e2018-02-22 15:26:27 -0800570 auto srtp_transport =
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200571 std::make_unique<webrtc::SrtpTransport>(rtcp_dtls_transport == nullptr);
Zhi Huange830e682018-03-30 10:48:35 -0700572 RTC_DCHECK(rtp_dtls_transport);
573 srtp_transport->SetRtpPacketTransport(rtp_dtls_transport);
574 if (rtcp_dtls_transport) {
575 srtp_transport->SetRtcpPacketTransport(rtcp_dtls_transport);
Zhi Huange818b6e2018-02-22 15:26:27 -0800576 }
577 if (config_.enable_external_auth) {
578 srtp_transport->EnableExternalAuth();
579 }
580 return srtp_transport;
581}
582
583std::unique_ptr<webrtc::DtlsSrtpTransport>
584JsepTransportController::CreateDtlsSrtpTransport(
585 const std::string& transport_name,
586 cricket::DtlsTransportInternal* rtp_dtls_transport,
587 cricket::DtlsTransportInternal* rtcp_dtls_transport) {
588 RTC_DCHECK(network_thread_->IsCurrent());
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200589 auto dtls_srtp_transport = std::make_unique<webrtc::DtlsSrtpTransport>(
Zhi Huang365381f2018-04-13 16:44:34 -0700590 rtcp_dtls_transport == nullptr);
Zhi Huang27f3bf52018-03-26 21:37:23 -0700591 if (config_.enable_external_auth) {
Zhi Huang365381f2018-04-13 16:44:34 -0700592 dtls_srtp_transport->EnableExternalAuth();
Zhi Huang27f3bf52018-03-26 21:37:23 -0700593 }
Zhi Huang97d5e5b2018-03-27 00:09:01 +0000594
Zhi Huange818b6e2018-02-22 15:26:27 -0800595 dtls_srtp_transport->SetDtlsTransports(rtp_dtls_transport,
596 rtcp_dtls_transport);
Zhi Huangb57e1692018-06-12 11:41:11 -0700597 dtls_srtp_transport->SetActiveResetSrtpParams(
598 config_.active_reset_srtp_params);
Jonas Olsson635474e2018-10-18 15:58:17 +0200599 dtls_srtp_transport->SignalDtlsStateChange.connect(
600 this, &JsepTransportController::UpdateAggregateStates_n);
Zhi Huange818b6e2018-02-22 15:26:27 -0800601 return dtls_srtp_transport;
602}
603
604std::vector<cricket::DtlsTransportInternal*>
605JsepTransportController::GetDtlsTransports() {
606 std::vector<cricket::DtlsTransportInternal*> dtls_transports;
Zhi Huange830e682018-03-30 10:48:35 -0700607 for (auto it = jsep_transports_by_name_.begin();
608 it != jsep_transports_by_name_.end(); ++it) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800609 auto jsep_transport = it->second.get();
610 RTC_DCHECK(jsep_transport);
611 if (jsep_transport->rtp_dtls_transport()) {
612 dtls_transports.push_back(jsep_transport->rtp_dtls_transport());
613 }
614
615 if (jsep_transport->rtcp_dtls_transport()) {
616 dtls_transports.push_back(jsep_transport->rtcp_dtls_transport());
617 }
618 }
619 return dtls_transports;
620}
621
Zhi Huange818b6e2018-02-22 15:26:27 -0800622RTCError JsepTransportController::ApplyDescription_n(
623 bool local,
624 SdpType type,
625 const cricket::SessionDescription* description) {
626 RTC_DCHECK(network_thread_->IsCurrent());
627 RTC_DCHECK(description);
628
629 if (local) {
630 local_desc_ = description;
631 } else {
632 remote_desc_ = description;
633 }
634
Zhi Huange830e682018-03-30 10:48:35 -0700635 RTCError error;
Zhi Huangd2248f82018-04-10 14:41:03 -0700636 error = ValidateAndMaybeUpdateBundleGroup(local, type, description);
Zhi Huange830e682018-03-30 10:48:35 -0700637 if (!error.ok()) {
638 return error;
Zhi Huange818b6e2018-02-22 15:26:27 -0800639 }
640
641 std::vector<int> merged_encrypted_extension_ids;
642 if (bundle_group_) {
643 merged_encrypted_extension_ids =
644 MergeEncryptedHeaderExtensionIdsForBundle(description);
645 }
646
647 for (const cricket::ContentInfo& content_info : description->contents()) {
648 // Don't create transports for rejected m-lines and bundled m-lines."
649 if (content_info.rejected ||
650 (IsBundled(content_info.name) && content_info.name != *bundled_mid())) {
651 continue;
652 }
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -0800653 error = MaybeCreateJsepTransport(local, content_info, *description);
Zhi Huange830e682018-03-30 10:48:35 -0700654 if (!error.ok()) {
655 return error;
656 }
Zhi Huange818b6e2018-02-22 15:26:27 -0800657 }
658
659 RTC_DCHECK(description->contents().size() ==
660 description->transport_infos().size());
661 for (size_t i = 0; i < description->contents().size(); ++i) {
662 const cricket::ContentInfo& content_info = description->contents()[i];
663 const cricket::TransportInfo& transport_info =
664 description->transport_infos()[i];
665 if (content_info.rejected) {
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700666 HandleRejectedContent(content_info, description);
Zhi Huange818b6e2018-02-22 15:26:27 -0800667 continue;
668 }
669
670 if (IsBundled(content_info.name) && content_info.name != *bundled_mid()) {
Zhi Huang365381f2018-04-13 16:44:34 -0700671 if (!HandleBundledContent(content_info)) {
672 return RTCError(RTCErrorType::INVALID_PARAMETER,
673 "Failed to process the bundled m= section.");
674 }
Zhi Huange818b6e2018-02-22 15:26:27 -0800675 continue;
676 }
677
Zhi Huange830e682018-03-30 10:48:35 -0700678 error = ValidateContent(content_info);
679 if (!error.ok()) {
680 return error;
681 }
682
Zhi Huange818b6e2018-02-22 15:26:27 -0800683 std::vector<int> extension_ids;
Taylor Brandstetter0ab56512018-04-12 10:30:48 -0700684 if (bundled_mid() && content_info.name == *bundled_mid()) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800685 extension_ids = merged_encrypted_extension_ids;
686 } else {
687 extension_ids = GetEncryptedHeaderExtensionIds(content_info);
688 }
689
Zhi Huange830e682018-03-30 10:48:35 -0700690 int rtp_abs_sendtime_extn_id =
691 GetRtpAbsSendTimeHeaderExtensionId(content_info);
692
Zhi Huang365381f2018-04-13 16:44:34 -0700693 cricket::JsepTransport* transport =
Zhi Huange830e682018-03-30 10:48:35 -0700694 GetJsepTransportForMid(content_info.name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800695 RTC_DCHECK(transport);
696
697 SetIceRole_n(DetermineIceRole(transport, transport_info, type, local));
698
Zhi Huange818b6e2018-02-22 15:26:27 -0800699 cricket::JsepTransportDescription jsep_description =
700 CreateJsepTransportDescription(content_info, transport_info,
Zhi Huange830e682018-03-30 10:48:35 -0700701 extension_ids, rtp_abs_sendtime_extn_id);
Zhi Huange818b6e2018-02-22 15:26:27 -0800702 if (local) {
703 error =
704 transport->SetLocalJsepTransportDescription(jsep_description, type);
705 } else {
706 error =
707 transport->SetRemoteJsepTransportDescription(jsep_description, type);
708 }
709
710 if (!error.ok()) {
711 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
712 "Failed to apply the description for " +
713 content_info.name + ": " + error.message());
714 }
715 }
716 return RTCError::OK();
717}
718
Zhi Huangd2248f82018-04-10 14:41:03 -0700719RTCError JsepTransportController::ValidateAndMaybeUpdateBundleGroup(
720 bool local,
721 SdpType type,
Zhi Huange830e682018-03-30 10:48:35 -0700722 const cricket::SessionDescription* description) {
723 RTC_DCHECK(description);
Zhi Huangd2248f82018-04-10 14:41:03 -0700724 const cricket::ContentGroup* new_bundle_group =
725 description->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
726
727 // The BUNDLE group containing a MID that no m= section has is invalid.
728 if (new_bundle_group) {
Mirko Bonadei739baf02019-01-27 17:29:42 +0100729 for (const auto& content_name : new_bundle_group->content_names()) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700730 if (!description->GetContentByName(content_name)) {
731 return RTCError(RTCErrorType::INVALID_PARAMETER,
732 "The BUNDLE group contains MID:" + content_name +
733 " matching no m= section.");
734 }
735 }
736 }
737
738 if (type == SdpType::kAnswer) {
739 const cricket::ContentGroup* offered_bundle_group =
740 local ? remote_desc_->GetGroupByName(cricket::GROUP_TYPE_BUNDLE)
741 : local_desc_->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
742
743 if (new_bundle_group) {
744 // The BUNDLE group in answer should be a subset of offered group.
Mirko Bonadei739baf02019-01-27 17:29:42 +0100745 for (const auto& content_name : new_bundle_group->content_names()) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700746 if (!offered_bundle_group ||
747 !offered_bundle_group->HasContentName(content_name)) {
748 return RTCError(RTCErrorType::INVALID_PARAMETER,
749 "The BUNDLE group in answer contains a MID that was "
750 "not in the offered group.");
751 }
752 }
753 }
754
755 if (bundle_group_) {
Mirko Bonadei739baf02019-01-27 17:29:42 +0100756 for (const auto& content_name : bundle_group_->content_names()) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700757 // An answer that removes m= sections from pre-negotiated BUNDLE group
758 // without rejecting it, is invalid.
759 if (!new_bundle_group ||
760 !new_bundle_group->HasContentName(content_name)) {
761 auto* content_info = description->GetContentByName(content_name);
762 if (!content_info || !content_info->rejected) {
763 return RTCError(RTCErrorType::INVALID_PARAMETER,
764 "Answer cannot remove m= section " + content_name +
765 " from already-established BUNDLE group.");
766 }
767 }
768 }
769 }
770 }
771
772 if (config_.bundle_policy ==
773 PeerConnectionInterface::kBundlePolicyMaxBundle &&
774 !description->HasGroup(cricket::GROUP_TYPE_BUNDLE)) {
775 return RTCError(RTCErrorType::INVALID_PARAMETER,
776 "max-bundle is used but no bundle group found.");
777 }
778
779 if (ShouldUpdateBundleGroup(type, description)) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700780 bundle_group_ = *new_bundle_group;
781 }
Zhi Huange830e682018-03-30 10:48:35 -0700782
783 if (!bundled_mid()) {
784 return RTCError::OK();
785 }
786
787 auto bundled_content = description->GetContentByName(*bundled_mid());
788 if (!bundled_content) {
789 return RTCError(
790 RTCErrorType::INVALID_PARAMETER,
791 "An m= section associated with the BUNDLE-tag doesn't exist.");
792 }
793
794 // If the |bundled_content| is rejected, other contents in the bundle group
795 // should be rejected.
796 if (bundled_content->rejected) {
Mirko Bonadei739baf02019-01-27 17:29:42 +0100797 for (const auto& content_name : bundle_group_->content_names()) {
Zhi Huange830e682018-03-30 10:48:35 -0700798 auto other_content = description->GetContentByName(content_name);
799 if (!other_content->rejected) {
800 return RTCError(
801 RTCErrorType::INVALID_PARAMETER,
802 "The m= section:" + content_name + " should be rejected.");
803 }
804 }
805 }
806
807 return RTCError::OK();
808}
809
810RTCError JsepTransportController::ValidateContent(
811 const cricket::ContentInfo& content_info) {
812 if (config_.rtcp_mux_policy ==
813 PeerConnectionInterface::kRtcpMuxPolicyRequire &&
814 content_info.type == cricket::MediaProtocolType::kRtp &&
815 !content_info.media_description()->rtcp_mux()) {
816 return RTCError(RTCErrorType::INVALID_PARAMETER,
817 "The m= section:" + content_info.name +
818 " is invalid. RTCP-MUX is not "
819 "enabled when it is required.");
820 }
821 return RTCError::OK();
822}
823
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700824void JsepTransportController::HandleRejectedContent(
Zhi Huangd2248f82018-04-10 14:41:03 -0700825 const cricket::ContentInfo& content_info,
826 const cricket::SessionDescription* description) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800827 // If the content is rejected, let the
828 // BaseChannel/SctpTransport change the RtpTransport/DtlsTransport first,
Zhi Huang365381f2018-04-13 16:44:34 -0700829 // then destroy the cricket::JsepTransport.
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700830 RemoveTransportForMid(content_info.name);
Zhi Huange830e682018-03-30 10:48:35 -0700831 if (content_info.name == bundled_mid()) {
Mirko Bonadei739baf02019-01-27 17:29:42 +0100832 for (const auto& content_name : bundle_group_->content_names()) {
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700833 RemoveTransportForMid(content_name);
Zhi Huange830e682018-03-30 10:48:35 -0700834 }
835 bundle_group_.reset();
836 } else if (IsBundled(content_info.name)) {
837 // Remove the rejected content from the |bundle_group_|.
Zhi Huange818b6e2018-02-22 15:26:27 -0800838 bundle_group_->RemoveContentName(content_info.name);
Zhi Huange830e682018-03-30 10:48:35 -0700839 // Reset the bundle group if nothing left.
840 if (!bundle_group_->FirstContentName()) {
841 bundle_group_.reset();
842 }
Zhi Huange818b6e2018-02-22 15:26:27 -0800843 }
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700844 MaybeDestroyJsepTransport(content_info.name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800845}
846
Zhi Huang365381f2018-04-13 16:44:34 -0700847bool JsepTransportController::HandleBundledContent(
Zhi Huange818b6e2018-02-22 15:26:27 -0800848 const cricket::ContentInfo& content_info) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700849 auto jsep_transport = GetJsepTransportByName(*bundled_mid());
850 RTC_DCHECK(jsep_transport);
Zhi Huange818b6e2018-02-22 15:26:27 -0800851 // If the content is bundled, let the
852 // BaseChannel/SctpTransport change the RtpTransport/DtlsTransport first,
Zhi Huang365381f2018-04-13 16:44:34 -0700853 // then destroy the cricket::JsepTransport.
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700854 if (SetTransportForMid(content_info.name, jsep_transport)) {
Piotr (Peter) Slatala10aeb2a2018-11-14 10:57:24 -0800855 // TODO(bugs.webrtc.org/9719) For media transport this is far from ideal,
856 // because it means that we first create media transport and start
857 // connecting it, and then we destroy it. We will need to address it before
858 // video path is enabled.
Zhi Huang365381f2018-04-13 16:44:34 -0700859 MaybeDestroyJsepTransport(content_info.name);
860 return true;
861 }
862 return false;
Zhi Huange818b6e2018-02-22 15:26:27 -0800863}
864
Zhi Huang365381f2018-04-13 16:44:34 -0700865bool JsepTransportController::SetTransportForMid(
Zhi Huangd2248f82018-04-10 14:41:03 -0700866 const std::string& mid,
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700867 cricket::JsepTransport* jsep_transport) {
Zhi Huang365381f2018-04-13 16:44:34 -0700868 RTC_DCHECK(jsep_transport);
Zhi Huangd2248f82018-04-10 14:41:03 -0700869 if (mid_to_transport_[mid] == jsep_transport) {
Zhi Huang365381f2018-04-13 16:44:34 -0700870 return true;
Zhi Huangd2248f82018-04-10 14:41:03 -0700871 }
872
873 mid_to_transport_[mid] = jsep_transport;
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700874 return config_.transport_observer->OnTransportChanged(
Harald Alvestrandc85328f2019-02-28 07:51:00 +0100875 mid, jsep_transport->rtp_transport(), jsep_transport->RtpDtlsTransport(),
Qingsi Wang437077d2019-09-10 17:52:26 +0000876 jsep_transport->media_transport(), jsep_transport->datagram_transport(),
877 NegotiationState::kInitial);
Zhi Huangd2248f82018-04-10 14:41:03 -0700878}
879
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700880void JsepTransportController::RemoveTransportForMid(const std::string& mid) {
Bjorn A Mellemb689af42019-08-21 10:44:59 -0700881 bool ret = config_.transport_observer->OnTransportChanged(
Qingsi Wang437077d2019-09-10 17:52:26 +0000882 mid, nullptr, nullptr, nullptr, nullptr, NegotiationState::kFinal);
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700883 // Calling OnTransportChanged with nullptr should always succeed, since it is
884 // only expected to fail when adding media to a transport (not removing).
885 RTC_DCHECK(ret);
Zhi Huangd2248f82018-04-10 14:41:03 -0700886 mid_to_transport_.erase(mid);
887}
888
Zhi Huange818b6e2018-02-22 15:26:27 -0800889cricket::JsepTransportDescription
890JsepTransportController::CreateJsepTransportDescription(
Harald Alvestrand1716d392019-06-03 20:35:45 +0200891 const cricket::ContentInfo& content_info,
892 const cricket::TransportInfo& transport_info,
Zhi Huange830e682018-03-30 10:48:35 -0700893 const std::vector<int>& encrypted_extension_ids,
894 int rtp_abs_sendtime_extn_id) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800895 const cricket::MediaContentDescription* content_desc =
Harald Alvestrand1716d392019-06-03 20:35:45 +0200896 content_info.media_description();
Zhi Huange818b6e2018-02-22 15:26:27 -0800897 RTC_DCHECK(content_desc);
898 bool rtcp_mux_enabled = content_info.type == cricket::MediaProtocolType::kSctp
899 ? true
900 : content_desc->rtcp_mux();
901
902 return cricket::JsepTransportDescription(
903 rtcp_mux_enabled, content_desc->cryptos(), encrypted_extension_ids,
Zhi Huange830e682018-03-30 10:48:35 -0700904 rtp_abs_sendtime_extn_id, transport_info.description);
Zhi Huange818b6e2018-02-22 15:26:27 -0800905}
906
907bool JsepTransportController::ShouldUpdateBundleGroup(
908 SdpType type,
909 const cricket::SessionDescription* description) {
910 if (config_.bundle_policy ==
911 PeerConnectionInterface::kBundlePolicyMaxBundle) {
912 return true;
913 }
914
915 if (type != SdpType::kAnswer) {
916 return false;
917 }
918
919 RTC_DCHECK(local_desc_ && remote_desc_);
920 const cricket::ContentGroup* local_bundle =
921 local_desc_->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
922 const cricket::ContentGroup* remote_bundle =
923 remote_desc_->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
924 return local_bundle && remote_bundle;
925}
926
927std::vector<int> JsepTransportController::GetEncryptedHeaderExtensionIds(
928 const cricket::ContentInfo& content_info) {
929 const cricket::MediaContentDescription* content_desc =
Harald Alvestrand1716d392019-06-03 20:35:45 +0200930 content_info.media_description();
Zhi Huange818b6e2018-02-22 15:26:27 -0800931
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700932 if (!config_.crypto_options.srtp.enable_encrypted_rtp_header_extensions) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800933 return std::vector<int>();
934 }
935
936 std::vector<int> encrypted_header_extension_ids;
Mirko Bonadei739baf02019-01-27 17:29:42 +0100937 for (const auto& extension : content_desc->rtp_header_extensions()) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800938 if (!extension.encrypt) {
939 continue;
940 }
Steve Anton64b626b2019-01-28 17:25:26 -0800941 if (!absl::c_linear_search(encrypted_header_extension_ids, extension.id)) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800942 encrypted_header_extension_ids.push_back(extension.id);
943 }
944 }
945 return encrypted_header_extension_ids;
946}
947
948std::vector<int>
949JsepTransportController::MergeEncryptedHeaderExtensionIdsForBundle(
950 const cricket::SessionDescription* description) {
951 RTC_DCHECK(description);
952 RTC_DCHECK(bundle_group_);
953
954 std::vector<int> merged_ids;
955 // Union the encrypted header IDs in the group when bundle is enabled.
956 for (const cricket::ContentInfo& content_info : description->contents()) {
957 if (bundle_group_->HasContentName(content_info.name)) {
958 std::vector<int> extension_ids =
959 GetEncryptedHeaderExtensionIds(content_info);
960 for (int id : extension_ids) {
Steve Anton64b626b2019-01-28 17:25:26 -0800961 if (!absl::c_linear_search(merged_ids, id)) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800962 merged_ids.push_back(id);
963 }
964 }
965 }
966 }
967 return merged_ids;
968}
969
Zhi Huange830e682018-03-30 10:48:35 -0700970int JsepTransportController::GetRtpAbsSendTimeHeaderExtensionId(
Zhi Huange818b6e2018-02-22 15:26:27 -0800971 const cricket::ContentInfo& content_info) {
Zhi Huange830e682018-03-30 10:48:35 -0700972 if (!config_.enable_external_auth) {
973 return -1;
Zhi Huange818b6e2018-02-22 15:26:27 -0800974 }
975
976 const cricket::MediaContentDescription* content_desc =
Harald Alvestrand1716d392019-06-03 20:35:45 +0200977 content_info.media_description();
Zhi Huange830e682018-03-30 10:48:35 -0700978
979 const webrtc::RtpExtension* send_time_extension =
980 webrtc::RtpExtension::FindHeaderExtensionByUri(
981 content_desc->rtp_header_extensions(),
982 webrtc::RtpExtension::kAbsSendTimeUri);
983 return send_time_extension ? send_time_extension->id : -1;
984}
985
Zhi Huang365381f2018-04-13 16:44:34 -0700986const cricket::JsepTransport* JsepTransportController::GetJsepTransportForMid(
Zhi Huange830e682018-03-30 10:48:35 -0700987 const std::string& mid) const {
Zhi Huangd2248f82018-04-10 14:41:03 -0700988 auto it = mid_to_transport_.find(mid);
989 return it == mid_to_transport_.end() ? nullptr : it->second;
Zhi Huange830e682018-03-30 10:48:35 -0700990}
991
Zhi Huang365381f2018-04-13 16:44:34 -0700992cricket::JsepTransport* JsepTransportController::GetJsepTransportForMid(
Zhi Huange830e682018-03-30 10:48:35 -0700993 const std::string& mid) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700994 auto it = mid_to_transport_.find(mid);
995 return it == mid_to_transport_.end() ? nullptr : it->second;
Zhi Huange830e682018-03-30 10:48:35 -0700996}
997
Zhi Huang365381f2018-04-13 16:44:34 -0700998const cricket::JsepTransport* JsepTransportController::GetJsepTransportByName(
Zhi Huange830e682018-03-30 10:48:35 -0700999 const std::string& transport_name) const {
1000 auto it = jsep_transports_by_name_.find(transport_name);
1001 return (it == jsep_transports_by_name_.end()) ? nullptr : it->second.get();
1002}
1003
Zhi Huang365381f2018-04-13 16:44:34 -07001004cricket::JsepTransport* JsepTransportController::GetJsepTransportByName(
Zhi Huange830e682018-03-30 10:48:35 -07001005 const std::string& transport_name) {
1006 auto it = jsep_transports_by_name_.find(transport_name);
1007 return (it == jsep_transports_by_name_.end()) ? nullptr : it->second.get();
1008}
1009
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001010std::unique_ptr<webrtc::MediaTransportInterface>
1011JsepTransportController::MaybeCreateMediaTransport(
1012 const cricket::ContentInfo& content_info,
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -08001013 const cricket::SessionDescription& description,
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001014 bool local) {
Piotr (Peter) Slatala63a176b2019-01-25 08:25:33 -08001015 if (config_.media_transport_factory == nullptr) {
1016 return nullptr;
1017 }
1018
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001019 if (!config_.use_media_transport_for_media &&
1020 !config_.use_media_transport_for_data_channels) {
1021 return nullptr;
1022 }
1023
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001024 // Caller (offerer) media transport.
1025 if (local) {
1026 if (offer_media_transport_) {
1027 RTC_LOG(LS_INFO) << "Offered media transport has now been activated.";
1028 return std::move(offer_media_transport_);
1029 } else {
1030 RTC_LOG(LS_INFO)
1031 << "Not returning media transport. Either SDES wasn't enabled, or "
1032 "media transport didn't return an offer earlier.";
1033 // Offer wasn't generated. Either because media transport didn't want it,
1034 // or because SDES wasn't enabled.
1035 return nullptr;
1036 }
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -07001037 }
1038
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001039 // Remote offer. If no x-mt lines, do not create media transport.
1040 if (description.MediaTransportSettings().empty()) {
Piotr (Peter) Slatala63a176b2019-01-25 08:25:33 -08001041 return nullptr;
Anton Sukhanov7940da02018-10-10 10:34:49 -07001042 }
1043
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001044 // When bundle is enabled, two JsepTransports are created, and then
1045 // the second transport is destroyed (right away).
1046 // For media transport, we don't want to create the second
1047 // media transport in the first place.
1048 RTC_LOG(LS_INFO) << "Returning new, client media transport.";
Piotr (Peter) Slatala63a176b2019-01-25 08:25:33 -08001049
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001050 RTC_DCHECK(!local)
1051 << "If media transport is used, you must call "
1052 "GenerateOrGetLastMediaTransportOffer before SetLocalDescription. You "
1053 "also "
1054 "must use kRtcpMuxPolicyRequire and kBundlePolicyMaxBundle with media "
1055 "transport.";
Piotr (Peter) Slatala63a176b2019-01-25 08:25:33 -08001056 MediaTransportSettings settings;
1057 settings.is_caller = local;
Piotr (Peter) Slatala01fe3092019-02-15 12:05:50 -08001058 if (config_.use_media_transport_for_media) {
1059 settings.event_log = config_.event_log;
1060 }
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -08001061
1062 // Assume there is only one media transport (or if more, use the first one).
1063 if (!local && !description.MediaTransportSettings().empty() &&
1064 config_.media_transport_factory->GetTransportName() ==
1065 description.MediaTransportSettings()[0].transport_name) {
1066 settings.remote_transport_parameters =
1067 description.MediaTransportSettings()[0].transport_setting;
1068 }
1069
Piotr (Peter) Slatala63a176b2019-01-25 08:25:33 -08001070 auto media_transport_result =
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001071 config_.media_transport_factory->CreateMediaTransport(network_thread_,
1072 settings);
Piotr (Peter) Slatala63a176b2019-01-25 08:25:33 -08001073
1074 // TODO(sukhanov): Proper error handling.
1075 RTC_CHECK(media_transport_result.ok());
1076
1077 return media_transport_result.MoveValue();
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001078}
1079
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001080// TODO(sukhanov): Refactor to avoid code duplication for Media and Datagram
1081// transports setup.
1082std::unique_ptr<webrtc::DatagramTransportInterface>
1083JsepTransportController::MaybeCreateDatagramTransport(
1084 const cricket::ContentInfo& content_info,
1085 const cricket::SessionDescription& description,
1086 bool local) {
1087 if (config_.media_transport_factory == nullptr) {
1088 return nullptr;
1089 }
1090
Bjorn A Mellemb689af42019-08-21 10:44:59 -07001091 if (!(config_.use_datagram_transport ||
1092 config_.use_datagram_transport_for_data_channels)) {
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001093 return nullptr;
1094 }
1095
1096 // Caller (offerer) datagram transport.
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07001097 if (offer_datagram_transport_) {
1098 RTC_DCHECK(local);
1099 RTC_LOG(LS_INFO) << "Offered datagram transport has now been activated.";
1100 return std::move(offer_datagram_transport_);
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001101 }
1102
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07001103 const cricket::TransportDescription* transport_description =
1104 description.GetTransportDescriptionByName(content_info.mid());
1105 RTC_DCHECK(transport_description)
1106 << "Missing transport description for mid=" << content_info.mid();
1107
1108 if (!transport_description->opaque_parameters) {
1109 RTC_LOG(LS_INFO)
1110 << "No opaque transport parameters, not creating datagram transport";
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001111 return nullptr;
1112 }
1113
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07001114 if (transport_description->opaque_parameters->protocol !=
1115 config_.media_transport_factory->GetTransportName()) {
1116 RTC_LOG(LS_INFO) << "Opaque transport parameters for protocol="
1117 << transport_description->opaque_parameters->protocol
1118 << ", which does not match supported protocol="
1119 << config_.media_transport_factory->GetTransportName();
1120 return nullptr;
1121 }
1122
1123 RTC_DCHECK(!local);
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001124 // When bundle is enabled, two JsepTransports are created, and then
1125 // the second transport is destroyed (right away).
1126 // For datagram transport, we don't want to create the second
1127 // datagram transport in the first place.
1128 RTC_LOG(LS_INFO) << "Returning new, client datagram transport.";
1129
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001130 MediaTransportSettings settings;
1131 settings.is_caller = local;
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07001132 settings.remote_transport_parameters =
1133 transport_description->opaque_parameters->parameters;
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001134 settings.event_log = config_.event_log;
1135
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001136 auto datagram_transport_result =
1137 config_.media_transport_factory->CreateDatagramTransport(network_thread_,
1138 settings);
1139
1140 // TODO(sukhanov): Proper error handling.
1141 RTC_CHECK(datagram_transport_result.ok());
1142
1143 return datagram_transport_result.MoveValue();
1144}
1145
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001146RTCError JsepTransportController::MaybeCreateJsepTransport(
1147 bool local,
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -08001148 const cricket::ContentInfo& content_info,
1149 const cricket::SessionDescription& description) {
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001150 RTC_DCHECK(network_thread_->IsCurrent());
1151 cricket::JsepTransport* transport = GetJsepTransportByName(content_info.name);
1152 if (transport) {
1153 return RTCError::OK();
1154 }
1155
1156 const cricket::MediaContentDescription* content_desc =
Harald Alvestrand1716d392019-06-03 20:35:45 +02001157 content_info.media_description();
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001158 if (certificate_ && !content_desc->cryptos().empty()) {
1159 return RTCError(RTCErrorType::INVALID_PARAMETER,
1160 "SDES and DTLS-SRTP cannot be enabled at the same time.");
1161 }
1162
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001163 std::unique_ptr<cricket::IceTransportInternal> ice =
1164 CreateIceTransport(content_info.name, /*rtcp=*/false);
1165
1166 std::unique_ptr<MediaTransportInterface> media_transport =
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001167 MaybeCreateMediaTransport(content_info, description, local);
1168 if (media_transport) {
1169 media_transport_created_once_ = true;
1170 media_transport->Connect(ice.get());
1171 }
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001172
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001173 std::unique_ptr<DatagramTransportInterface> datagram_transport =
1174 MaybeCreateDatagramTransport(content_info, description, local);
1175 if (datagram_transport) {
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001176 datagram_transport->Connect(ice.get());
1177 }
1178
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001179 std::unique_ptr<cricket::DtlsTransportInternal> rtp_dtls_transport =
Anton Sukhanovac6c0962019-07-10 15:44:56 -07001180 CreateDtlsTransport(content_info, ice.get(), nullptr);
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001181
1182 std::unique_ptr<cricket::DtlsTransportInternal> rtcp_dtls_transport;
1183 std::unique_ptr<RtpTransport> unencrypted_rtp_transport;
1184 std::unique_ptr<SrtpTransport> sdes_transport;
1185 std::unique_ptr<DtlsSrtpTransport> dtls_srtp_transport;
Bjorn A Mellem364b2672019-08-20 16:58:03 -07001186 std::unique_ptr<RtpTransportInternal> datagram_rtp_transport;
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001187
Bjorn A Mellem0c1c1b42019-05-29 17:34:13 -07001188 std::unique_ptr<cricket::IceTransportInternal> rtcp_ice;
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001189 if (config_.rtcp_mux_policy !=
1190 PeerConnectionInterface::kRtcpMuxPolicyRequire &&
1191 content_info.type == cricket::MediaProtocolType::kRtp) {
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001192 RTC_DCHECK(media_transport == nullptr);
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001193 RTC_DCHECK(datagram_transport == nullptr);
Bjorn A Mellem0c1c1b42019-05-29 17:34:13 -07001194 rtcp_ice = CreateIceTransport(content_info.name, /*rtcp=*/true);
Anton Sukhanovac6c0962019-07-10 15:44:56 -07001195 rtcp_dtls_transport = CreateDtlsTransport(content_info, rtcp_ice.get(),
Bjorn A Mellem0c1c1b42019-05-29 17:34:13 -07001196 /*datagram_transport=*/nullptr);
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001197 }
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001198
Bjorn A Mellem703ea952019-08-23 10:31:11 -07001199 // Only create a datagram RTP transport if the datagram transport should be
1200 // used for RTP.
1201 if (datagram_transport && config_.use_datagram_transport) {
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001202 // TODO(sukhanov): We use unencrypted RTP transport over DatagramTransport,
1203 // because MediaTransport encrypts. In the future we may want to
1204 // implement our own version of RtpTransport over MediaTransport, because
1205 // it will give us more control over things like:
1206 // - Fusing
1207 // - Rtp header compression
1208 // - Handling Rtcp feedback.
1209 RTC_LOG(LS_INFO) << "Creating UnencryptedRtpTransport, because datagram "
1210 "transport is used.";
1211 RTC_DCHECK(!rtcp_dtls_transport);
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001212 datagram_rtp_transport = std::make_unique<DatagramRtpTransport>(
Bjorn A Mellem364b2672019-08-20 16:58:03 -07001213 content_info.media_description()->rtp_header_extensions(), ice.get(),
1214 datagram_transport.get());
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07001215 }
1216
1217 if (config_.disable_encryption) {
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001218 RTC_LOG(LS_INFO)
1219 << "Creating UnencryptedRtpTransport, becayse encryption is disabled.";
Zhi Huange818b6e2018-02-22 15:26:27 -08001220 unencrypted_rtp_transport = CreateUnencryptedRtpTransport(
Zhi Huangd2248f82018-04-10 14:41:03 -07001221 content_info.name, rtp_dtls_transport.get(), rtcp_dtls_transport.get());
Zhi Huange818b6e2018-02-22 15:26:27 -08001222 } else if (!content_desc->cryptos().empty()) {
Zhi Huangd2248f82018-04-10 14:41:03 -07001223 sdes_transport = CreateSdesTransport(
1224 content_info.name, rtp_dtls_transport.get(), rtcp_dtls_transport.get());
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001225 RTC_LOG(LS_INFO) << "Creating SdesTransport.";
Zhi Huange818b6e2018-02-22 15:26:27 -08001226 } else {
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001227 RTC_LOG(LS_INFO) << "Creating DtlsSrtpTransport.";
Zhi Huangd2248f82018-04-10 14:41:03 -07001228 dtls_srtp_transport = CreateDtlsSrtpTransport(
1229 content_info.name, rtp_dtls_transport.get(), rtcp_dtls_transport.get());
Zhi Huange818b6e2018-02-22 15:26:27 -08001230 }
1231
Zhi Huang365381f2018-04-13 16:44:34 -07001232 std::unique_ptr<cricket::JsepTransport> jsep_transport =
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001233 std::make_unique<cricket::JsepTransport>(
Bjorn A Mellem0c1c1b42019-05-29 17:34:13 -07001234 content_info.name, certificate_, std::move(ice), std::move(rtcp_ice),
1235 std::move(unencrypted_rtp_transport), std::move(sdes_transport),
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07001236 std::move(dtls_srtp_transport), std::move(datagram_rtp_transport),
1237 std::move(rtp_dtls_transport), std::move(rtcp_dtls_transport),
Qingsi Wang437077d2019-09-10 17:52:26 +00001238 std::move(media_transport), std::move(datagram_transport));
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001239
Sebastian Jansson1b83a9e2019-09-18 18:22:12 +02001240 jsep_transport->rtp_transport()->SignalRtcpPacketReceived.connect(
1241 this, &JsepTransportController::OnRtcpPacketReceived_n);
1242
Zhi Huange818b6e2018-02-22 15:26:27 -08001243 jsep_transport->SignalRtcpMuxActive.connect(
1244 this, &JsepTransportController::UpdateAggregateStates_n);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001245 jsep_transport->SignalMediaTransportStateChanged.connect(
Bjorn Mellem175aa2e2018-11-08 11:23:22 -08001246 this, &JsepTransportController::OnMediaTransportStateChanged_n);
Bjorn A Mellemb689af42019-08-21 10:44:59 -07001247 jsep_transport->SignalDataChannelTransportNegotiated.connect(
1248 this, &JsepTransportController::OnDataChannelTransportNegotiated_n);
Taylor Brandstettercbaa2542018-04-16 16:42:14 -07001249 SetTransportForMid(content_info.name, jsep_transport.get());
Zhi Huange830e682018-03-30 10:48:35 -07001250
Zhi Huangd2248f82018-04-10 14:41:03 -07001251 jsep_transports_by_name_[content_info.name] = std::move(jsep_transport);
1252 UpdateAggregateStates_n();
Zhi Huange830e682018-03-30 10:48:35 -07001253 return RTCError::OK();
Zhi Huange818b6e2018-02-22 15:26:27 -08001254}
1255
1256void JsepTransportController::MaybeDestroyJsepTransport(
1257 const std::string& mid) {
Zhi Huangd2248f82018-04-10 14:41:03 -07001258 auto jsep_transport = GetJsepTransportByName(mid);
1259 if (!jsep_transport) {
1260 return;
1261 }
1262
1263 // Don't destroy the JsepTransport if there are still media sections referring
1264 // to it.
1265 for (const auto& kv : mid_to_transport_) {
1266 if (kv.second == jsep_transport) {
1267 return;
1268 }
1269 }
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -08001270
Zhi Huange830e682018-03-30 10:48:35 -07001271 jsep_transports_by_name_.erase(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -08001272 UpdateAggregateStates_n();
1273}
1274
1275void JsepTransportController::DestroyAllJsepTransports_n() {
1276 RTC_DCHECK(network_thread_->IsCurrent());
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -08001277
1278 for (const auto& jsep_transport : jsep_transports_by_name_) {
Bjorn A Mellemb689af42019-08-21 10:44:59 -07001279 config_.transport_observer->OnTransportChanged(
Qingsi Wang437077d2019-09-10 17:52:26 +00001280 jsep_transport.first, nullptr, nullptr, nullptr, nullptr,
1281 NegotiationState::kFinal);
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -08001282 }
1283
Zhi Huange830e682018-03-30 10:48:35 -07001284 jsep_transports_by_name_.clear();
Zhi Huange818b6e2018-02-22 15:26:27 -08001285}
1286
1287void JsepTransportController::SetIceRole_n(cricket::IceRole ice_role) {
1288 RTC_DCHECK(network_thread_->IsCurrent());
1289
1290 ice_role_ = ice_role;
1291 for (auto& dtls : GetDtlsTransports()) {
1292 dtls->ice_transport()->SetIceRole(ice_role_);
1293 }
1294}
1295
1296cricket::IceRole JsepTransportController::DetermineIceRole(
Zhi Huang365381f2018-04-13 16:44:34 -07001297 cricket::JsepTransport* jsep_transport,
Zhi Huange818b6e2018-02-22 15:26:27 -08001298 const cricket::TransportInfo& transport_info,
1299 SdpType type,
1300 bool local) {
1301 cricket::IceRole ice_role = ice_role_;
1302 auto tdesc = transport_info.description;
1303 if (local) {
1304 // The initial offer side may use ICE Lite, in which case, per RFC5245
1305 // Section 5.1.1, the answer side should take the controlling role if it is
1306 // in the full ICE mode.
1307 //
1308 // When both sides use ICE Lite, the initial offer side must take the
1309 // controlling role, and this is the default logic implemented in
1310 // SetLocalDescription in JsepTransportController.
1311 if (jsep_transport->remote_description() &&
1312 jsep_transport->remote_description()->transport_desc.ice_mode ==
1313 cricket::ICEMODE_LITE &&
1314 ice_role_ == cricket::ICEROLE_CONTROLLED &&
1315 tdesc.ice_mode == cricket::ICEMODE_FULL) {
1316 ice_role = cricket::ICEROLE_CONTROLLING;
1317 }
1318
1319 // Older versions of Chrome expect the ICE role to be re-determined when an
1320 // ICE restart occurs, and also don't perform conflict resolution correctly,
1321 // so for now we can't safely stop doing this, unless the application opts
1322 // in by setting |config_.redetermine_role_on_ice_restart_| to false. See:
1323 // https://bugs.chromium.org/p/chromium/issues/detail?id=628676
1324 // TODO(deadbeef): Remove this when these old versions of Chrome reach a low
1325 // enough population.
1326 if (config_.redetermine_role_on_ice_restart &&
1327 jsep_transport->local_description() &&
1328 cricket::IceCredentialsChanged(
1329 jsep_transport->local_description()->transport_desc.ice_ufrag,
1330 jsep_transport->local_description()->transport_desc.ice_pwd,
1331 tdesc.ice_ufrag, tdesc.ice_pwd) &&
1332 // Don't change the ICE role if the remote endpoint is ICE lite; we
1333 // should always be controlling in that case.
1334 (!jsep_transport->remote_description() ||
1335 jsep_transport->remote_description()->transport_desc.ice_mode !=
1336 cricket::ICEMODE_LITE)) {
1337 ice_role = (type == SdpType::kOffer) ? cricket::ICEROLE_CONTROLLING
1338 : cricket::ICEROLE_CONTROLLED;
1339 }
1340 } else {
1341 // If our role is cricket::ICEROLE_CONTROLLED and the remote endpoint
1342 // supports only ice_lite, this local endpoint should take the CONTROLLING
1343 // role.
1344 // TODO(deadbeef): This is a session-level attribute, so it really shouldn't
1345 // be in a TransportDescription in the first place...
1346 if (ice_role_ == cricket::ICEROLE_CONTROLLED &&
1347 tdesc.ice_mode == cricket::ICEMODE_LITE) {
1348 ice_role = cricket::ICEROLE_CONTROLLING;
1349 }
1350
1351 // If we use ICE Lite and the remote endpoint uses the full implementation
1352 // of ICE, the local endpoint must take the controlled role, and the other
1353 // side must be the controlling role.
1354 if (jsep_transport->local_description() &&
1355 jsep_transport->local_description()->transport_desc.ice_mode ==
1356 cricket::ICEMODE_LITE &&
1357 ice_role_ == cricket::ICEROLE_CONTROLLING &&
Zhi Huange830e682018-03-30 10:48:35 -07001358 tdesc.ice_mode == cricket::ICEMODE_FULL) {
Zhi Huange818b6e2018-02-22 15:26:27 -08001359 ice_role = cricket::ICEROLE_CONTROLLED;
1360 }
1361 }
1362
1363 return ice_role;
1364}
1365
1366void JsepTransportController::OnTransportWritableState_n(
1367 rtc::PacketTransportInternal* transport) {
1368 RTC_DCHECK(network_thread_->IsCurrent());
1369 RTC_LOG(LS_INFO) << " Transport " << transport->transport_name()
1370 << " writability changed to " << transport->writable()
1371 << ".";
1372 UpdateAggregateStates_n();
1373}
1374
1375void JsepTransportController::OnTransportReceivingState_n(
1376 rtc::PacketTransportInternal* transport) {
1377 RTC_DCHECK(network_thread_->IsCurrent());
1378 UpdateAggregateStates_n();
1379}
1380
1381void JsepTransportController::OnTransportGatheringState_n(
1382 cricket::IceTransportInternal* transport) {
1383 RTC_DCHECK(network_thread_->IsCurrent());
1384 UpdateAggregateStates_n();
1385}
1386
1387void JsepTransportController::OnTransportCandidateGathered_n(
1388 cricket::IceTransportInternal* transport,
1389 const cricket::Candidate& candidate) {
1390 RTC_DCHECK(network_thread_->IsCurrent());
1391
1392 // We should never signal peer-reflexive candidates.
1393 if (candidate.type() == cricket::PRFLX_PORT_TYPE) {
1394 RTC_NOTREACHED();
1395 return;
1396 }
Steve Antond25828a2018-08-31 13:06:05 -07001397 std::string transport_name = transport->transport_name();
1398 invoker_.AsyncInvoke<void>(
1399 RTC_FROM_HERE, signaling_thread_, [this, transport_name, candidate] {
1400 SignalIceCandidatesGathered(transport_name, {candidate});
1401 });
Zhi Huange818b6e2018-02-22 15:26:27 -08001402}
1403
Eldar Relloda13ea22019-06-01 12:23:43 +03001404void JsepTransportController::OnTransportCandidateError_n(
1405 cricket::IceTransportInternal* transport,
1406 const cricket::IceCandidateErrorEvent& event) {
1407 RTC_DCHECK(network_thread_->IsCurrent());
1408
1409 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_,
1410 [this, event] { SignalIceCandidateError(event); });
1411}
Zhi Huange818b6e2018-02-22 15:26:27 -08001412void JsepTransportController::OnTransportCandidatesRemoved_n(
1413 cricket::IceTransportInternal* transport,
1414 const cricket::Candidates& candidates) {
1415 invoker_.AsyncInvoke<void>(
1416 RTC_FROM_HERE, signaling_thread_,
Steve Antond25828a2018-08-31 13:06:05 -07001417 [this, candidates] { SignalIceCandidatesRemoved(candidates); });
Zhi Huange818b6e2018-02-22 15:26:27 -08001418}
Alex Drake00c7ecf2019-08-06 10:54:47 -07001419void JsepTransportController::OnTransportCandidatePairChanged_n(
1420 const cricket::CandidatePairChangeEvent& event) {
1421 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_, [this, event] {
1422 SignalIceCandidatePairChanged(event);
1423 });
1424}
Zhi Huange818b6e2018-02-22 15:26:27 -08001425
1426void JsepTransportController::OnTransportRoleConflict_n(
1427 cricket::IceTransportInternal* transport) {
1428 RTC_DCHECK(network_thread_->IsCurrent());
1429 // Note: since the role conflict is handled entirely on the network thread,
1430 // we don't need to worry about role conflicts occurring on two ports at
1431 // once. The first one encountered should immediately reverse the role.
1432 cricket::IceRole reversed_role = (ice_role_ == cricket::ICEROLE_CONTROLLING)
1433 ? cricket::ICEROLE_CONTROLLED
1434 : cricket::ICEROLE_CONTROLLING;
1435 RTC_LOG(LS_INFO) << "Got role conflict; switching to "
1436 << (reversed_role == cricket::ICEROLE_CONTROLLING
1437 ? "controlling"
1438 : "controlled")
1439 << " role.";
1440 SetIceRole_n(reversed_role);
1441}
1442
1443void JsepTransportController::OnTransportStateChanged_n(
1444 cricket::IceTransportInternal* transport) {
1445 RTC_DCHECK(network_thread_->IsCurrent());
1446 RTC_LOG(LS_INFO) << transport->transport_name() << " Transport "
1447 << transport->component()
1448 << " state changed. Check if state is complete.";
1449 UpdateAggregateStates_n();
1450}
1451
Bjorn Mellem175aa2e2018-11-08 11:23:22 -08001452void JsepTransportController::OnMediaTransportStateChanged_n() {
Bjorn Mellem175aa2e2018-11-08 11:23:22 -08001453 UpdateAggregateStates_n();
1454}
1455
Bjorn A Mellemb689af42019-08-21 10:44:59 -07001456void JsepTransportController::OnDataChannelTransportNegotiated_n(
1457 cricket::JsepTransport* transport,
Qingsi Wang437077d2019-09-10 17:52:26 +00001458 DataChannelTransportInterface* data_channel_transport,
1459 bool provisional) {
Bjorn A Mellemb689af42019-08-21 10:44:59 -07001460 for (auto it : mid_to_transport_) {
1461 if (it.second == transport) {
1462 config_.transport_observer->OnTransportChanged(
1463 it.first, transport->rtp_transport(), transport->RtpDtlsTransport(),
Qingsi Wang437077d2019-09-10 17:52:26 +00001464 transport->media_transport(), data_channel_transport,
1465 provisional ? NegotiationState::kProvisional
1466 : NegotiationState::kFinal);
Bjorn A Mellemb689af42019-08-21 10:44:59 -07001467 }
1468 }
1469}
1470
Zhi Huange818b6e2018-02-22 15:26:27 -08001471void JsepTransportController::UpdateAggregateStates_n() {
1472 RTC_DCHECK(network_thread_->IsCurrent());
1473
1474 auto dtls_transports = GetDtlsTransports();
Alex Loiko9289eda2018-11-23 16:18:59 +00001475 cricket::IceConnectionState new_connection_state =
1476 cricket::kIceConnectionConnecting;
Jonas Olsson635474e2018-10-18 15:58:17 +02001477 PeerConnectionInterface::IceConnectionState new_ice_connection_state =
1478 PeerConnectionInterface::IceConnectionState::kIceConnectionNew;
1479 PeerConnectionInterface::PeerConnectionState new_combined_state =
1480 PeerConnectionInterface::PeerConnectionState::kNew;
Zhi Huange818b6e2018-02-22 15:26:27 -08001481 cricket::IceGatheringState new_gathering_state = cricket::kIceGatheringNew;
Alex Loiko9289eda2018-11-23 16:18:59 +00001482 bool any_failed = false;
1483
1484 // TODO(http://bugs.webrtc.org/9719) If(when) media_transport disables
1485 // dtls_transports entirely, the below line will have to be changed to account
1486 // for the fact that dtls transports might be absent.
1487 bool all_connected = !dtls_transports.empty();
1488 bool all_completed = !dtls_transports.empty();
Zhi Huange818b6e2018-02-22 15:26:27 -08001489 bool any_gathering = false;
1490 bool all_done_gathering = !dtls_transports.empty();
Jonas Olsson635474e2018-10-18 15:58:17 +02001491
1492 std::map<IceTransportState, int> ice_state_counts;
1493 std::map<cricket::DtlsTransportState, int> dtls_state_counts;
1494
Zhi Huange818b6e2018-02-22 15:26:27 -08001495 for (const auto& dtls : dtls_transports) {
Alex Loiko9289eda2018-11-23 16:18:59 +00001496 any_failed = any_failed || dtls->ice_transport()->GetState() ==
1497 cricket::IceTransportState::STATE_FAILED;
1498 all_connected = all_connected && dtls->writable();
1499 all_completed =
1500 all_completed && dtls->writable() &&
1501 dtls->ice_transport()->GetState() ==
1502 cricket::IceTransportState::STATE_COMPLETED &&
1503 dtls->ice_transport()->GetIceRole() == cricket::ICEROLE_CONTROLLING &&
1504 dtls->ice_transport()->gathering_state() ==
1505 cricket::kIceGatheringComplete;
Zhi Huange818b6e2018-02-22 15:26:27 -08001506 any_gathering = any_gathering || dtls->ice_transport()->gathering_state() !=
1507 cricket::kIceGatheringNew;
1508 all_done_gathering =
1509 all_done_gathering && dtls->ice_transport()->gathering_state() ==
1510 cricket::kIceGatheringComplete;
Jonas Olsson635474e2018-10-18 15:58:17 +02001511
1512 dtls_state_counts[dtls->dtls_state()]++;
1513 ice_state_counts[dtls->ice_transport()->GetIceTransportState()]++;
Zhi Huange818b6e2018-02-22 15:26:27 -08001514 }
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001515
Bjorn A Mellemfa8f4ee2019-08-16 15:47:45 -07001516 // Don't indicate that the call failed or isn't connected due to media
1517 // transport state unless the media transport is used for media. If it's only
1518 // used for data channels, it will signal those separately.
1519 if (config_.use_media_transport_for_media || config_.use_datagram_transport) {
1520 for (auto it = jsep_transports_by_name_.begin();
1521 it != jsep_transports_by_name_.end(); ++it) {
1522 auto jsep_transport = it->second.get();
1523 if (!jsep_transport->media_transport()) {
1524 continue;
1525 }
Alex Loiko9289eda2018-11-23 16:18:59 +00001526
Bjorn A Mellemfa8f4ee2019-08-16 15:47:45 -07001527 // There is no 'kIceConnectionDisconnected', so we only need to handle
1528 // connected and completed.
1529 // We treat kClosed as failed, because if it happens before shutting down
1530 // media transports it means that there was a failure.
1531 // MediaTransportInterface allows to flip back and forth between kWritable
1532 // and kPending, but there does not exist an implementation that does
1533 // that, and the contract of jsep transport controller doesn't quite
1534 // expect that. When this happens, we would go from connected to
1535 // connecting state, but this may change in future.
1536 any_failed |= jsep_transport->media_transport_state() ==
1537 webrtc::MediaTransportState::kClosed;
1538 all_completed &= jsep_transport->media_transport_state() ==
1539 webrtc::MediaTransportState::kWritable;
1540 all_connected &= jsep_transport->media_transport_state() ==
1541 webrtc::MediaTransportState::kWritable;
1542 }
Alex Loiko9289eda2018-11-23 16:18:59 +00001543 }
1544
1545 if (any_failed) {
1546 new_connection_state = cricket::kIceConnectionFailed;
1547 } else if (all_completed) {
1548 new_connection_state = cricket::kIceConnectionCompleted;
1549 } else if (all_connected) {
1550 new_connection_state = cricket::kIceConnectionConnected;
1551 }
1552 if (ice_connection_state_ != new_connection_state) {
1553 ice_connection_state_ = new_connection_state;
1554 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_,
1555 [this, new_connection_state] {
1556 SignalIceConnectionState(new_connection_state);
1557 });
1558 }
1559
Jonas Olsson635474e2018-10-18 15:58:17 +02001560 // Compute the current RTCIceConnectionState as described in
1561 // https://www.w3.org/TR/webrtc/#dom-rtciceconnectionstate.
1562 // The PeerConnection is responsible for handling the "closed" state.
1563 int total_ice_checking = ice_state_counts[IceTransportState::kChecking];
1564 int total_ice_connected = ice_state_counts[IceTransportState::kConnected];
1565 int total_ice_completed = ice_state_counts[IceTransportState::kCompleted];
1566 int total_ice_failed = ice_state_counts[IceTransportState::kFailed];
1567 int total_ice_disconnected =
1568 ice_state_counts[IceTransportState::kDisconnected];
1569 int total_ice_closed = ice_state_counts[IceTransportState::kClosed];
1570 int total_ice_new = ice_state_counts[IceTransportState::kNew];
1571 int total_ice = dtls_transports.size();
1572
1573 if (total_ice_failed > 0) {
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001574 // Any RTCIceTransports are in the "failed" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001575 new_ice_connection_state = PeerConnectionInterface::kIceConnectionFailed;
Alex Loiko9289eda2018-11-23 16:18:59 +00001576 } else if (total_ice_disconnected > 0) {
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001577 // None of the previous states apply and any RTCIceTransports are in the
1578 // "disconnected" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001579 new_ice_connection_state =
1580 PeerConnectionInterface::kIceConnectionDisconnected;
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001581 } else if (total_ice_new + total_ice_closed == total_ice) {
1582 // None of the previous states apply and all RTCIceTransports are in the
1583 // "new" or "closed" state, or there are no transports.
1584 new_ice_connection_state = PeerConnectionInterface::kIceConnectionNew;
1585 } else if (total_ice_new + total_ice_checking > 0) {
1586 // None of the previous states apply and any RTCIceTransports are in the
1587 // "new" or "checking" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001588 new_ice_connection_state = PeerConnectionInterface::kIceConnectionChecking;
Jonas Olssonacd8ae72019-02-25 15:26:24 +01001589 } else if (total_ice_completed + total_ice_closed == total_ice ||
1590 all_completed) {
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001591 // None of the previous states apply and all RTCIceTransports are in the
1592 // "completed" or "closed" state.
Jonas Olssonacd8ae72019-02-25 15:26:24 +01001593 //
1594 // TODO(https://bugs.webrtc.org/10356): The all_completed condition is added
1595 // to mimic the behavior of the old ICE connection state, and should be
1596 // removed once we get end-of-candidates signaling in place.
Jonas Olsson635474e2018-10-18 15:58:17 +02001597 new_ice_connection_state = PeerConnectionInterface::kIceConnectionCompleted;
1598 } else if (total_ice_connected + total_ice_completed + total_ice_closed ==
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001599 total_ice) {
1600 // None of the previous states apply and all RTCIceTransports are in the
1601 // "connected", "completed" or "closed" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001602 new_ice_connection_state = PeerConnectionInterface::kIceConnectionConnected;
Jonas Olsson635474e2018-10-18 15:58:17 +02001603 } else {
1604 RTC_NOTREACHED();
1605 }
1606
Alex Loiko9289eda2018-11-23 16:18:59 +00001607 if (standardized_ice_connection_state_ != new_ice_connection_state) {
Jonas Olssonacd8ae72019-02-25 15:26:24 +01001608 if (standardized_ice_connection_state_ ==
1609 PeerConnectionInterface::kIceConnectionChecking &&
1610 new_ice_connection_state ==
1611 PeerConnectionInterface::kIceConnectionCompleted) {
1612 // Ensure that we never skip over the "connected" state.
1613 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_, [this] {
1614 SignalStandardizedIceConnectionState(
1615 PeerConnectionInterface::kIceConnectionConnected);
1616 });
1617 }
Alex Loiko9289eda2018-11-23 16:18:59 +00001618 standardized_ice_connection_state_ = new_ice_connection_state;
Jonas Olsson635474e2018-10-18 15:58:17 +02001619 invoker_.AsyncInvoke<void>(
1620 RTC_FROM_HERE, signaling_thread_, [this, new_ice_connection_state] {
Alex Loiko9289eda2018-11-23 16:18:59 +00001621 SignalStandardizedIceConnectionState(new_ice_connection_state);
Jonas Olsson635474e2018-10-18 15:58:17 +02001622 });
1623 }
1624
1625 // Compute the current RTCPeerConnectionState as described in
1626 // https://www.w3.org/TR/webrtc/#dom-rtcpeerconnectionstate.
1627 // The PeerConnection is responsible for handling the "closed" state.
1628 // Note that "connecting" is only a valid state for DTLS transports while
1629 // "checking", "completed" and "disconnected" are only valid for ICE
1630 // transports.
1631 int total_connected = total_ice_connected +
1632 dtls_state_counts[cricket::DTLS_TRANSPORT_CONNECTED];
1633 int total_dtls_connecting =
1634 dtls_state_counts[cricket::DTLS_TRANSPORT_CONNECTING];
1635 int total_failed =
1636 total_ice_failed + dtls_state_counts[cricket::DTLS_TRANSPORT_FAILED];
1637 int total_closed =
1638 total_ice_closed + dtls_state_counts[cricket::DTLS_TRANSPORT_CLOSED];
1639 int total_new =
1640 total_ice_new + dtls_state_counts[cricket::DTLS_TRANSPORT_NEW];
1641 int total_transports = total_ice * 2;
1642
1643 if (total_failed > 0) {
1644 // Any of the RTCIceTransports or RTCDtlsTransports are in a "failed" state.
1645 new_combined_state = PeerConnectionInterface::PeerConnectionState::kFailed;
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001646 } else if (total_ice_disconnected > 0) {
1647 // None of the previous states apply and any RTCIceTransports or
1648 // RTCDtlsTransports are in the "disconnected" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001649 new_combined_state =
1650 PeerConnectionInterface::PeerConnectionState::kDisconnected;
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001651 } else if (total_new + total_closed == total_transports) {
1652 // None of the previous states apply and all RTCIceTransports and
1653 // RTCDtlsTransports are in the "new" or "closed" state, or there are no
1654 // transports.
1655 new_combined_state = PeerConnectionInterface::PeerConnectionState::kNew;
1656 } else if (total_new + total_dtls_connecting + total_ice_checking > 0) {
1657 // None of the previous states apply and all RTCIceTransports or
1658 // RTCDtlsTransports are in the "new", "connecting" or "checking" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001659 new_combined_state =
1660 PeerConnectionInterface::PeerConnectionState::kConnecting;
1661 } else if (total_connected + total_ice_completed + total_closed ==
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001662 total_transports) {
1663 // None of the previous states apply and all RTCIceTransports and
1664 // RTCDtlsTransports are in the "connected", "completed" or "closed" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001665 new_combined_state =
1666 PeerConnectionInterface::PeerConnectionState::kConnected;
Jonas Olsson635474e2018-10-18 15:58:17 +02001667 } else {
1668 RTC_NOTREACHED();
1669 }
1670
1671 if (combined_connection_state_ != new_combined_state) {
1672 combined_connection_state_ = new_combined_state;
1673 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_,
1674 [this, new_combined_state] {
1675 SignalConnectionState(new_combined_state);
1676 });
1677 }
1678
Zhi Huange818b6e2018-02-22 15:26:27 -08001679 if (all_done_gathering) {
1680 new_gathering_state = cricket::kIceGatheringComplete;
1681 } else if (any_gathering) {
1682 new_gathering_state = cricket::kIceGatheringGathering;
1683 }
1684 if (ice_gathering_state_ != new_gathering_state) {
1685 ice_gathering_state_ = new_gathering_state;
Steve Antond25828a2018-08-31 13:06:05 -07001686 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_,
1687 [this, new_gathering_state] {
1688 SignalIceGatheringState(new_gathering_state);
1689 });
Zhi Huange818b6e2018-02-22 15:26:27 -08001690 }
1691}
1692
Sebastian Jansson1b83a9e2019-09-18 18:22:12 +02001693void JsepTransportController::OnRtcpPacketReceived_n(
1694 rtc::CopyOnWriteBuffer* packet,
1695 int64_t packet_time_us) {
1696 RTC_DCHECK(config_.rtcp_handler);
1697 config_.rtcp_handler(*packet, packet_time_us);
1698}
1699
Zhi Huange818b6e2018-02-22 15:26:27 -08001700void JsepTransportController::OnDtlsHandshakeError(
1701 rtc::SSLHandshakeError error) {
1702 SignalDtlsHandshakeError(error);
1703}
1704
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001705absl::optional<cricket::SessionDescription::MediaTransportSetting>
1706JsepTransportController::GenerateOrGetLastMediaTransportOffer() {
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07001707 if (media_transport_created_once_) {
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001708 RTC_LOG(LS_INFO) << "Not regenerating media transport for the new offer in "
1709 "existing session.";
1710 return media_transport_offer_settings_;
1711 }
1712
1713 RTC_LOG(LS_INFO) << "Generating media transport offer!";
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001714
1715 absl::optional<std::string> transport_parameters;
1716
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001717 // Check that media transport is supposed to be used.
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001718 // Note that ICE is not available when media transport is created. It will
1719 // only be available in 'Connect'. This may be a potential server config, if
1720 // we decide to use this peer connection as a caller, not as a callee.
1721 // TODO(sukhanov): Avoid code duplication with CreateMedia/MediaTransport.
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001722 if (config_.use_media_transport_for_media ||
1723 config_.use_media_transport_for_data_channels) {
1724 RTC_DCHECK(config_.media_transport_factory != nullptr);
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001725 RTC_DCHECK(!config_.use_datagram_transport);
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001726 webrtc::MediaTransportSettings settings;
1727 settings.is_caller = true;
1728 settings.pre_shared_key = rtc::CreateRandomString(32);
Bjorn A Mellemb073f1c2019-07-02 09:50:35 -07001729 if (config_.use_media_transport_for_media) {
1730 settings.event_log = config_.event_log;
1731 }
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001732 auto media_transport_or_error =
1733 config_.media_transport_factory->CreateMediaTransport(network_thread_,
1734 settings);
1735
1736 if (media_transport_or_error.ok()) {
1737 offer_media_transport_ = std::move(media_transport_or_error.value());
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001738 transport_parameters =
1739 offer_media_transport_->GetTransportParametersOffer();
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001740 } else {
1741 RTC_LOG(LS_INFO) << "Unable to create media transport, error="
1742 << media_transport_or_error.error().message();
1743 }
1744 }
1745
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07001746 if (!offer_media_transport_) {
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001747 RTC_LOG(LS_INFO) << "Media and data transports do not exist";
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001748 return absl::nullopt;
1749 }
1750
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001751 if (!transport_parameters) {
1752 RTC_LOG(LS_INFO) << "Media transport didn't generate the offer";
1753 // Media transport didn't generate the offer, and is not supposed to be
1754 // used. Destroy the temporary media transport.
1755 offer_media_transport_ = nullptr;
1756 return absl::nullopt;
1757 }
1758
1759 cricket::SessionDescription::MediaTransportSetting setting;
1760 setting.transport_name = config_.media_transport_factory->GetTransportName();
1761 setting.transport_setting = *transport_parameters;
1762 media_transport_offer_settings_ = setting;
1763 return setting;
1764}
1765
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07001766absl::optional<cricket::OpaqueTransportParameters>
1767JsepTransportController::GetTransportParameters(const std::string& mid) {
Bjorn A Mellemb689af42019-08-21 10:44:59 -07001768 if (!(config_.use_datagram_transport ||
1769 config_.use_datagram_transport_for_data_channels)) {
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07001770 return absl::nullopt;
1771 }
1772
1773 cricket::JsepTransport* transport = GetJsepTransportForMid(mid);
1774 if (transport) {
1775 absl::optional<cricket::OpaqueTransportParameters> params =
1776 transport->GetTransportParameters();
1777 if (params) {
1778 params->protocol = config_.media_transport_factory->GetTransportName();
1779 }
1780 return params;
1781 }
1782
1783 RTC_DCHECK(!local_desc_ && !remote_desc_)
1784 << "JsepTransport should exist for every mid once any description is set";
1785
1786 // Need to generate a transport for the offer.
1787 if (!offer_datagram_transport_) {
1788 webrtc::MediaTransportSettings settings;
1789 settings.is_caller = true;
1790 settings.pre_shared_key = rtc::CreateRandomString(32);
1791 settings.event_log = config_.event_log;
1792 auto datagram_transport_or_error =
1793 config_.media_transport_factory->CreateDatagramTransport(
1794 network_thread_, settings);
1795
1796 if (datagram_transport_or_error.ok()) {
1797 offer_datagram_transport_ =
1798 std::move(datagram_transport_or_error.value());
1799 } else {
1800 RTC_LOG(LS_INFO) << "Unable to create datagram transport, error="
1801 << datagram_transport_or_error.error().message();
1802 }
1803 }
1804
1805 // We have prepared a transport for the offer, and can now use its parameters.
1806 cricket::OpaqueTransportParameters params;
1807 params.parameters = offer_datagram_transport_->GetTransportParameters();
1808 params.protocol = config_.media_transport_factory->GetTransportName();
1809 return params;
1810}
1811
Zhi Huange818b6e2018-02-22 15:26:27 -08001812} // namespace webrtc