blob: dc05073c1b925b160c483effd1418abff738ce35 [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
13#include <algorithm>
14#include <memory>
15#include <utility>
16
Zach Steinc64078f2018-11-27 15:53:01 -080017#include "absl/memory/memory.h"
Zhi Huange818b6e2018-02-22 15:26:27 -080018#include "p2p/base/port.h"
Steve Anton10542f22019-01-11 09:11:00 -080019#include "pc/srtp_filter.h"
Zhi Huange818b6e2018-02-22 15:26:27 -080020#include "rtc_base/bind.h"
21#include "rtc_base/checks.h"
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -070022#include "rtc_base/key_derivation.h"
Zhi Huange818b6e2018-02-22 15:26:27 -080023#include "rtc_base/thread.h"
24
25using webrtc::SdpType;
26
27namespace {
28
Zhi Huange818b6e2018-02-22 15:26:27 -080029webrtc::RTCError VerifyCandidate(const cricket::Candidate& cand) {
30 // No address zero.
31 if (cand.address().IsNil() || cand.address().IsAnyIP()) {
32 return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
33 "candidate has address of zero");
34 }
35
36 // Disallow all ports below 1024, except for 80 and 443 on public addresses.
37 int port = cand.address().port();
38 if (cand.protocol() == cricket::TCP_PROTOCOL_NAME &&
39 (cand.tcptype() == cricket::TCPTYPE_ACTIVE_STR || port == 0)) {
40 // Expected for active-only candidates per
41 // http://tools.ietf.org/html/rfc6544#section-4.5 so no error.
42 // Libjingle clients emit port 0, in "active" mode.
43 return webrtc::RTCError::OK();
44 }
45 if (port < 1024) {
46 if ((port != 80) && (port != 443)) {
47 return webrtc::RTCError(
48 webrtc::RTCErrorType::INVALID_PARAMETER,
49 "candidate has port below 1024, but not 80 or 443");
50 }
51
52 if (cand.address().IsPrivateIP()) {
53 return webrtc::RTCError(
54 webrtc::RTCErrorType::INVALID_PARAMETER,
55 "candidate has port of 80 or 443 with private IP address");
56 }
57 }
58
59 return webrtc::RTCError::OK();
60}
61
62webrtc::RTCError VerifyCandidates(const cricket::Candidates& candidates) {
63 for (const cricket::Candidate& candidate : candidates) {
64 webrtc::RTCError error = VerifyCandidate(candidate);
65 if (!error.ok()) {
66 return error;
67 }
68 }
69 return webrtc::RTCError::OK();
70}
71
72} // namespace
73
74namespace webrtc {
75
76JsepTransportController::JsepTransportController(
77 rtc::Thread* signaling_thread,
78 rtc::Thread* network_thread,
79 cricket::PortAllocator* port_allocator,
Zach Steine20867f2018-08-02 13:20:15 -070080 AsyncResolverFactory* async_resolver_factory,
Zhi Huange818b6e2018-02-22 15:26:27 -080081 Config config)
82 : signaling_thread_(signaling_thread),
83 network_thread_(network_thread),
84 port_allocator_(port_allocator),
Zach Steine20867f2018-08-02 13:20:15 -070085 async_resolver_factory_(async_resolver_factory),
Zhi Huang365381f2018-04-13 16:44:34 -070086 config_(config) {
87 // The |transport_observer| is assumed to be non-null.
88 RTC_DCHECK(config_.transport_observer);
89}
Zhi Huange818b6e2018-02-22 15:26:27 -080090
91JsepTransportController::~JsepTransportController() {
92 // Channel destructors may try to send packets, so this needs to happen on
93 // the network thread.
94 network_thread_->Invoke<void>(
95 RTC_FROM_HERE,
96 rtc::Bind(&JsepTransportController::DestroyAllJsepTransports_n, this));
97}
98
99RTCError JsepTransportController::SetLocalDescription(
100 SdpType type,
101 const cricket::SessionDescription* description) {
102 if (!network_thread_->IsCurrent()) {
103 return network_thread_->Invoke<RTCError>(
104 RTC_FROM_HERE, [=] { return SetLocalDescription(type, description); });
105 }
106
107 if (!initial_offerer_.has_value()) {
108 initial_offerer_.emplace(type == SdpType::kOffer);
109 if (*initial_offerer_) {
110 SetIceRole_n(cricket::ICEROLE_CONTROLLING);
111 } else {
112 SetIceRole_n(cricket::ICEROLE_CONTROLLED);
113 }
114 }
115 return ApplyDescription_n(/*local=*/true, type, description);
116}
117
118RTCError JsepTransportController::SetRemoteDescription(
119 SdpType type,
120 const cricket::SessionDescription* description) {
121 if (!network_thread_->IsCurrent()) {
122 return network_thread_->Invoke<RTCError>(
123 RTC_FROM_HERE, [=] { return SetRemoteDescription(type, description); });
124 }
125
126 return ApplyDescription_n(/*local=*/false, type, description);
127}
128
129RtpTransportInternal* JsepTransportController::GetRtpTransport(
130 const std::string& mid) const {
Zhi Huange830e682018-03-30 10:48:35 -0700131 auto jsep_transport = GetJsepTransportForMid(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -0800132 if (!jsep_transport) {
133 return nullptr;
134 }
135 return jsep_transport->rtp_transport();
136}
137
Anton Sukhanov7940da02018-10-10 10:34:49 -0700138MediaTransportInterface* JsepTransportController::GetMediaTransport(
139 const std::string& mid) const {
140 auto jsep_transport = GetJsepTransportForMid(mid);
141 if (!jsep_transport) {
142 return nullptr;
143 }
144 return jsep_transport->media_transport();
145}
146
Bjorn Mellem175aa2e2018-11-08 11:23:22 -0800147MediaTransportState JsepTransportController::GetMediaTransportState(
148 const std::string& mid) const {
149 auto jsep_transport = GetJsepTransportForMid(mid);
150 if (!jsep_transport) {
151 return MediaTransportState::kPending;
152 }
153 return jsep_transport->media_transport_state();
154}
155
Zhi Huange818b6e2018-02-22 15:26:27 -0800156cricket::DtlsTransportInternal* JsepTransportController::GetDtlsTransport(
Harald Alvestrandad88c882018-11-28 16:47:46 +0100157 const std::string& mid) {
Zhi Huange830e682018-03-30 10:48:35 -0700158 auto jsep_transport = GetJsepTransportForMid(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -0800159 if (!jsep_transport) {
160 return nullptr;
161 }
162 return jsep_transport->rtp_dtls_transport();
163}
164
Harald Alvestrandad88c882018-11-28 16:47:46 +0100165const cricket::DtlsTransportInternal*
166JsepTransportController::GetRtcpDtlsTransport(const std::string& mid) const {
Zhi Huange830e682018-03-30 10:48:35 -0700167 auto jsep_transport = GetJsepTransportForMid(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -0800168 if (!jsep_transport) {
169 return nullptr;
170 }
171 return jsep_transport->rtcp_dtls_transport();
172}
173
Harald Alvestrandad88c882018-11-28 16:47:46 +0100174rtc::scoped_refptr<webrtc::DtlsTransportInterface>
175JsepTransportController::LookupDtlsTransportByMid(const std::string& mid) {
176 auto jsep_transport = GetJsepTransportForMid(mid);
177 if (!jsep_transport) {
178 return nullptr;
179 }
180 return jsep_transport->RtpDtlsTransport();
181}
182
Zhi Huange818b6e2018-02-22 15:26:27 -0800183void JsepTransportController::SetIceConfig(const cricket::IceConfig& config) {
184 if (!network_thread_->IsCurrent()) {
185 network_thread_->Invoke<void>(RTC_FROM_HERE, [&] { SetIceConfig(config); });
186 return;
187 }
188
189 ice_config_ = config;
190 for (auto& dtls : GetDtlsTransports()) {
191 dtls->ice_transport()->SetIceConfig(ice_config_);
192 }
193}
194
195void JsepTransportController::SetNeedsIceRestartFlag() {
Zhi Huange830e682018-03-30 10:48:35 -0700196 for (auto& kv : jsep_transports_by_name_) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800197 kv.second->SetNeedsIceRestartFlag();
198 }
199}
200
201bool JsepTransportController::NeedsIceRestart(
202 const std::string& transport_name) const {
Zhi Huang365381f2018-04-13 16:44:34 -0700203 const cricket::JsepTransport* transport =
Zhi Huange830e682018-03-30 10:48:35 -0700204 GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800205 if (!transport) {
206 return false;
207 }
208 return transport->needs_ice_restart();
209}
210
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200211absl::optional<rtc::SSLRole> JsepTransportController::GetDtlsRole(
Zhi Huange830e682018-03-30 10:48:35 -0700212 const std::string& mid) const {
Zhi Huange818b6e2018-02-22 15:26:27 -0800213 if (!network_thread_->IsCurrent()) {
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200214 return network_thread_->Invoke<absl::optional<rtc::SSLRole>>(
Zhi Huange830e682018-03-30 10:48:35 -0700215 RTC_FROM_HERE, [&] { return GetDtlsRole(mid); });
Zhi Huange818b6e2018-02-22 15:26:27 -0800216 }
217
Zhi Huang365381f2018-04-13 16:44:34 -0700218 const cricket::JsepTransport* t = GetJsepTransportForMid(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -0800219 if (!t) {
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200220 return absl::optional<rtc::SSLRole>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800221 }
222 return t->GetDtlsRole();
223}
224
225bool JsepTransportController::SetLocalCertificate(
226 const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) {
227 if (!network_thread_->IsCurrent()) {
228 return network_thread_->Invoke<bool>(
229 RTC_FROM_HERE, [&] { return SetLocalCertificate(certificate); });
230 }
231
232 // Can't change a certificate, or set a null certificate.
233 if (certificate_ || !certificate) {
234 return false;
235 }
236 certificate_ = certificate;
237
238 // Set certificate for JsepTransport, which verifies it matches the
239 // fingerprint in SDP, and DTLS transport.
240 // Fallback from DTLS to SDES is not supported.
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->SetLocalCertificate(certificate_);
243 }
244 for (auto& dtls : GetDtlsTransports()) {
245 bool set_cert_success = dtls->SetLocalCertificate(certificate_);
246 RTC_DCHECK(set_cert_success);
247 }
248 return true;
249}
250
251rtc::scoped_refptr<rtc::RTCCertificate>
252JsepTransportController::GetLocalCertificate(
253 const std::string& transport_name) const {
254 if (!network_thread_->IsCurrent()) {
255 return network_thread_->Invoke<rtc::scoped_refptr<rtc::RTCCertificate>>(
256 RTC_FROM_HERE, [&] { return GetLocalCertificate(transport_name); });
257 }
258
Zhi Huang365381f2018-04-13 16:44:34 -0700259 const cricket::JsepTransport* t = GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800260 if (!t) {
261 return nullptr;
262 }
263 return t->GetLocalCertificate();
264}
265
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800266std::unique_ptr<rtc::SSLCertChain>
267JsepTransportController::GetRemoteSSLCertChain(
Zhi Huange818b6e2018-02-22 15:26:27 -0800268 const std::string& transport_name) const {
269 if (!network_thread_->IsCurrent()) {
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800270 return network_thread_->Invoke<std::unique_ptr<rtc::SSLCertChain>>(
271 RTC_FROM_HERE, [&] { return GetRemoteSSLCertChain(transport_name); });
Zhi Huange818b6e2018-02-22 15:26:27 -0800272 }
273
Zhi Huange830e682018-03-30 10:48:35 -0700274 // Get the certificate from the RTP transport's DTLS handshake. Should be
275 // identical to the RTCP transport's, since they were given the same remote
Zhi Huange818b6e2018-02-22 15:26:27 -0800276 // fingerprint.
Zhi Huange830e682018-03-30 10:48:35 -0700277 auto jsep_transport = GetJsepTransportByName(transport_name);
278 if (!jsep_transport) {
279 return nullptr;
280 }
281 auto dtls = jsep_transport->rtp_dtls_transport();
Zhi Huange818b6e2018-02-22 15:26:27 -0800282 if (!dtls) {
283 return nullptr;
284 }
285
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800286 return dtls->GetRemoteSSLCertChain();
Zhi Huange818b6e2018-02-22 15:26:27 -0800287}
288
289void JsepTransportController::MaybeStartGathering() {
290 if (!network_thread_->IsCurrent()) {
291 network_thread_->Invoke<void>(RTC_FROM_HERE,
292 [&] { MaybeStartGathering(); });
293 return;
294 }
295
296 for (auto& dtls : GetDtlsTransports()) {
297 dtls->ice_transport()->MaybeStartGathering();
298 }
299}
300
301RTCError JsepTransportController::AddRemoteCandidates(
302 const std::string& transport_name,
303 const cricket::Candidates& candidates) {
304 if (!network_thread_->IsCurrent()) {
305 return network_thread_->Invoke<RTCError>(RTC_FROM_HERE, [&] {
306 return AddRemoteCandidates(transport_name, candidates);
307 });
308 }
309
310 // Verify each candidate before passing down to the transport layer.
311 RTCError error = VerifyCandidates(candidates);
312 if (!error.ok()) {
313 return error;
314 }
Zhi Huange830e682018-03-30 10:48:35 -0700315 auto jsep_transport = GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800316 if (!jsep_transport) {
Zhi Huange830e682018-03-30 10:48:35 -0700317 RTC_LOG(LS_WARNING) << "Not adding candidate because the JsepTransport "
318 "doesn't exist. Ignore it.";
319 return RTCError::OK();
Zhi Huange818b6e2018-02-22 15:26:27 -0800320 }
Zhi Huange818b6e2018-02-22 15:26:27 -0800321 return jsep_transport->AddRemoteCandidates(candidates);
322}
323
324RTCError JsepTransportController::RemoveRemoteCandidates(
325 const cricket::Candidates& candidates) {
326 if (!network_thread_->IsCurrent()) {
327 return network_thread_->Invoke<RTCError>(
328 RTC_FROM_HERE, [&] { return RemoveRemoteCandidates(candidates); });
329 }
330
331 // Verify each candidate before passing down to the transport layer.
332 RTCError error = VerifyCandidates(candidates);
333 if (!error.ok()) {
334 return error;
335 }
336
337 std::map<std::string, cricket::Candidates> candidates_by_transport_name;
338 for (const cricket::Candidate& cand : candidates) {
339 if (!cand.transport_name().empty()) {
340 candidates_by_transport_name[cand.transport_name()].push_back(cand);
341 } else {
342 RTC_LOG(LS_ERROR) << "Not removing candidate because it does not have a "
343 "transport name set: "
344 << cand.ToString();
345 }
346 }
347
348 for (const auto& kv : candidates_by_transport_name) {
349 const std::string& transport_name = kv.first;
350 const cricket::Candidates& candidates = kv.second;
Zhi Huang365381f2018-04-13 16:44:34 -0700351 cricket::JsepTransport* jsep_transport =
Zhi Huange830e682018-03-30 10:48:35 -0700352 GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800353 if (!jsep_transport) {
Zhi Huange830e682018-03-30 10:48:35 -0700354 RTC_LOG(LS_WARNING)
355 << "Not removing candidate because the JsepTransport doesn't exist.";
356 continue;
Zhi Huange818b6e2018-02-22 15:26:27 -0800357 }
358 for (const cricket::Candidate& candidate : candidates) {
Harald Alvestrandad88c882018-11-28 16:47:46 +0100359 cricket::DtlsTransportInternal* dtls =
360 candidate.component() == cricket::ICE_CANDIDATE_COMPONENT_RTP
361 ? jsep_transport->rtp_dtls_transport()
362 : jsep_transport->rtcp_dtls_transport();
Zhi Huange818b6e2018-02-22 15:26:27 -0800363 if (dtls) {
364 dtls->ice_transport()->RemoveRemoteCandidate(candidate);
365 }
366 }
367 }
368 return RTCError::OK();
369}
370
371bool JsepTransportController::GetStats(const std::string& transport_name,
372 cricket::TransportStats* stats) {
373 if (!network_thread_->IsCurrent()) {
374 return network_thread_->Invoke<bool>(
375 RTC_FROM_HERE, [=] { return GetStats(transport_name, stats); });
376 }
377
Zhi Huang365381f2018-04-13 16:44:34 -0700378 cricket::JsepTransport* transport = GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800379 if (!transport) {
380 return false;
381 }
382 return transport->GetStats(stats);
383}
384
Zhi Huangb57e1692018-06-12 11:41:11 -0700385void JsepTransportController::SetActiveResetSrtpParams(
386 bool active_reset_srtp_params) {
387 if (!network_thread_->IsCurrent()) {
388 network_thread_->Invoke<void>(RTC_FROM_HERE, [=] {
389 SetActiveResetSrtpParams(active_reset_srtp_params);
390 });
391 return;
392 }
393
394 RTC_LOG(INFO)
395 << "Updating the active_reset_srtp_params for JsepTransportController: "
396 << active_reset_srtp_params;
397 config_.active_reset_srtp_params = active_reset_srtp_params;
398 for (auto& kv : jsep_transports_by_name_) {
399 kv.second->SetActiveResetSrtpParams(active_reset_srtp_params);
400 }
401}
402
Piotr (Peter) Slatala97fc11f2018-10-18 12:57:59 -0700403void JsepTransportController::SetMediaTransportFactory(
404 MediaTransportFactory* media_transport_factory) {
405 RTC_DCHECK(media_transport_factory == config_.media_transport_factory ||
406 jsep_transports_by_name_.empty())
407 << "You can only call SetMediaTransportFactory before "
408 "JsepTransportController created its first transport.";
409 config_.media_transport_factory = media_transport_factory;
410}
411
Zhi Huange818b6e2018-02-22 15:26:27 -0800412std::unique_ptr<cricket::DtlsTransportInternal>
413JsepTransportController::CreateDtlsTransport(const std::string& transport_name,
414 bool rtcp) {
415 RTC_DCHECK(network_thread_->IsCurrent());
416 int component = rtcp ? cricket::ICE_CANDIDATE_COMPONENT_RTCP
417 : cricket::ICE_CANDIDATE_COMPONENT_RTP;
418
419 std::unique_ptr<cricket::DtlsTransportInternal> dtls;
420 if (config_.external_transport_factory) {
421 auto ice = config_.external_transport_factory->CreateIceTransport(
422 transport_name, component);
423 dtls = config_.external_transport_factory->CreateDtlsTransport(
424 std::move(ice), config_.crypto_options);
425 } else {
Karl Wiberg918f50c2018-07-05 11:40:33 +0200426 auto ice = absl::make_unique<cricket::P2PTransportChannel>(
Zach Steine20867f2018-08-02 13:20:15 -0700427 transport_name, component, port_allocator_, async_resolver_factory_,
428 config_.event_log);
Zach Steinc64078f2018-11-27 15:53:01 -0800429 dtls = absl::make_unique<cricket::DtlsTransport>(
430 std::move(ice), config_.crypto_options, config_.event_log);
Zhi Huange818b6e2018-02-22 15:26:27 -0800431 }
432
433 RTC_DCHECK(dtls);
434 dtls->SetSslMaxProtocolVersion(config_.ssl_max_version);
Zhi Huange818b6e2018-02-22 15:26:27 -0800435 dtls->ice_transport()->SetIceRole(ice_role_);
436 dtls->ice_transport()->SetIceTiebreaker(ice_tiebreaker_);
437 dtls->ice_transport()->SetIceConfig(ice_config_);
438 if (certificate_) {
439 bool set_cert_success = dtls->SetLocalCertificate(certificate_);
440 RTC_DCHECK(set_cert_success);
441 }
442
443 // Connect to signals offered by the DTLS and ICE transport.
444 dtls->SignalWritableState.connect(
445 this, &JsepTransportController::OnTransportWritableState_n);
446 dtls->SignalReceivingState.connect(
447 this, &JsepTransportController::OnTransportReceivingState_n);
448 dtls->SignalDtlsHandshakeError.connect(
449 this, &JsepTransportController::OnDtlsHandshakeError);
450 dtls->ice_transport()->SignalGatheringState.connect(
451 this, &JsepTransportController::OnTransportGatheringState_n);
452 dtls->ice_transport()->SignalCandidateGathered.connect(
453 this, &JsepTransportController::OnTransportCandidateGathered_n);
454 dtls->ice_transport()->SignalCandidatesRemoved.connect(
455 this, &JsepTransportController::OnTransportCandidatesRemoved_n);
456 dtls->ice_transport()->SignalRoleConflict.connect(
457 this, &JsepTransportController::OnTransportRoleConflict_n);
458 dtls->ice_transport()->SignalStateChanged.connect(
459 this, &JsepTransportController::OnTransportStateChanged_n);
Jonas Olsson7a6739e2019-01-15 16:31:55 +0100460 dtls->ice_transport()->SignalIceTransportStateChanged.connect(
461 this, &JsepTransportController::OnTransportStateChanged_n);
Zhi Huange818b6e2018-02-22 15:26:27 -0800462 return dtls;
463}
464
465std::unique_ptr<webrtc::RtpTransport>
466JsepTransportController::CreateUnencryptedRtpTransport(
467 const std::string& transport_name,
468 rtc::PacketTransportInternal* rtp_packet_transport,
469 rtc::PacketTransportInternal* rtcp_packet_transport) {
470 RTC_DCHECK(network_thread_->IsCurrent());
Zhi Huange830e682018-03-30 10:48:35 -0700471 auto unencrypted_rtp_transport =
Karl Wiberg918f50c2018-07-05 11:40:33 +0200472 absl::make_unique<RtpTransport>(rtcp_packet_transport == nullptr);
Zhi Huange830e682018-03-30 10:48:35 -0700473 unencrypted_rtp_transport->SetRtpPacketTransport(rtp_packet_transport);
474 if (rtcp_packet_transport) {
475 unencrypted_rtp_transport->SetRtcpPacketTransport(rtcp_packet_transport);
476 }
477 return unencrypted_rtp_transport;
Zhi Huange818b6e2018-02-22 15:26:27 -0800478}
479
480std::unique_ptr<webrtc::SrtpTransport>
481JsepTransportController::CreateSdesTransport(
482 const std::string& transport_name,
Zhi Huange830e682018-03-30 10:48:35 -0700483 cricket::DtlsTransportInternal* rtp_dtls_transport,
484 cricket::DtlsTransportInternal* rtcp_dtls_transport) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800485 RTC_DCHECK(network_thread_->IsCurrent());
Zhi Huange818b6e2018-02-22 15:26:27 -0800486 auto srtp_transport =
Karl Wiberg918f50c2018-07-05 11:40:33 +0200487 absl::make_unique<webrtc::SrtpTransport>(rtcp_dtls_transport == nullptr);
Zhi Huange830e682018-03-30 10:48:35 -0700488 RTC_DCHECK(rtp_dtls_transport);
489 srtp_transport->SetRtpPacketTransport(rtp_dtls_transport);
490 if (rtcp_dtls_transport) {
491 srtp_transport->SetRtcpPacketTransport(rtcp_dtls_transport);
Zhi Huange818b6e2018-02-22 15:26:27 -0800492 }
493 if (config_.enable_external_auth) {
494 srtp_transport->EnableExternalAuth();
495 }
496 return srtp_transport;
497}
498
499std::unique_ptr<webrtc::DtlsSrtpTransport>
500JsepTransportController::CreateDtlsSrtpTransport(
501 const std::string& transport_name,
502 cricket::DtlsTransportInternal* rtp_dtls_transport,
503 cricket::DtlsTransportInternal* rtcp_dtls_transport) {
504 RTC_DCHECK(network_thread_->IsCurrent());
Karl Wiberg918f50c2018-07-05 11:40:33 +0200505 auto dtls_srtp_transport = absl::make_unique<webrtc::DtlsSrtpTransport>(
Zhi Huang365381f2018-04-13 16:44:34 -0700506 rtcp_dtls_transport == nullptr);
Zhi Huang27f3bf52018-03-26 21:37:23 -0700507 if (config_.enable_external_auth) {
Zhi Huang365381f2018-04-13 16:44:34 -0700508 dtls_srtp_transport->EnableExternalAuth();
Zhi Huang27f3bf52018-03-26 21:37:23 -0700509 }
Zhi Huang97d5e5b2018-03-27 00:09:01 +0000510
Zhi Huange818b6e2018-02-22 15:26:27 -0800511 dtls_srtp_transport->SetDtlsTransports(rtp_dtls_transport,
512 rtcp_dtls_transport);
Zhi Huangb57e1692018-06-12 11:41:11 -0700513 dtls_srtp_transport->SetActiveResetSrtpParams(
514 config_.active_reset_srtp_params);
Jonas Olsson635474e2018-10-18 15:58:17 +0200515 dtls_srtp_transport->SignalDtlsStateChange.connect(
516 this, &JsepTransportController::UpdateAggregateStates_n);
Zhi Huange818b6e2018-02-22 15:26:27 -0800517 return dtls_srtp_transport;
518}
519
520std::vector<cricket::DtlsTransportInternal*>
521JsepTransportController::GetDtlsTransports() {
522 std::vector<cricket::DtlsTransportInternal*> dtls_transports;
Zhi Huange830e682018-03-30 10:48:35 -0700523 for (auto it = jsep_transports_by_name_.begin();
524 it != jsep_transports_by_name_.end(); ++it) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800525 auto jsep_transport = it->second.get();
526 RTC_DCHECK(jsep_transport);
527 if (jsep_transport->rtp_dtls_transport()) {
528 dtls_transports.push_back(jsep_transport->rtp_dtls_transport());
529 }
530
531 if (jsep_transport->rtcp_dtls_transport()) {
532 dtls_transports.push_back(jsep_transport->rtcp_dtls_transport());
533 }
534 }
535 return dtls_transports;
536}
537
Zhi Huange818b6e2018-02-22 15:26:27 -0800538RTCError JsepTransportController::ApplyDescription_n(
539 bool local,
540 SdpType type,
541 const cricket::SessionDescription* description) {
542 RTC_DCHECK(network_thread_->IsCurrent());
543 RTC_DCHECK(description);
544
545 if (local) {
546 local_desc_ = description;
547 } else {
548 remote_desc_ = description;
549 }
550
Zhi Huange830e682018-03-30 10:48:35 -0700551 RTCError error;
Zhi Huangd2248f82018-04-10 14:41:03 -0700552 error = ValidateAndMaybeUpdateBundleGroup(local, type, description);
Zhi Huange830e682018-03-30 10:48:35 -0700553 if (!error.ok()) {
554 return error;
Zhi Huange818b6e2018-02-22 15:26:27 -0800555 }
556
557 std::vector<int> merged_encrypted_extension_ids;
558 if (bundle_group_) {
559 merged_encrypted_extension_ids =
560 MergeEncryptedHeaderExtensionIdsForBundle(description);
561 }
562
563 for (const cricket::ContentInfo& content_info : description->contents()) {
564 // Don't create transports for rejected m-lines and bundled m-lines."
565 if (content_info.rejected ||
566 (IsBundled(content_info.name) && content_info.name != *bundled_mid())) {
567 continue;
568 }
Anton Sukhanov7940da02018-10-10 10:34:49 -0700569 error = MaybeCreateJsepTransport(local, content_info);
Zhi Huange830e682018-03-30 10:48:35 -0700570 if (!error.ok()) {
571 return error;
572 }
Zhi Huange818b6e2018-02-22 15:26:27 -0800573 }
574
575 RTC_DCHECK(description->contents().size() ==
576 description->transport_infos().size());
577 for (size_t i = 0; i < description->contents().size(); ++i) {
578 const cricket::ContentInfo& content_info = description->contents()[i];
579 const cricket::TransportInfo& transport_info =
580 description->transport_infos()[i];
581 if (content_info.rejected) {
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700582 HandleRejectedContent(content_info, description);
Zhi Huange818b6e2018-02-22 15:26:27 -0800583 continue;
584 }
585
586 if (IsBundled(content_info.name) && content_info.name != *bundled_mid()) {
Zhi Huang365381f2018-04-13 16:44:34 -0700587 if (!HandleBundledContent(content_info)) {
588 return RTCError(RTCErrorType::INVALID_PARAMETER,
589 "Failed to process the bundled m= section.");
590 }
Zhi Huange818b6e2018-02-22 15:26:27 -0800591 continue;
592 }
593
Zhi Huange830e682018-03-30 10:48:35 -0700594 error = ValidateContent(content_info);
595 if (!error.ok()) {
596 return error;
597 }
598
Zhi Huange818b6e2018-02-22 15:26:27 -0800599 std::vector<int> extension_ids;
Taylor Brandstetter0ab56512018-04-12 10:30:48 -0700600 if (bundled_mid() && content_info.name == *bundled_mid()) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800601 extension_ids = merged_encrypted_extension_ids;
602 } else {
603 extension_ids = GetEncryptedHeaderExtensionIds(content_info);
604 }
605
Zhi Huange830e682018-03-30 10:48:35 -0700606 int rtp_abs_sendtime_extn_id =
607 GetRtpAbsSendTimeHeaderExtensionId(content_info);
608
Zhi Huang365381f2018-04-13 16:44:34 -0700609 cricket::JsepTransport* transport =
Zhi Huange830e682018-03-30 10:48:35 -0700610 GetJsepTransportForMid(content_info.name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800611 RTC_DCHECK(transport);
612
613 SetIceRole_n(DetermineIceRole(transport, transport_info, type, local));
614
Zhi Huange818b6e2018-02-22 15:26:27 -0800615 cricket::JsepTransportDescription jsep_description =
616 CreateJsepTransportDescription(content_info, transport_info,
Zhi Huange830e682018-03-30 10:48:35 -0700617 extension_ids, rtp_abs_sendtime_extn_id);
Zhi Huange818b6e2018-02-22 15:26:27 -0800618 if (local) {
619 error =
620 transport->SetLocalJsepTransportDescription(jsep_description, type);
621 } else {
622 error =
623 transport->SetRemoteJsepTransportDescription(jsep_description, type);
624 }
625
626 if (!error.ok()) {
627 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
628 "Failed to apply the description for " +
629 content_info.name + ": " + error.message());
630 }
631 }
632 return RTCError::OK();
633}
634
Zhi Huangd2248f82018-04-10 14:41:03 -0700635RTCError JsepTransportController::ValidateAndMaybeUpdateBundleGroup(
636 bool local,
637 SdpType type,
Zhi Huange830e682018-03-30 10:48:35 -0700638 const cricket::SessionDescription* description) {
639 RTC_DCHECK(description);
Zhi Huangd2248f82018-04-10 14:41:03 -0700640 const cricket::ContentGroup* new_bundle_group =
641 description->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
642
643 // The BUNDLE group containing a MID that no m= section has is invalid.
644 if (new_bundle_group) {
645 for (auto content_name : new_bundle_group->content_names()) {
646 if (!description->GetContentByName(content_name)) {
647 return RTCError(RTCErrorType::INVALID_PARAMETER,
648 "The BUNDLE group contains MID:" + content_name +
649 " matching no m= section.");
650 }
651 }
652 }
653
654 if (type == SdpType::kAnswer) {
655 const cricket::ContentGroup* offered_bundle_group =
656 local ? remote_desc_->GetGroupByName(cricket::GROUP_TYPE_BUNDLE)
657 : local_desc_->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
658
659 if (new_bundle_group) {
660 // The BUNDLE group in answer should be a subset of offered group.
661 for (auto content_name : new_bundle_group->content_names()) {
662 if (!offered_bundle_group ||
663 !offered_bundle_group->HasContentName(content_name)) {
664 return RTCError(RTCErrorType::INVALID_PARAMETER,
665 "The BUNDLE group in answer contains a MID that was "
666 "not in the offered group.");
667 }
668 }
669 }
670
671 if (bundle_group_) {
672 for (auto content_name : bundle_group_->content_names()) {
673 // An answer that removes m= sections from pre-negotiated BUNDLE group
674 // without rejecting it, is invalid.
675 if (!new_bundle_group ||
676 !new_bundle_group->HasContentName(content_name)) {
677 auto* content_info = description->GetContentByName(content_name);
678 if (!content_info || !content_info->rejected) {
679 return RTCError(RTCErrorType::INVALID_PARAMETER,
680 "Answer cannot remove m= section " + content_name +
681 " from already-established BUNDLE group.");
682 }
683 }
684 }
685 }
686 }
687
688 if (config_.bundle_policy ==
689 PeerConnectionInterface::kBundlePolicyMaxBundle &&
690 !description->HasGroup(cricket::GROUP_TYPE_BUNDLE)) {
691 return RTCError(RTCErrorType::INVALID_PARAMETER,
692 "max-bundle is used but no bundle group found.");
693 }
694
695 if (ShouldUpdateBundleGroup(type, description)) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700696 bundle_group_ = *new_bundle_group;
697 }
Zhi Huange830e682018-03-30 10:48:35 -0700698
699 if (!bundled_mid()) {
700 return RTCError::OK();
701 }
702
703 auto bundled_content = description->GetContentByName(*bundled_mid());
704 if (!bundled_content) {
705 return RTCError(
706 RTCErrorType::INVALID_PARAMETER,
707 "An m= section associated with the BUNDLE-tag doesn't exist.");
708 }
709
710 // If the |bundled_content| is rejected, other contents in the bundle group
711 // should be rejected.
712 if (bundled_content->rejected) {
713 for (auto content_name : bundle_group_->content_names()) {
714 auto other_content = description->GetContentByName(content_name);
715 if (!other_content->rejected) {
716 return RTCError(
717 RTCErrorType::INVALID_PARAMETER,
718 "The m= section:" + content_name + " should be rejected.");
719 }
720 }
721 }
722
723 return RTCError::OK();
724}
725
726RTCError JsepTransportController::ValidateContent(
727 const cricket::ContentInfo& content_info) {
728 if (config_.rtcp_mux_policy ==
729 PeerConnectionInterface::kRtcpMuxPolicyRequire &&
730 content_info.type == cricket::MediaProtocolType::kRtp &&
731 !content_info.media_description()->rtcp_mux()) {
732 return RTCError(RTCErrorType::INVALID_PARAMETER,
733 "The m= section:" + content_info.name +
734 " is invalid. RTCP-MUX is not "
735 "enabled when it is required.");
736 }
737 return RTCError::OK();
738}
739
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700740void JsepTransportController::HandleRejectedContent(
Zhi Huangd2248f82018-04-10 14:41:03 -0700741 const cricket::ContentInfo& content_info,
742 const cricket::SessionDescription* description) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800743 // If the content is rejected, let the
744 // BaseChannel/SctpTransport change the RtpTransport/DtlsTransport first,
Zhi Huang365381f2018-04-13 16:44:34 -0700745 // then destroy the cricket::JsepTransport.
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700746 RemoveTransportForMid(content_info.name);
Zhi Huange830e682018-03-30 10:48:35 -0700747 if (content_info.name == bundled_mid()) {
748 for (auto content_name : bundle_group_->content_names()) {
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700749 RemoveTransportForMid(content_name);
Zhi Huange830e682018-03-30 10:48:35 -0700750 }
751 bundle_group_.reset();
752 } else if (IsBundled(content_info.name)) {
753 // Remove the rejected content from the |bundle_group_|.
Zhi Huange818b6e2018-02-22 15:26:27 -0800754 bundle_group_->RemoveContentName(content_info.name);
Zhi Huange830e682018-03-30 10:48:35 -0700755 // Reset the bundle group if nothing left.
756 if (!bundle_group_->FirstContentName()) {
757 bundle_group_.reset();
758 }
Zhi Huange818b6e2018-02-22 15:26:27 -0800759 }
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700760 MaybeDestroyJsepTransport(content_info.name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800761}
762
Zhi Huang365381f2018-04-13 16:44:34 -0700763bool JsepTransportController::HandleBundledContent(
Zhi Huange818b6e2018-02-22 15:26:27 -0800764 const cricket::ContentInfo& content_info) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700765 auto jsep_transport = GetJsepTransportByName(*bundled_mid());
766 RTC_DCHECK(jsep_transport);
Zhi Huange818b6e2018-02-22 15:26:27 -0800767 // If the content is bundled, let the
768 // BaseChannel/SctpTransport change the RtpTransport/DtlsTransport first,
Zhi Huang365381f2018-04-13 16:44:34 -0700769 // then destroy the cricket::JsepTransport.
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700770 if (SetTransportForMid(content_info.name, jsep_transport)) {
Piotr (Peter) Slatala10aeb2a2018-11-14 10:57:24 -0800771 // TODO(bugs.webrtc.org/9719) For media transport this is far from ideal,
772 // because it means that we first create media transport and start
773 // connecting it, and then we destroy it. We will need to address it before
774 // video path is enabled.
Zhi Huang365381f2018-04-13 16:44:34 -0700775 MaybeDestroyJsepTransport(content_info.name);
776 return true;
777 }
778 return false;
Zhi Huange818b6e2018-02-22 15:26:27 -0800779}
780
Zhi Huang365381f2018-04-13 16:44:34 -0700781bool JsepTransportController::SetTransportForMid(
Zhi Huangd2248f82018-04-10 14:41:03 -0700782 const std::string& mid,
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700783 cricket::JsepTransport* jsep_transport) {
Zhi Huang365381f2018-04-13 16:44:34 -0700784 RTC_DCHECK(jsep_transport);
Zhi Huangd2248f82018-04-10 14:41:03 -0700785 if (mid_to_transport_[mid] == jsep_transport) {
Zhi Huang365381f2018-04-13 16:44:34 -0700786 return true;
Zhi Huangd2248f82018-04-10 14:41:03 -0700787 }
788
789 mid_to_transport_[mid] = jsep_transport;
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700790 return config_.transport_observer->OnTransportChanged(
791 mid, jsep_transport->rtp_transport(),
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -0800792 jsep_transport->rtp_dtls_transport(), jsep_transport->media_transport());
Zhi Huangd2248f82018-04-10 14:41:03 -0700793}
794
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700795void JsepTransportController::RemoveTransportForMid(const std::string& mid) {
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -0800796 bool ret = config_.transport_observer->OnTransportChanged(mid, nullptr,
797 nullptr, nullptr);
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700798 // Calling OnTransportChanged with nullptr should always succeed, since it is
799 // only expected to fail when adding media to a transport (not removing).
800 RTC_DCHECK(ret);
Zhi Huangd2248f82018-04-10 14:41:03 -0700801 mid_to_transport_.erase(mid);
802}
803
Zhi Huange818b6e2018-02-22 15:26:27 -0800804cricket::JsepTransportDescription
805JsepTransportController::CreateJsepTransportDescription(
806 cricket::ContentInfo content_info,
807 cricket::TransportInfo transport_info,
Zhi Huange830e682018-03-30 10:48:35 -0700808 const std::vector<int>& encrypted_extension_ids,
809 int rtp_abs_sendtime_extn_id) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800810 const cricket::MediaContentDescription* content_desc =
811 static_cast<const cricket::MediaContentDescription*>(
812 content_info.description);
813 RTC_DCHECK(content_desc);
814 bool rtcp_mux_enabled = content_info.type == cricket::MediaProtocolType::kSctp
815 ? true
816 : content_desc->rtcp_mux();
817
818 return cricket::JsepTransportDescription(
819 rtcp_mux_enabled, content_desc->cryptos(), encrypted_extension_ids,
Zhi Huange830e682018-03-30 10:48:35 -0700820 rtp_abs_sendtime_extn_id, transport_info.description);
Zhi Huange818b6e2018-02-22 15:26:27 -0800821}
822
823bool JsepTransportController::ShouldUpdateBundleGroup(
824 SdpType type,
825 const cricket::SessionDescription* description) {
826 if (config_.bundle_policy ==
827 PeerConnectionInterface::kBundlePolicyMaxBundle) {
828 return true;
829 }
830
831 if (type != SdpType::kAnswer) {
832 return false;
833 }
834
835 RTC_DCHECK(local_desc_ && remote_desc_);
836 const cricket::ContentGroup* local_bundle =
837 local_desc_->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
838 const cricket::ContentGroup* remote_bundle =
839 remote_desc_->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
840 return local_bundle && remote_bundle;
841}
842
843std::vector<int> JsepTransportController::GetEncryptedHeaderExtensionIds(
844 const cricket::ContentInfo& content_info) {
845 const cricket::MediaContentDescription* content_desc =
846 static_cast<const cricket::MediaContentDescription*>(
847 content_info.description);
848
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700849 if (!config_.crypto_options.srtp.enable_encrypted_rtp_header_extensions) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800850 return std::vector<int>();
851 }
852
853 std::vector<int> encrypted_header_extension_ids;
854 for (auto extension : content_desc->rtp_header_extensions()) {
855 if (!extension.encrypt) {
856 continue;
857 }
858 auto it = std::find(encrypted_header_extension_ids.begin(),
859 encrypted_header_extension_ids.end(), extension.id);
860 if (it == encrypted_header_extension_ids.end()) {
861 encrypted_header_extension_ids.push_back(extension.id);
862 }
863 }
864 return encrypted_header_extension_ids;
865}
866
867std::vector<int>
868JsepTransportController::MergeEncryptedHeaderExtensionIdsForBundle(
869 const cricket::SessionDescription* description) {
870 RTC_DCHECK(description);
871 RTC_DCHECK(bundle_group_);
872
873 std::vector<int> merged_ids;
874 // Union the encrypted header IDs in the group when bundle is enabled.
875 for (const cricket::ContentInfo& content_info : description->contents()) {
876 if (bundle_group_->HasContentName(content_info.name)) {
877 std::vector<int> extension_ids =
878 GetEncryptedHeaderExtensionIds(content_info);
879 for (int id : extension_ids) {
880 auto it = std::find(merged_ids.begin(), merged_ids.end(), id);
881 if (it == merged_ids.end()) {
882 merged_ids.push_back(id);
883 }
884 }
885 }
886 }
887 return merged_ids;
888}
889
Zhi Huange830e682018-03-30 10:48:35 -0700890int JsepTransportController::GetRtpAbsSendTimeHeaderExtensionId(
Zhi Huange818b6e2018-02-22 15:26:27 -0800891 const cricket::ContentInfo& content_info) {
Zhi Huange830e682018-03-30 10:48:35 -0700892 if (!config_.enable_external_auth) {
893 return -1;
Zhi Huange818b6e2018-02-22 15:26:27 -0800894 }
895
896 const cricket::MediaContentDescription* content_desc =
897 static_cast<const cricket::MediaContentDescription*>(
898 content_info.description);
Zhi Huange830e682018-03-30 10:48:35 -0700899
900 const webrtc::RtpExtension* send_time_extension =
901 webrtc::RtpExtension::FindHeaderExtensionByUri(
902 content_desc->rtp_header_extensions(),
903 webrtc::RtpExtension::kAbsSendTimeUri);
904 return send_time_extension ? send_time_extension->id : -1;
905}
906
Zhi Huang365381f2018-04-13 16:44:34 -0700907const cricket::JsepTransport* JsepTransportController::GetJsepTransportForMid(
Zhi Huange830e682018-03-30 10:48:35 -0700908 const std::string& mid) const {
Zhi Huangd2248f82018-04-10 14:41:03 -0700909 auto it = mid_to_transport_.find(mid);
910 return it == mid_to_transport_.end() ? nullptr : it->second;
Zhi Huange830e682018-03-30 10:48:35 -0700911}
912
Zhi Huang365381f2018-04-13 16:44:34 -0700913cricket::JsepTransport* JsepTransportController::GetJsepTransportForMid(
Zhi Huange830e682018-03-30 10:48:35 -0700914 const std::string& mid) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700915 auto it = mid_to_transport_.find(mid);
916 return it == mid_to_transport_.end() ? nullptr : it->second;
Zhi Huange830e682018-03-30 10:48:35 -0700917}
918
Zhi Huang365381f2018-04-13 16:44:34 -0700919const cricket::JsepTransport* JsepTransportController::GetJsepTransportByName(
Zhi Huange830e682018-03-30 10:48:35 -0700920 const std::string& transport_name) const {
921 auto it = jsep_transports_by_name_.find(transport_name);
922 return (it == jsep_transports_by_name_.end()) ? nullptr : it->second.get();
923}
924
Zhi Huang365381f2018-04-13 16:44:34 -0700925cricket::JsepTransport* JsepTransportController::GetJsepTransportByName(
Zhi Huange830e682018-03-30 10:48:35 -0700926 const std::string& transport_name) {
927 auto it = jsep_transports_by_name_.find(transport_name);
928 return (it == jsep_transports_by_name_.end()) ? nullptr : it->second.get();
929}
930
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -0800931std::unique_ptr<webrtc::MediaTransportInterface>
932JsepTransportController::MaybeCreateMediaTransport(
933 const cricket::ContentInfo& content_info,
Anton Sukhanov7940da02018-10-10 10:34:49 -0700934 bool local,
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -0800935 cricket::IceTransportInternal* ice_transport) {
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700936 absl::optional<cricket::CryptoParams> selected_crypto_for_media_transport;
937 if (content_info.media_description() &&
938 !content_info.media_description()->cryptos().empty()) {
939 // Order of cryptos is deterministic (rfc4568, 5.1.1), so we just select the
940 // first one (in fact the first one should be the most preferred one.) We
941 // ignore the HMAC size, as media transport crypto settings currently don't
942 // expose HMAC size, nor crypto protocol for that matter.
943 selected_crypto_for_media_transport =
944 content_info.media_description()->cryptos()[0];
945 }
946
Anton Sukhanov7940da02018-10-10 10:34:49 -0700947 if (config_.media_transport_factory != nullptr) {
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700948 if (!selected_crypto_for_media_transport.has_value()) {
949 RTC_LOG(LS_WARNING) << "a=cryto line was not found in the offer. Most "
950 "likely you did not enable SDES. "
951 "Make sure to pass config.enable_dtls_srtp=false "
952 "to RTCConfiguration. "
953 "Cannot continue with media transport. Falling "
954 "back to RTP. is_local="
955 << local;
Anton Sukhanov7940da02018-10-10 10:34:49 -0700956
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700957 // Remove media_transport_factory from config, because we don't want to
958 // use it on the subsequent call (for the other side of the offer).
959 config_.media_transport_factory = nullptr;
960 } else {
961 // Note that we ignore here lifetime and length.
962 // In fact we take those bits (inline, lifetime and length) and keep it as
963 // part of key derivation.
964 //
965 // Technically, we are also not following rfc4568, which requires us to
966 // send and answer with the key that we chose. In practice, for media
967 // transport, the current approach should be sufficient (we take the key
968 // that sender offered, and caller assumes we will use it. We are not
969 // signaling back that we indeed used it.)
970 std::unique_ptr<rtc::KeyDerivation> key_derivation =
971 rtc::KeyDerivation::Create(rtc::KeyDerivationAlgorithm::HKDF_SHA256);
972 const std::string label = "MediaTransportLabel";
973 constexpr int kDerivedKeyByteSize = 32;
Anton Sukhanov7940da02018-10-10 10:34:49 -0700974
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700975 int key_len, salt_len;
976 if (!rtc::GetSrtpKeyAndSaltLengths(
977 rtc::SrtpCryptoSuiteFromName(
978 selected_crypto_for_media_transport.value().cipher_suite),
979 &key_len, &salt_len)) {
980 RTC_CHECK(false) << "Cannot set up secure media transport";
981 }
982 rtc::ZeroOnFreeBuffer<uint8_t> raw_key(key_len + salt_len);
983
984 cricket::SrtpFilter::ParseKeyParams(
985 selected_crypto_for_media_transport.value().key_params,
986 raw_key.data(), raw_key.size());
987 absl::optional<rtc::ZeroOnFreeBuffer<uint8_t>> key =
988 key_derivation->DeriveKey(
989 raw_key,
990 /*salt=*/nullptr,
991 rtc::ArrayView<const uint8_t>(
992 reinterpret_cast<const uint8_t*>(label.data()), label.size()),
993 kDerivedKeyByteSize);
994
995 // We want to crash the app if we don't have a key, and not silently fall
996 // back to the unsecure communication.
997 RTC_CHECK(key.has_value());
998 MediaTransportSettings settings;
999 settings.is_caller = local;
1000 settings.pre_shared_key =
1001 std::string(reinterpret_cast<const char*>(key.value().data()),
1002 key.value().size());
Piotr (Peter) Slatala0c022502018-12-28 10:39:39 -08001003 settings.event_log = config_.event_log;
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -07001004 auto media_transport_result =
1005 config_.media_transport_factory->CreateMediaTransport(
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001006 ice_transport, network_thread_, settings);
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -07001007
1008 // TODO(sukhanov): Proper error handling.
1009 RTC_CHECK(media_transport_result.ok());
1010
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001011 return media_transport_result.MoveValue();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -07001012 }
Anton Sukhanov7940da02018-10-10 10:34:49 -07001013 }
1014
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001015 return nullptr;
1016}
1017
1018RTCError JsepTransportController::MaybeCreateJsepTransport(
1019 bool local,
1020 const cricket::ContentInfo& content_info) {
1021 RTC_DCHECK(network_thread_->IsCurrent());
1022 cricket::JsepTransport* transport = GetJsepTransportByName(content_info.name);
1023 if (transport) {
1024 return RTCError::OK();
1025 }
1026
1027 const cricket::MediaContentDescription* content_desc =
1028 static_cast<const cricket::MediaContentDescription*>(
1029 content_info.description);
1030 if (certificate_ && !content_desc->cryptos().empty()) {
1031 return RTCError(RTCErrorType::INVALID_PARAMETER,
1032 "SDES and DTLS-SRTP cannot be enabled at the same time.");
1033 }
1034
1035 std::unique_ptr<cricket::DtlsTransportInternal> rtp_dtls_transport =
1036 CreateDtlsTransport(content_info.name, /*rtcp =*/false);
1037
1038 std::unique_ptr<cricket::DtlsTransportInternal> rtcp_dtls_transport;
1039 std::unique_ptr<RtpTransport> unencrypted_rtp_transport;
1040 std::unique_ptr<SrtpTransport> sdes_transport;
1041 std::unique_ptr<DtlsSrtpTransport> dtls_srtp_transport;
1042 std::unique_ptr<MediaTransportInterface> media_transport;
1043
1044 if (config_.rtcp_mux_policy !=
1045 PeerConnectionInterface::kRtcpMuxPolicyRequire &&
1046 content_info.type == cricket::MediaProtocolType::kRtp) {
1047 rtcp_dtls_transport =
1048 CreateDtlsTransport(content_info.name, /*rtcp =*/true);
1049 }
1050 media_transport = MaybeCreateMediaTransport(
1051 content_info, local, rtp_dtls_transport->ice_transport());
1052
Anton Sukhanov7940da02018-10-10 10:34:49 -07001053 // TODO(sukhanov): Do not create RTP/RTCP transports if media transport is
1054 // used.
Zhi Huange818b6e2018-02-22 15:26:27 -08001055 if (config_.disable_encryption) {
1056 unencrypted_rtp_transport = CreateUnencryptedRtpTransport(
Zhi Huangd2248f82018-04-10 14:41:03 -07001057 content_info.name, rtp_dtls_transport.get(), rtcp_dtls_transport.get());
Zhi Huange818b6e2018-02-22 15:26:27 -08001058 } else if (!content_desc->cryptos().empty()) {
Zhi Huangd2248f82018-04-10 14:41:03 -07001059 sdes_transport = CreateSdesTransport(
1060 content_info.name, rtp_dtls_transport.get(), rtcp_dtls_transport.get());
Zhi Huange818b6e2018-02-22 15:26:27 -08001061 } else {
Zhi Huangd2248f82018-04-10 14:41:03 -07001062 dtls_srtp_transport = CreateDtlsSrtpTransport(
1063 content_info.name, rtp_dtls_transport.get(), rtcp_dtls_transport.get());
Zhi Huange818b6e2018-02-22 15:26:27 -08001064 }
1065
Zhi Huang365381f2018-04-13 16:44:34 -07001066 std::unique_ptr<cricket::JsepTransport> jsep_transport =
Karl Wiberg918f50c2018-07-05 11:40:33 +02001067 absl::make_unique<cricket::JsepTransport>(
Zhi Huangd2248f82018-04-10 14:41:03 -07001068 content_info.name, certificate_, std::move(unencrypted_rtp_transport),
Zhi Huange818b6e2018-02-22 15:26:27 -08001069 std::move(sdes_transport), std::move(dtls_srtp_transport),
Anton Sukhanov7940da02018-10-10 10:34:49 -07001070 std::move(rtp_dtls_transport), std::move(rtcp_dtls_transport),
1071 std::move(media_transport));
Zhi Huange818b6e2018-02-22 15:26:27 -08001072 jsep_transport->SignalRtcpMuxActive.connect(
1073 this, &JsepTransportController::UpdateAggregateStates_n);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001074 jsep_transport->SignalMediaTransportStateChanged.connect(
Bjorn Mellem175aa2e2018-11-08 11:23:22 -08001075 this, &JsepTransportController::OnMediaTransportStateChanged_n);
Taylor Brandstettercbaa2542018-04-16 16:42:14 -07001076 SetTransportForMid(content_info.name, jsep_transport.get());
Zhi Huange830e682018-03-30 10:48:35 -07001077
Zhi Huangd2248f82018-04-10 14:41:03 -07001078 jsep_transports_by_name_[content_info.name] = std::move(jsep_transport);
1079 UpdateAggregateStates_n();
Zhi Huange830e682018-03-30 10:48:35 -07001080 return RTCError::OK();
Zhi Huange818b6e2018-02-22 15:26:27 -08001081}
1082
1083void JsepTransportController::MaybeDestroyJsepTransport(
1084 const std::string& mid) {
Zhi Huangd2248f82018-04-10 14:41:03 -07001085 auto jsep_transport = GetJsepTransportByName(mid);
1086 if (!jsep_transport) {
1087 return;
1088 }
1089
1090 // Don't destroy the JsepTransport if there are still media sections referring
1091 // to it.
1092 for (const auto& kv : mid_to_transport_) {
1093 if (kv.second == jsep_transport) {
1094 return;
1095 }
1096 }
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -08001097
Zhi Huange830e682018-03-30 10:48:35 -07001098 jsep_transports_by_name_.erase(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -08001099 UpdateAggregateStates_n();
1100}
1101
1102void JsepTransportController::DestroyAllJsepTransports_n() {
1103 RTC_DCHECK(network_thread_->IsCurrent());
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -08001104
1105 for (const auto& jsep_transport : jsep_transports_by_name_) {
1106 config_.transport_observer->OnTransportChanged(jsep_transport.first,
1107 nullptr, nullptr, nullptr);
1108 }
1109
Zhi Huange830e682018-03-30 10:48:35 -07001110 jsep_transports_by_name_.clear();
Zhi Huange818b6e2018-02-22 15:26:27 -08001111}
1112
1113void JsepTransportController::SetIceRole_n(cricket::IceRole ice_role) {
1114 RTC_DCHECK(network_thread_->IsCurrent());
1115
1116 ice_role_ = ice_role;
1117 for (auto& dtls : GetDtlsTransports()) {
1118 dtls->ice_transport()->SetIceRole(ice_role_);
1119 }
1120}
1121
1122cricket::IceRole JsepTransportController::DetermineIceRole(
Zhi Huang365381f2018-04-13 16:44:34 -07001123 cricket::JsepTransport* jsep_transport,
Zhi Huange818b6e2018-02-22 15:26:27 -08001124 const cricket::TransportInfo& transport_info,
1125 SdpType type,
1126 bool local) {
1127 cricket::IceRole ice_role = ice_role_;
1128 auto tdesc = transport_info.description;
1129 if (local) {
1130 // The initial offer side may use ICE Lite, in which case, per RFC5245
1131 // Section 5.1.1, the answer side should take the controlling role if it is
1132 // in the full ICE mode.
1133 //
1134 // When both sides use ICE Lite, the initial offer side must take the
1135 // controlling role, and this is the default logic implemented in
1136 // SetLocalDescription in JsepTransportController.
1137 if (jsep_transport->remote_description() &&
1138 jsep_transport->remote_description()->transport_desc.ice_mode ==
1139 cricket::ICEMODE_LITE &&
1140 ice_role_ == cricket::ICEROLE_CONTROLLED &&
1141 tdesc.ice_mode == cricket::ICEMODE_FULL) {
1142 ice_role = cricket::ICEROLE_CONTROLLING;
1143 }
1144
1145 // Older versions of Chrome expect the ICE role to be re-determined when an
1146 // ICE restart occurs, and also don't perform conflict resolution correctly,
1147 // so for now we can't safely stop doing this, unless the application opts
1148 // in by setting |config_.redetermine_role_on_ice_restart_| to false. See:
1149 // https://bugs.chromium.org/p/chromium/issues/detail?id=628676
1150 // TODO(deadbeef): Remove this when these old versions of Chrome reach a low
1151 // enough population.
1152 if (config_.redetermine_role_on_ice_restart &&
1153 jsep_transport->local_description() &&
1154 cricket::IceCredentialsChanged(
1155 jsep_transport->local_description()->transport_desc.ice_ufrag,
1156 jsep_transport->local_description()->transport_desc.ice_pwd,
1157 tdesc.ice_ufrag, tdesc.ice_pwd) &&
1158 // Don't change the ICE role if the remote endpoint is ICE lite; we
1159 // should always be controlling in that case.
1160 (!jsep_transport->remote_description() ||
1161 jsep_transport->remote_description()->transport_desc.ice_mode !=
1162 cricket::ICEMODE_LITE)) {
1163 ice_role = (type == SdpType::kOffer) ? cricket::ICEROLE_CONTROLLING
1164 : cricket::ICEROLE_CONTROLLED;
1165 }
1166 } else {
1167 // If our role is cricket::ICEROLE_CONTROLLED and the remote endpoint
1168 // supports only ice_lite, this local endpoint should take the CONTROLLING
1169 // role.
1170 // TODO(deadbeef): This is a session-level attribute, so it really shouldn't
1171 // be in a TransportDescription in the first place...
1172 if (ice_role_ == cricket::ICEROLE_CONTROLLED &&
1173 tdesc.ice_mode == cricket::ICEMODE_LITE) {
1174 ice_role = cricket::ICEROLE_CONTROLLING;
1175 }
1176
1177 // If we use ICE Lite and the remote endpoint uses the full implementation
1178 // of ICE, the local endpoint must take the controlled role, and the other
1179 // side must be the controlling role.
1180 if (jsep_transport->local_description() &&
1181 jsep_transport->local_description()->transport_desc.ice_mode ==
1182 cricket::ICEMODE_LITE &&
1183 ice_role_ == cricket::ICEROLE_CONTROLLING &&
Zhi Huange830e682018-03-30 10:48:35 -07001184 tdesc.ice_mode == cricket::ICEMODE_FULL) {
Zhi Huange818b6e2018-02-22 15:26:27 -08001185 ice_role = cricket::ICEROLE_CONTROLLED;
1186 }
1187 }
1188
1189 return ice_role;
1190}
1191
1192void JsepTransportController::OnTransportWritableState_n(
1193 rtc::PacketTransportInternal* transport) {
1194 RTC_DCHECK(network_thread_->IsCurrent());
1195 RTC_LOG(LS_INFO) << " Transport " << transport->transport_name()
1196 << " writability changed to " << transport->writable()
1197 << ".";
1198 UpdateAggregateStates_n();
1199}
1200
1201void JsepTransportController::OnTransportReceivingState_n(
1202 rtc::PacketTransportInternal* transport) {
1203 RTC_DCHECK(network_thread_->IsCurrent());
1204 UpdateAggregateStates_n();
1205}
1206
1207void JsepTransportController::OnTransportGatheringState_n(
1208 cricket::IceTransportInternal* transport) {
1209 RTC_DCHECK(network_thread_->IsCurrent());
1210 UpdateAggregateStates_n();
1211}
1212
1213void JsepTransportController::OnTransportCandidateGathered_n(
1214 cricket::IceTransportInternal* transport,
1215 const cricket::Candidate& candidate) {
1216 RTC_DCHECK(network_thread_->IsCurrent());
1217
1218 // We should never signal peer-reflexive candidates.
1219 if (candidate.type() == cricket::PRFLX_PORT_TYPE) {
1220 RTC_NOTREACHED();
1221 return;
1222 }
Steve Antond25828a2018-08-31 13:06:05 -07001223 std::string transport_name = transport->transport_name();
1224 invoker_.AsyncInvoke<void>(
1225 RTC_FROM_HERE, signaling_thread_, [this, transport_name, candidate] {
1226 SignalIceCandidatesGathered(transport_name, {candidate});
1227 });
Zhi Huange818b6e2018-02-22 15:26:27 -08001228}
1229
1230void JsepTransportController::OnTransportCandidatesRemoved_n(
1231 cricket::IceTransportInternal* transport,
1232 const cricket::Candidates& candidates) {
1233 invoker_.AsyncInvoke<void>(
1234 RTC_FROM_HERE, signaling_thread_,
Steve Antond25828a2018-08-31 13:06:05 -07001235 [this, candidates] { SignalIceCandidatesRemoved(candidates); });
Zhi Huange818b6e2018-02-22 15:26:27 -08001236}
1237
1238void JsepTransportController::OnTransportRoleConflict_n(
1239 cricket::IceTransportInternal* transport) {
1240 RTC_DCHECK(network_thread_->IsCurrent());
1241 // Note: since the role conflict is handled entirely on the network thread,
1242 // we don't need to worry about role conflicts occurring on two ports at
1243 // once. The first one encountered should immediately reverse the role.
1244 cricket::IceRole reversed_role = (ice_role_ == cricket::ICEROLE_CONTROLLING)
1245 ? cricket::ICEROLE_CONTROLLED
1246 : cricket::ICEROLE_CONTROLLING;
1247 RTC_LOG(LS_INFO) << "Got role conflict; switching to "
1248 << (reversed_role == cricket::ICEROLE_CONTROLLING
1249 ? "controlling"
1250 : "controlled")
1251 << " role.";
1252 SetIceRole_n(reversed_role);
1253}
1254
1255void JsepTransportController::OnTransportStateChanged_n(
1256 cricket::IceTransportInternal* transport) {
1257 RTC_DCHECK(network_thread_->IsCurrent());
1258 RTC_LOG(LS_INFO) << transport->transport_name() << " Transport "
1259 << transport->component()
1260 << " state changed. Check if state is complete.";
1261 UpdateAggregateStates_n();
1262}
1263
Bjorn Mellem175aa2e2018-11-08 11:23:22 -08001264void JsepTransportController::OnMediaTransportStateChanged_n() {
1265 SignalMediaTransportStateChanged();
1266 UpdateAggregateStates_n();
1267}
1268
Zhi Huange818b6e2018-02-22 15:26:27 -08001269void JsepTransportController::UpdateAggregateStates_n() {
1270 RTC_DCHECK(network_thread_->IsCurrent());
1271
1272 auto dtls_transports = GetDtlsTransports();
Alex Loiko9289eda2018-11-23 16:18:59 +00001273 cricket::IceConnectionState new_connection_state =
1274 cricket::kIceConnectionConnecting;
Jonas Olsson635474e2018-10-18 15:58:17 +02001275 PeerConnectionInterface::IceConnectionState new_ice_connection_state =
1276 PeerConnectionInterface::IceConnectionState::kIceConnectionNew;
1277 PeerConnectionInterface::PeerConnectionState new_combined_state =
1278 PeerConnectionInterface::PeerConnectionState::kNew;
Zhi Huange818b6e2018-02-22 15:26:27 -08001279 cricket::IceGatheringState new_gathering_state = cricket::kIceGatheringNew;
Alex Loiko9289eda2018-11-23 16:18:59 +00001280 bool any_failed = false;
1281
1282 // TODO(http://bugs.webrtc.org/9719) If(when) media_transport disables
1283 // dtls_transports entirely, the below line will have to be changed to account
1284 // for the fact that dtls transports might be absent.
1285 bool all_connected = !dtls_transports.empty();
1286 bool all_completed = !dtls_transports.empty();
Zhi Huange818b6e2018-02-22 15:26:27 -08001287 bool any_gathering = false;
1288 bool all_done_gathering = !dtls_transports.empty();
Jonas Olsson635474e2018-10-18 15:58:17 +02001289
1290 std::map<IceTransportState, int> ice_state_counts;
1291 std::map<cricket::DtlsTransportState, int> dtls_state_counts;
1292
Zhi Huange818b6e2018-02-22 15:26:27 -08001293 for (const auto& dtls : dtls_transports) {
Alex Loiko9289eda2018-11-23 16:18:59 +00001294 any_failed = any_failed || dtls->ice_transport()->GetState() ==
1295 cricket::IceTransportState::STATE_FAILED;
1296 all_connected = all_connected && dtls->writable();
1297 all_completed =
1298 all_completed && dtls->writable() &&
1299 dtls->ice_transport()->GetState() ==
1300 cricket::IceTransportState::STATE_COMPLETED &&
1301 dtls->ice_transport()->GetIceRole() == cricket::ICEROLE_CONTROLLING &&
1302 dtls->ice_transport()->gathering_state() ==
1303 cricket::kIceGatheringComplete;
Zhi Huange818b6e2018-02-22 15:26:27 -08001304 any_gathering = any_gathering || dtls->ice_transport()->gathering_state() !=
1305 cricket::kIceGatheringNew;
1306 all_done_gathering =
1307 all_done_gathering && dtls->ice_transport()->gathering_state() ==
1308 cricket::kIceGatheringComplete;
Jonas Olsson635474e2018-10-18 15:58:17 +02001309
1310 dtls_state_counts[dtls->dtls_state()]++;
1311 ice_state_counts[dtls->ice_transport()->GetIceTransportState()]++;
Zhi Huange818b6e2018-02-22 15:26:27 -08001312 }
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001313
Alex Loiko9289eda2018-11-23 16:18:59 +00001314 for (auto it = jsep_transports_by_name_.begin();
1315 it != jsep_transports_by_name_.end(); ++it) {
1316 auto jsep_transport = it->second.get();
1317 if (!jsep_transport->media_transport()) {
1318 continue;
1319 }
1320
1321 // There is no 'kIceConnectionDisconnected', so we only need to handle
1322 // connected and completed.
1323 // We treat kClosed as failed, because if it happens before shutting down
1324 // media transports it means that there was a failure.
1325 // MediaTransportInterface allows to flip back and forth between kWritable
1326 // and kPending, but there does not exist an implementation that does that,
1327 // and the contract of jsep transport controller doesn't quite expect that.
1328 // When this happens, we would go from connected to connecting state, but
1329 // this may change in future.
1330 any_failed |= jsep_transport->media_transport_state() ==
1331 webrtc::MediaTransportState::kClosed;
1332 all_completed &= jsep_transport->media_transport_state() ==
1333 webrtc::MediaTransportState::kWritable;
1334 all_connected &= jsep_transport->media_transport_state() ==
1335 webrtc::MediaTransportState::kWritable;
1336 }
1337
1338 if (any_failed) {
1339 new_connection_state = cricket::kIceConnectionFailed;
1340 } else if (all_completed) {
1341 new_connection_state = cricket::kIceConnectionCompleted;
1342 } else if (all_connected) {
1343 new_connection_state = cricket::kIceConnectionConnected;
1344 }
1345 if (ice_connection_state_ != new_connection_state) {
1346 ice_connection_state_ = new_connection_state;
1347 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_,
1348 [this, new_connection_state] {
1349 SignalIceConnectionState(new_connection_state);
1350 });
1351 }
1352
Jonas Olsson635474e2018-10-18 15:58:17 +02001353 // Compute the current RTCIceConnectionState as described in
1354 // https://www.w3.org/TR/webrtc/#dom-rtciceconnectionstate.
1355 // The PeerConnection is responsible for handling the "closed" state.
1356 int total_ice_checking = ice_state_counts[IceTransportState::kChecking];
1357 int total_ice_connected = ice_state_counts[IceTransportState::kConnected];
1358 int total_ice_completed = ice_state_counts[IceTransportState::kCompleted];
1359 int total_ice_failed = ice_state_counts[IceTransportState::kFailed];
1360 int total_ice_disconnected =
1361 ice_state_counts[IceTransportState::kDisconnected];
1362 int total_ice_closed = ice_state_counts[IceTransportState::kClosed];
1363 int total_ice_new = ice_state_counts[IceTransportState::kNew];
1364 int total_ice = dtls_transports.size();
1365
1366 if (total_ice_failed > 0) {
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001367 // Any RTCIceTransports are in the "failed" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001368 new_ice_connection_state = PeerConnectionInterface::kIceConnectionFailed;
Alex Loiko9289eda2018-11-23 16:18:59 +00001369 } else if (total_ice_disconnected > 0) {
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001370 // None of the previous states apply and any RTCIceTransports are in the
1371 // "disconnected" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001372 new_ice_connection_state =
1373 PeerConnectionInterface::kIceConnectionDisconnected;
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001374 } else if (total_ice_new + total_ice_closed == total_ice) {
1375 // None of the previous states apply and all RTCIceTransports are in the
1376 // "new" or "closed" state, or there are no transports.
1377 new_ice_connection_state = PeerConnectionInterface::kIceConnectionNew;
1378 } else if (total_ice_new + total_ice_checking > 0) {
1379 // None of the previous states apply and any RTCIceTransports are in the
1380 // "new" or "checking" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001381 new_ice_connection_state = PeerConnectionInterface::kIceConnectionChecking;
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001382 } else if (total_ice_completed + total_ice_closed == total_ice) {
1383 // None of the previous states apply and all RTCIceTransports are in the
1384 // "completed" or "closed" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001385 new_ice_connection_state = PeerConnectionInterface::kIceConnectionCompleted;
1386 } else if (total_ice_connected + total_ice_completed + total_ice_closed ==
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001387 total_ice) {
1388 // None of the previous states apply and all RTCIceTransports are in the
1389 // "connected", "completed" or "closed" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001390 new_ice_connection_state = PeerConnectionInterface::kIceConnectionConnected;
Jonas Olsson635474e2018-10-18 15:58:17 +02001391 } else {
1392 RTC_NOTREACHED();
1393 }
1394
Alex Loiko9289eda2018-11-23 16:18:59 +00001395 if (standardized_ice_connection_state_ != new_ice_connection_state) {
1396 standardized_ice_connection_state_ = new_ice_connection_state;
Jonas Olsson635474e2018-10-18 15:58:17 +02001397 invoker_.AsyncInvoke<void>(
1398 RTC_FROM_HERE, signaling_thread_, [this, new_ice_connection_state] {
Alex Loiko9289eda2018-11-23 16:18:59 +00001399 SignalStandardizedIceConnectionState(new_ice_connection_state);
Jonas Olsson635474e2018-10-18 15:58:17 +02001400 });
1401 }
1402
1403 // Compute the current RTCPeerConnectionState as described in
1404 // https://www.w3.org/TR/webrtc/#dom-rtcpeerconnectionstate.
1405 // The PeerConnection is responsible for handling the "closed" state.
1406 // Note that "connecting" is only a valid state for DTLS transports while
1407 // "checking", "completed" and "disconnected" are only valid for ICE
1408 // transports.
1409 int total_connected = total_ice_connected +
1410 dtls_state_counts[cricket::DTLS_TRANSPORT_CONNECTED];
1411 int total_dtls_connecting =
1412 dtls_state_counts[cricket::DTLS_TRANSPORT_CONNECTING];
1413 int total_failed =
1414 total_ice_failed + dtls_state_counts[cricket::DTLS_TRANSPORT_FAILED];
1415 int total_closed =
1416 total_ice_closed + dtls_state_counts[cricket::DTLS_TRANSPORT_CLOSED];
1417 int total_new =
1418 total_ice_new + dtls_state_counts[cricket::DTLS_TRANSPORT_NEW];
1419 int total_transports = total_ice * 2;
1420
1421 if (total_failed > 0) {
1422 // Any of the RTCIceTransports or RTCDtlsTransports are in a "failed" state.
1423 new_combined_state = PeerConnectionInterface::PeerConnectionState::kFailed;
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001424 } else if (total_ice_disconnected > 0) {
1425 // None of the previous states apply and any RTCIceTransports or
1426 // RTCDtlsTransports are in the "disconnected" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001427 new_combined_state =
1428 PeerConnectionInterface::PeerConnectionState::kDisconnected;
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001429 } else if (total_new + total_closed == total_transports) {
1430 // None of the previous states apply and all RTCIceTransports and
1431 // RTCDtlsTransports are in the "new" or "closed" state, or there are no
1432 // transports.
1433 new_combined_state = PeerConnectionInterface::PeerConnectionState::kNew;
1434 } else if (total_new + total_dtls_connecting + total_ice_checking > 0) {
1435 // None of the previous states apply and all RTCIceTransports or
1436 // RTCDtlsTransports are in the "new", "connecting" or "checking" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001437 new_combined_state =
1438 PeerConnectionInterface::PeerConnectionState::kConnecting;
1439 } else if (total_connected + total_ice_completed + total_closed ==
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001440 total_transports) {
1441 // None of the previous states apply and all RTCIceTransports and
1442 // RTCDtlsTransports are in the "connected", "completed" or "closed" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001443 new_combined_state =
1444 PeerConnectionInterface::PeerConnectionState::kConnected;
Jonas Olsson635474e2018-10-18 15:58:17 +02001445 } else {
1446 RTC_NOTREACHED();
1447 }
1448
1449 if (combined_connection_state_ != new_combined_state) {
1450 combined_connection_state_ = new_combined_state;
1451 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_,
1452 [this, new_combined_state] {
1453 SignalConnectionState(new_combined_state);
1454 });
1455 }
1456
Zhi Huange818b6e2018-02-22 15:26:27 -08001457 if (all_done_gathering) {
1458 new_gathering_state = cricket::kIceGatheringComplete;
1459 } else if (any_gathering) {
1460 new_gathering_state = cricket::kIceGatheringGathering;
1461 }
1462 if (ice_gathering_state_ != new_gathering_state) {
1463 ice_gathering_state_ = new_gathering_state;
Steve Antond25828a2018-08-31 13:06:05 -07001464 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_,
1465 [this, new_gathering_state] {
1466 SignalIceGatheringState(new_gathering_state);
1467 });
Zhi Huange818b6e2018-02-22 15:26:27 -08001468 }
1469}
1470
1471void JsepTransportController::OnDtlsHandshakeError(
1472 rtc::SSLHandshakeError error) {
1473 SignalDtlsHandshakeError(error);
1474}
1475
1476} // namespace webrtc