blob: 78ecaf31deac4e41e8db488a0df6ca81504d2cb7 [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
11#include "pc/jseptransportcontroller.h"
12
13#include <algorithm>
14#include <memory>
15#include <utility>
16
17#include "p2p/base/port.h"
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -070018#include "pc/srtpfilter.h"
Zhi Huange818b6e2018-02-22 15:26:27 -080019#include "rtc_base/bind.h"
20#include "rtc_base/checks.h"
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -070021#include "rtc_base/key_derivation.h"
Zhi Huange818b6e2018-02-22 15:26:27 -080022#include "rtc_base/thread.h"
23
24using webrtc::SdpType;
25
26namespace {
27
Zhi Huange818b6e2018-02-22 15:26:27 -080028webrtc::RTCError VerifyCandidate(const cricket::Candidate& cand) {
29 // No address zero.
30 if (cand.address().IsNil() || cand.address().IsAnyIP()) {
31 return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
32 "candidate has address of zero");
33 }
34
35 // Disallow all ports below 1024, except for 80 and 443 on public addresses.
36 int port = cand.address().port();
37 if (cand.protocol() == cricket::TCP_PROTOCOL_NAME &&
38 (cand.tcptype() == cricket::TCPTYPE_ACTIVE_STR || port == 0)) {
39 // Expected for active-only candidates per
40 // http://tools.ietf.org/html/rfc6544#section-4.5 so no error.
41 // Libjingle clients emit port 0, in "active" mode.
42 return webrtc::RTCError::OK();
43 }
44 if (port < 1024) {
45 if ((port != 80) && (port != 443)) {
46 return webrtc::RTCError(
47 webrtc::RTCErrorType::INVALID_PARAMETER,
48 "candidate has port below 1024, but not 80 or 443");
49 }
50
51 if (cand.address().IsPrivateIP()) {
52 return webrtc::RTCError(
53 webrtc::RTCErrorType::INVALID_PARAMETER,
54 "candidate has port of 80 or 443 with private IP address");
55 }
56 }
57
58 return webrtc::RTCError::OK();
59}
60
61webrtc::RTCError VerifyCandidates(const cricket::Candidates& candidates) {
62 for (const cricket::Candidate& candidate : candidates) {
63 webrtc::RTCError error = VerifyCandidate(candidate);
64 if (!error.ok()) {
65 return error;
66 }
67 }
68 return webrtc::RTCError::OK();
69}
70
71} // namespace
72
73namespace webrtc {
74
75JsepTransportController::JsepTransportController(
76 rtc::Thread* signaling_thread,
77 rtc::Thread* network_thread,
78 cricket::PortAllocator* port_allocator,
Zach Steine20867f2018-08-02 13:20:15 -070079 AsyncResolverFactory* async_resolver_factory,
Zhi Huange818b6e2018-02-22 15:26:27 -080080 Config config)
81 : signaling_thread_(signaling_thread),
82 network_thread_(network_thread),
83 port_allocator_(port_allocator),
Zach Steine20867f2018-08-02 13:20:15 -070084 async_resolver_factory_(async_resolver_factory),
Zhi Huang365381f2018-04-13 16:44:34 -070085 config_(config) {
86 // The |transport_observer| is assumed to be non-null.
87 RTC_DCHECK(config_.transport_observer);
88}
Zhi Huange818b6e2018-02-22 15:26:27 -080089
90JsepTransportController::~JsepTransportController() {
91 // Channel destructors may try to send packets, so this needs to happen on
92 // the network thread.
93 network_thread_->Invoke<void>(
94 RTC_FROM_HERE,
95 rtc::Bind(&JsepTransportController::DestroyAllJsepTransports_n, this));
96}
97
98RTCError JsepTransportController::SetLocalDescription(
99 SdpType type,
100 const cricket::SessionDescription* description) {
101 if (!network_thread_->IsCurrent()) {
102 return network_thread_->Invoke<RTCError>(
103 RTC_FROM_HERE, [=] { return SetLocalDescription(type, description); });
104 }
105
106 if (!initial_offerer_.has_value()) {
107 initial_offerer_.emplace(type == SdpType::kOffer);
108 if (*initial_offerer_) {
109 SetIceRole_n(cricket::ICEROLE_CONTROLLING);
110 } else {
111 SetIceRole_n(cricket::ICEROLE_CONTROLLED);
112 }
113 }
114 return ApplyDescription_n(/*local=*/true, type, description);
115}
116
117RTCError JsepTransportController::SetRemoteDescription(
118 SdpType type,
119 const cricket::SessionDescription* description) {
120 if (!network_thread_->IsCurrent()) {
121 return network_thread_->Invoke<RTCError>(
122 RTC_FROM_HERE, [=] { return SetRemoteDescription(type, description); });
123 }
124
125 return ApplyDescription_n(/*local=*/false, type, description);
126}
127
128RtpTransportInternal* JsepTransportController::GetRtpTransport(
129 const std::string& mid) const {
Zhi Huange830e682018-03-30 10:48:35 -0700130 auto jsep_transport = GetJsepTransportForMid(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -0800131 if (!jsep_transport) {
132 return nullptr;
133 }
134 return jsep_transport->rtp_transport();
135}
136
Anton Sukhanov7940da02018-10-10 10:34:49 -0700137MediaTransportInterface* JsepTransportController::GetMediaTransport(
138 const std::string& mid) const {
139 auto jsep_transport = GetJsepTransportForMid(mid);
140 if (!jsep_transport) {
141 return nullptr;
142 }
143 return jsep_transport->media_transport();
144}
145
Bjorn Mellem175aa2e2018-11-08 11:23:22 -0800146MediaTransportState JsepTransportController::GetMediaTransportState(
147 const std::string& mid) const {
148 auto jsep_transport = GetJsepTransportForMid(mid);
149 if (!jsep_transport) {
150 return MediaTransportState::kPending;
151 }
152 return jsep_transport->media_transport_state();
153}
154
Zhi Huange818b6e2018-02-22 15:26:27 -0800155cricket::DtlsTransportInternal* JsepTransportController::GetDtlsTransport(
156 const std::string& mid) const {
Zhi Huange830e682018-03-30 10:48:35 -0700157 auto jsep_transport = GetJsepTransportForMid(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -0800158 if (!jsep_transport) {
159 return nullptr;
160 }
161 return jsep_transport->rtp_dtls_transport();
162}
163
164cricket::DtlsTransportInternal* JsepTransportController::GetRtcpDtlsTransport(
165 const std::string& mid) const {
Zhi Huange830e682018-03-30 10:48:35 -0700166 auto jsep_transport = GetJsepTransportForMid(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -0800167 if (!jsep_transport) {
168 return nullptr;
169 }
170 return jsep_transport->rtcp_dtls_transport();
171}
172
173void JsepTransportController::SetIceConfig(const cricket::IceConfig& config) {
174 if (!network_thread_->IsCurrent()) {
175 network_thread_->Invoke<void>(RTC_FROM_HERE, [&] { SetIceConfig(config); });
176 return;
177 }
178
179 ice_config_ = config;
180 for (auto& dtls : GetDtlsTransports()) {
181 dtls->ice_transport()->SetIceConfig(ice_config_);
182 }
183}
184
185void JsepTransportController::SetNeedsIceRestartFlag() {
Zhi Huange830e682018-03-30 10:48:35 -0700186 for (auto& kv : jsep_transports_by_name_) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800187 kv.second->SetNeedsIceRestartFlag();
188 }
189}
190
191bool JsepTransportController::NeedsIceRestart(
192 const std::string& transport_name) const {
Zhi Huang365381f2018-04-13 16:44:34 -0700193 const cricket::JsepTransport* transport =
Zhi Huange830e682018-03-30 10:48:35 -0700194 GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800195 if (!transport) {
196 return false;
197 }
198 return transport->needs_ice_restart();
199}
200
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200201absl::optional<rtc::SSLRole> JsepTransportController::GetDtlsRole(
Zhi Huange830e682018-03-30 10:48:35 -0700202 const std::string& mid) const {
Zhi Huange818b6e2018-02-22 15:26:27 -0800203 if (!network_thread_->IsCurrent()) {
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200204 return network_thread_->Invoke<absl::optional<rtc::SSLRole>>(
Zhi Huange830e682018-03-30 10:48:35 -0700205 RTC_FROM_HERE, [&] { return GetDtlsRole(mid); });
Zhi Huange818b6e2018-02-22 15:26:27 -0800206 }
207
Zhi Huang365381f2018-04-13 16:44:34 -0700208 const cricket::JsepTransport* t = GetJsepTransportForMid(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -0800209 if (!t) {
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200210 return absl::optional<rtc::SSLRole>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800211 }
212 return t->GetDtlsRole();
213}
214
215bool JsepTransportController::SetLocalCertificate(
216 const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) {
217 if (!network_thread_->IsCurrent()) {
218 return network_thread_->Invoke<bool>(
219 RTC_FROM_HERE, [&] { return SetLocalCertificate(certificate); });
220 }
221
222 // Can't change a certificate, or set a null certificate.
223 if (certificate_ || !certificate) {
224 return false;
225 }
226 certificate_ = certificate;
227
228 // Set certificate for JsepTransport, which verifies it matches the
229 // fingerprint in SDP, and DTLS transport.
230 // Fallback from DTLS to SDES is not supported.
Zhi Huange830e682018-03-30 10:48:35 -0700231 for (auto& kv : jsep_transports_by_name_) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800232 kv.second->SetLocalCertificate(certificate_);
233 }
234 for (auto& dtls : GetDtlsTransports()) {
235 bool set_cert_success = dtls->SetLocalCertificate(certificate_);
236 RTC_DCHECK(set_cert_success);
237 }
238 return true;
239}
240
241rtc::scoped_refptr<rtc::RTCCertificate>
242JsepTransportController::GetLocalCertificate(
243 const std::string& transport_name) const {
244 if (!network_thread_->IsCurrent()) {
245 return network_thread_->Invoke<rtc::scoped_refptr<rtc::RTCCertificate>>(
246 RTC_FROM_HERE, [&] { return GetLocalCertificate(transport_name); });
247 }
248
Zhi Huang365381f2018-04-13 16:44:34 -0700249 const cricket::JsepTransport* t = GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800250 if (!t) {
251 return nullptr;
252 }
253 return t->GetLocalCertificate();
254}
255
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800256std::unique_ptr<rtc::SSLCertChain>
257JsepTransportController::GetRemoteSSLCertChain(
Zhi Huange818b6e2018-02-22 15:26:27 -0800258 const std::string& transport_name) const {
259 if (!network_thread_->IsCurrent()) {
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800260 return network_thread_->Invoke<std::unique_ptr<rtc::SSLCertChain>>(
261 RTC_FROM_HERE, [&] { return GetRemoteSSLCertChain(transport_name); });
Zhi Huange818b6e2018-02-22 15:26:27 -0800262 }
263
Zhi Huange830e682018-03-30 10:48:35 -0700264 // Get the certificate from the RTP transport's DTLS handshake. Should be
265 // identical to the RTCP transport's, since they were given the same remote
Zhi Huange818b6e2018-02-22 15:26:27 -0800266 // fingerprint.
Zhi Huange830e682018-03-30 10:48:35 -0700267 auto jsep_transport = GetJsepTransportByName(transport_name);
268 if (!jsep_transport) {
269 return nullptr;
270 }
271 auto dtls = jsep_transport->rtp_dtls_transport();
Zhi Huange818b6e2018-02-22 15:26:27 -0800272 if (!dtls) {
273 return nullptr;
274 }
275
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800276 return dtls->GetRemoteSSLCertChain();
Zhi Huange818b6e2018-02-22 15:26:27 -0800277}
278
279void JsepTransportController::MaybeStartGathering() {
280 if (!network_thread_->IsCurrent()) {
281 network_thread_->Invoke<void>(RTC_FROM_HERE,
282 [&] { MaybeStartGathering(); });
283 return;
284 }
285
286 for (auto& dtls : GetDtlsTransports()) {
287 dtls->ice_transport()->MaybeStartGathering();
288 }
289}
290
291RTCError JsepTransportController::AddRemoteCandidates(
292 const std::string& transport_name,
293 const cricket::Candidates& candidates) {
294 if (!network_thread_->IsCurrent()) {
295 return network_thread_->Invoke<RTCError>(RTC_FROM_HERE, [&] {
296 return AddRemoteCandidates(transport_name, candidates);
297 });
298 }
299
300 // Verify each candidate before passing down to the transport layer.
301 RTCError error = VerifyCandidates(candidates);
302 if (!error.ok()) {
303 return error;
304 }
Zhi Huange830e682018-03-30 10:48:35 -0700305 auto jsep_transport = GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800306 if (!jsep_transport) {
Zhi Huange830e682018-03-30 10:48:35 -0700307 RTC_LOG(LS_WARNING) << "Not adding candidate because the JsepTransport "
308 "doesn't exist. Ignore it.";
309 return RTCError::OK();
Zhi Huange818b6e2018-02-22 15:26:27 -0800310 }
Zhi Huange818b6e2018-02-22 15:26:27 -0800311 return jsep_transport->AddRemoteCandidates(candidates);
312}
313
314RTCError JsepTransportController::RemoveRemoteCandidates(
315 const cricket::Candidates& candidates) {
316 if (!network_thread_->IsCurrent()) {
317 return network_thread_->Invoke<RTCError>(
318 RTC_FROM_HERE, [&] { return RemoveRemoteCandidates(candidates); });
319 }
320
321 // Verify each candidate before passing down to the transport layer.
322 RTCError error = VerifyCandidates(candidates);
323 if (!error.ok()) {
324 return error;
325 }
326
327 std::map<std::string, cricket::Candidates> candidates_by_transport_name;
328 for (const cricket::Candidate& cand : candidates) {
329 if (!cand.transport_name().empty()) {
330 candidates_by_transport_name[cand.transport_name()].push_back(cand);
331 } else {
332 RTC_LOG(LS_ERROR) << "Not removing candidate because it does not have a "
333 "transport name set: "
334 << cand.ToString();
335 }
336 }
337
338 for (const auto& kv : candidates_by_transport_name) {
339 const std::string& transport_name = kv.first;
340 const cricket::Candidates& candidates = kv.second;
Zhi Huang365381f2018-04-13 16:44:34 -0700341 cricket::JsepTransport* jsep_transport =
Zhi Huange830e682018-03-30 10:48:35 -0700342 GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800343 if (!jsep_transport) {
Zhi Huange830e682018-03-30 10:48:35 -0700344 RTC_LOG(LS_WARNING)
345 << "Not removing candidate because the JsepTransport doesn't exist.";
346 continue;
Zhi Huange818b6e2018-02-22 15:26:27 -0800347 }
348 for (const cricket::Candidate& candidate : candidates) {
349 auto dtls = candidate.component() == cricket::ICE_CANDIDATE_COMPONENT_RTP
350 ? jsep_transport->rtp_dtls_transport()
351 : jsep_transport->rtcp_dtls_transport();
352 if (dtls) {
353 dtls->ice_transport()->RemoveRemoteCandidate(candidate);
354 }
355 }
356 }
357 return RTCError::OK();
358}
359
360bool JsepTransportController::GetStats(const std::string& transport_name,
361 cricket::TransportStats* stats) {
362 if (!network_thread_->IsCurrent()) {
363 return network_thread_->Invoke<bool>(
364 RTC_FROM_HERE, [=] { return GetStats(transport_name, stats); });
365 }
366
Zhi Huang365381f2018-04-13 16:44:34 -0700367 cricket::JsepTransport* transport = GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800368 if (!transport) {
369 return false;
370 }
371 return transport->GetStats(stats);
372}
373
Zhi Huangb57e1692018-06-12 11:41:11 -0700374void JsepTransportController::SetActiveResetSrtpParams(
375 bool active_reset_srtp_params) {
376 if (!network_thread_->IsCurrent()) {
377 network_thread_->Invoke<void>(RTC_FROM_HERE, [=] {
378 SetActiveResetSrtpParams(active_reset_srtp_params);
379 });
380 return;
381 }
382
383 RTC_LOG(INFO)
384 << "Updating the active_reset_srtp_params for JsepTransportController: "
385 << active_reset_srtp_params;
386 config_.active_reset_srtp_params = active_reset_srtp_params;
387 for (auto& kv : jsep_transports_by_name_) {
388 kv.second->SetActiveResetSrtpParams(active_reset_srtp_params);
389 }
390}
391
Piotr (Peter) Slatala97fc11f2018-10-18 12:57:59 -0700392void JsepTransportController::SetMediaTransportFactory(
393 MediaTransportFactory* media_transport_factory) {
394 RTC_DCHECK(media_transport_factory == config_.media_transport_factory ||
395 jsep_transports_by_name_.empty())
396 << "You can only call SetMediaTransportFactory before "
397 "JsepTransportController created its first transport.";
398 config_.media_transport_factory = media_transport_factory;
399}
400
Zhi Huange818b6e2018-02-22 15:26:27 -0800401std::unique_ptr<cricket::DtlsTransportInternal>
402JsepTransportController::CreateDtlsTransport(const std::string& transport_name,
403 bool rtcp) {
404 RTC_DCHECK(network_thread_->IsCurrent());
405 int component = rtcp ? cricket::ICE_CANDIDATE_COMPONENT_RTCP
406 : cricket::ICE_CANDIDATE_COMPONENT_RTP;
407
408 std::unique_ptr<cricket::DtlsTransportInternal> dtls;
409 if (config_.external_transport_factory) {
410 auto ice = config_.external_transport_factory->CreateIceTransport(
411 transport_name, component);
412 dtls = config_.external_transport_factory->CreateDtlsTransport(
413 std::move(ice), config_.crypto_options);
414 } else {
Karl Wiberg918f50c2018-07-05 11:40:33 +0200415 auto ice = absl::make_unique<cricket::P2PTransportChannel>(
Zach Steine20867f2018-08-02 13:20:15 -0700416 transport_name, component, port_allocator_, async_resolver_factory_,
417 config_.event_log);
Karl Wiberg918f50c2018-07-05 11:40:33 +0200418 dtls = absl::make_unique<cricket::DtlsTransport>(std::move(ice),
419 config_.crypto_options);
Zhi Huange818b6e2018-02-22 15:26:27 -0800420 }
421
422 RTC_DCHECK(dtls);
423 dtls->SetSslMaxProtocolVersion(config_.ssl_max_version);
Zhi Huange818b6e2018-02-22 15:26:27 -0800424 dtls->ice_transport()->SetIceRole(ice_role_);
425 dtls->ice_transport()->SetIceTiebreaker(ice_tiebreaker_);
426 dtls->ice_transport()->SetIceConfig(ice_config_);
427 if (certificate_) {
428 bool set_cert_success = dtls->SetLocalCertificate(certificate_);
429 RTC_DCHECK(set_cert_success);
430 }
431
432 // Connect to signals offered by the DTLS and ICE transport.
433 dtls->SignalWritableState.connect(
434 this, &JsepTransportController::OnTransportWritableState_n);
435 dtls->SignalReceivingState.connect(
436 this, &JsepTransportController::OnTransportReceivingState_n);
437 dtls->SignalDtlsHandshakeError.connect(
438 this, &JsepTransportController::OnDtlsHandshakeError);
439 dtls->ice_transport()->SignalGatheringState.connect(
440 this, &JsepTransportController::OnTransportGatheringState_n);
441 dtls->ice_transport()->SignalCandidateGathered.connect(
442 this, &JsepTransportController::OnTransportCandidateGathered_n);
443 dtls->ice_transport()->SignalCandidatesRemoved.connect(
444 this, &JsepTransportController::OnTransportCandidatesRemoved_n);
445 dtls->ice_transport()->SignalRoleConflict.connect(
446 this, &JsepTransportController::OnTransportRoleConflict_n);
447 dtls->ice_transport()->SignalStateChanged.connect(
448 this, &JsepTransportController::OnTransportStateChanged_n);
449 return dtls;
450}
451
452std::unique_ptr<webrtc::RtpTransport>
453JsepTransportController::CreateUnencryptedRtpTransport(
454 const std::string& transport_name,
455 rtc::PacketTransportInternal* rtp_packet_transport,
456 rtc::PacketTransportInternal* rtcp_packet_transport) {
457 RTC_DCHECK(network_thread_->IsCurrent());
Zhi Huange830e682018-03-30 10:48:35 -0700458 auto unencrypted_rtp_transport =
Karl Wiberg918f50c2018-07-05 11:40:33 +0200459 absl::make_unique<RtpTransport>(rtcp_packet_transport == nullptr);
Zhi Huange830e682018-03-30 10:48:35 -0700460 unencrypted_rtp_transport->SetRtpPacketTransport(rtp_packet_transport);
461 if (rtcp_packet_transport) {
462 unencrypted_rtp_transport->SetRtcpPacketTransport(rtcp_packet_transport);
463 }
464 return unencrypted_rtp_transport;
Zhi Huange818b6e2018-02-22 15:26:27 -0800465}
466
467std::unique_ptr<webrtc::SrtpTransport>
468JsepTransportController::CreateSdesTransport(
469 const std::string& transport_name,
Zhi Huange830e682018-03-30 10:48:35 -0700470 cricket::DtlsTransportInternal* rtp_dtls_transport,
471 cricket::DtlsTransportInternal* rtcp_dtls_transport) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800472 RTC_DCHECK(network_thread_->IsCurrent());
Zhi Huange818b6e2018-02-22 15:26:27 -0800473 auto srtp_transport =
Karl Wiberg918f50c2018-07-05 11:40:33 +0200474 absl::make_unique<webrtc::SrtpTransport>(rtcp_dtls_transport == nullptr);
Zhi Huange830e682018-03-30 10:48:35 -0700475 RTC_DCHECK(rtp_dtls_transport);
476 srtp_transport->SetRtpPacketTransport(rtp_dtls_transport);
477 if (rtcp_dtls_transport) {
478 srtp_transport->SetRtcpPacketTransport(rtcp_dtls_transport);
Zhi Huange818b6e2018-02-22 15:26:27 -0800479 }
480 if (config_.enable_external_auth) {
481 srtp_transport->EnableExternalAuth();
482 }
483 return srtp_transport;
484}
485
486std::unique_ptr<webrtc::DtlsSrtpTransport>
487JsepTransportController::CreateDtlsSrtpTransport(
488 const std::string& transport_name,
489 cricket::DtlsTransportInternal* rtp_dtls_transport,
490 cricket::DtlsTransportInternal* rtcp_dtls_transport) {
491 RTC_DCHECK(network_thread_->IsCurrent());
Karl Wiberg918f50c2018-07-05 11:40:33 +0200492 auto dtls_srtp_transport = absl::make_unique<webrtc::DtlsSrtpTransport>(
Zhi Huang365381f2018-04-13 16:44:34 -0700493 rtcp_dtls_transport == nullptr);
Zhi Huang27f3bf52018-03-26 21:37:23 -0700494 if (config_.enable_external_auth) {
Zhi Huang365381f2018-04-13 16:44:34 -0700495 dtls_srtp_transport->EnableExternalAuth();
Zhi Huang27f3bf52018-03-26 21:37:23 -0700496 }
Zhi Huang97d5e5b2018-03-27 00:09:01 +0000497
Zhi Huange818b6e2018-02-22 15:26:27 -0800498 dtls_srtp_transport->SetDtlsTransports(rtp_dtls_transport,
499 rtcp_dtls_transport);
Zhi Huangb57e1692018-06-12 11:41:11 -0700500 dtls_srtp_transport->SetActiveResetSrtpParams(
501 config_.active_reset_srtp_params);
Jonas Olsson635474e2018-10-18 15:58:17 +0200502 dtls_srtp_transport->SignalDtlsStateChange.connect(
503 this, &JsepTransportController::UpdateAggregateStates_n);
Zhi Huange818b6e2018-02-22 15:26:27 -0800504 return dtls_srtp_transport;
505}
506
507std::vector<cricket::DtlsTransportInternal*>
508JsepTransportController::GetDtlsTransports() {
509 std::vector<cricket::DtlsTransportInternal*> dtls_transports;
Zhi Huange830e682018-03-30 10:48:35 -0700510 for (auto it = jsep_transports_by_name_.begin();
511 it != jsep_transports_by_name_.end(); ++it) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800512 auto jsep_transport = it->second.get();
513 RTC_DCHECK(jsep_transport);
514 if (jsep_transport->rtp_dtls_transport()) {
515 dtls_transports.push_back(jsep_transport->rtp_dtls_transport());
516 }
517
518 if (jsep_transport->rtcp_dtls_transport()) {
519 dtls_transports.push_back(jsep_transport->rtcp_dtls_transport());
520 }
521 }
522 return dtls_transports;
523}
524
Zhi Huange818b6e2018-02-22 15:26:27 -0800525RTCError JsepTransportController::ApplyDescription_n(
526 bool local,
527 SdpType type,
528 const cricket::SessionDescription* description) {
529 RTC_DCHECK(network_thread_->IsCurrent());
530 RTC_DCHECK(description);
531
532 if (local) {
533 local_desc_ = description;
534 } else {
535 remote_desc_ = description;
536 }
537
Zhi Huange830e682018-03-30 10:48:35 -0700538 RTCError error;
Zhi Huangd2248f82018-04-10 14:41:03 -0700539 error = ValidateAndMaybeUpdateBundleGroup(local, type, description);
Zhi Huange830e682018-03-30 10:48:35 -0700540 if (!error.ok()) {
541 return error;
Zhi Huange818b6e2018-02-22 15:26:27 -0800542 }
543
544 std::vector<int> merged_encrypted_extension_ids;
545 if (bundle_group_) {
546 merged_encrypted_extension_ids =
547 MergeEncryptedHeaderExtensionIdsForBundle(description);
548 }
549
550 for (const cricket::ContentInfo& content_info : description->contents()) {
551 // Don't create transports for rejected m-lines and bundled m-lines."
552 if (content_info.rejected ||
553 (IsBundled(content_info.name) && content_info.name != *bundled_mid())) {
554 continue;
555 }
Anton Sukhanov7940da02018-10-10 10:34:49 -0700556 error = MaybeCreateJsepTransport(local, content_info);
Zhi Huange830e682018-03-30 10:48:35 -0700557 if (!error.ok()) {
558 return error;
559 }
Zhi Huange818b6e2018-02-22 15:26:27 -0800560 }
561
562 RTC_DCHECK(description->contents().size() ==
563 description->transport_infos().size());
564 for (size_t i = 0; i < description->contents().size(); ++i) {
565 const cricket::ContentInfo& content_info = description->contents()[i];
566 const cricket::TransportInfo& transport_info =
567 description->transport_infos()[i];
568 if (content_info.rejected) {
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700569 HandleRejectedContent(content_info, description);
Zhi Huange818b6e2018-02-22 15:26:27 -0800570 continue;
571 }
572
573 if (IsBundled(content_info.name) && content_info.name != *bundled_mid()) {
Zhi Huang365381f2018-04-13 16:44:34 -0700574 if (!HandleBundledContent(content_info)) {
575 return RTCError(RTCErrorType::INVALID_PARAMETER,
576 "Failed to process the bundled m= section.");
577 }
Zhi Huange818b6e2018-02-22 15:26:27 -0800578 continue;
579 }
580
Zhi Huange830e682018-03-30 10:48:35 -0700581 error = ValidateContent(content_info);
582 if (!error.ok()) {
583 return error;
584 }
585
Zhi Huange818b6e2018-02-22 15:26:27 -0800586 std::vector<int> extension_ids;
Taylor Brandstetter0ab56512018-04-12 10:30:48 -0700587 if (bundled_mid() && content_info.name == *bundled_mid()) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800588 extension_ids = merged_encrypted_extension_ids;
589 } else {
590 extension_ids = GetEncryptedHeaderExtensionIds(content_info);
591 }
592
Zhi Huange830e682018-03-30 10:48:35 -0700593 int rtp_abs_sendtime_extn_id =
594 GetRtpAbsSendTimeHeaderExtensionId(content_info);
595
Zhi Huang365381f2018-04-13 16:44:34 -0700596 cricket::JsepTransport* transport =
Zhi Huange830e682018-03-30 10:48:35 -0700597 GetJsepTransportForMid(content_info.name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800598 RTC_DCHECK(transport);
599
600 SetIceRole_n(DetermineIceRole(transport, transport_info, type, local));
601
Zhi Huange818b6e2018-02-22 15:26:27 -0800602 cricket::JsepTransportDescription jsep_description =
603 CreateJsepTransportDescription(content_info, transport_info,
Zhi Huange830e682018-03-30 10:48:35 -0700604 extension_ids, rtp_abs_sendtime_extn_id);
Zhi Huange818b6e2018-02-22 15:26:27 -0800605 if (local) {
606 error =
607 transport->SetLocalJsepTransportDescription(jsep_description, type);
608 } else {
609 error =
610 transport->SetRemoteJsepTransportDescription(jsep_description, type);
611 }
612
613 if (!error.ok()) {
614 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
615 "Failed to apply the description for " +
616 content_info.name + ": " + error.message());
617 }
618 }
619 return RTCError::OK();
620}
621
Zhi Huangd2248f82018-04-10 14:41:03 -0700622RTCError JsepTransportController::ValidateAndMaybeUpdateBundleGroup(
623 bool local,
624 SdpType type,
Zhi Huange830e682018-03-30 10:48:35 -0700625 const cricket::SessionDescription* description) {
626 RTC_DCHECK(description);
Zhi Huangd2248f82018-04-10 14:41:03 -0700627 const cricket::ContentGroup* new_bundle_group =
628 description->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
629
630 // The BUNDLE group containing a MID that no m= section has is invalid.
631 if (new_bundle_group) {
632 for (auto content_name : new_bundle_group->content_names()) {
633 if (!description->GetContentByName(content_name)) {
634 return RTCError(RTCErrorType::INVALID_PARAMETER,
635 "The BUNDLE group contains MID:" + content_name +
636 " matching no m= section.");
637 }
638 }
639 }
640
641 if (type == SdpType::kAnswer) {
642 const cricket::ContentGroup* offered_bundle_group =
643 local ? remote_desc_->GetGroupByName(cricket::GROUP_TYPE_BUNDLE)
644 : local_desc_->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
645
646 if (new_bundle_group) {
647 // The BUNDLE group in answer should be a subset of offered group.
648 for (auto content_name : new_bundle_group->content_names()) {
649 if (!offered_bundle_group ||
650 !offered_bundle_group->HasContentName(content_name)) {
651 return RTCError(RTCErrorType::INVALID_PARAMETER,
652 "The BUNDLE group in answer contains a MID that was "
653 "not in the offered group.");
654 }
655 }
656 }
657
658 if (bundle_group_) {
659 for (auto content_name : bundle_group_->content_names()) {
660 // An answer that removes m= sections from pre-negotiated BUNDLE group
661 // without rejecting it, is invalid.
662 if (!new_bundle_group ||
663 !new_bundle_group->HasContentName(content_name)) {
664 auto* content_info = description->GetContentByName(content_name);
665 if (!content_info || !content_info->rejected) {
666 return RTCError(RTCErrorType::INVALID_PARAMETER,
667 "Answer cannot remove m= section " + content_name +
668 " from already-established BUNDLE group.");
669 }
670 }
671 }
672 }
673 }
674
675 if (config_.bundle_policy ==
676 PeerConnectionInterface::kBundlePolicyMaxBundle &&
677 !description->HasGroup(cricket::GROUP_TYPE_BUNDLE)) {
678 return RTCError(RTCErrorType::INVALID_PARAMETER,
679 "max-bundle is used but no bundle group found.");
680 }
681
682 if (ShouldUpdateBundleGroup(type, description)) {
Taylor Brandstetter0ab56512018-04-12 10:30:48 -0700683 const std::string* new_bundled_mid = new_bundle_group->FirstContentName();
684 if (bundled_mid() && new_bundled_mid &&
685 *bundled_mid() != *new_bundled_mid) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700686 return RTCError(RTCErrorType::UNSUPPORTED_OPERATION,
687 "Changing the negotiated BUNDLE-tag is not supported.");
688 }
689
690 bundle_group_ = *new_bundle_group;
691 }
Zhi Huange830e682018-03-30 10:48:35 -0700692
693 if (!bundled_mid()) {
694 return RTCError::OK();
695 }
696
697 auto bundled_content = description->GetContentByName(*bundled_mid());
698 if (!bundled_content) {
699 return RTCError(
700 RTCErrorType::INVALID_PARAMETER,
701 "An m= section associated with the BUNDLE-tag doesn't exist.");
702 }
703
704 // If the |bundled_content| is rejected, other contents in the bundle group
705 // should be rejected.
706 if (bundled_content->rejected) {
707 for (auto content_name : bundle_group_->content_names()) {
708 auto other_content = description->GetContentByName(content_name);
709 if (!other_content->rejected) {
710 return RTCError(
711 RTCErrorType::INVALID_PARAMETER,
712 "The m= section:" + content_name + " should be rejected.");
713 }
714 }
715 }
716
717 return RTCError::OK();
718}
719
720RTCError JsepTransportController::ValidateContent(
721 const cricket::ContentInfo& content_info) {
722 if (config_.rtcp_mux_policy ==
723 PeerConnectionInterface::kRtcpMuxPolicyRequire &&
724 content_info.type == cricket::MediaProtocolType::kRtp &&
725 !content_info.media_description()->rtcp_mux()) {
726 return RTCError(RTCErrorType::INVALID_PARAMETER,
727 "The m= section:" + content_info.name +
728 " is invalid. RTCP-MUX is not "
729 "enabled when it is required.");
730 }
731 return RTCError::OK();
732}
733
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700734void JsepTransportController::HandleRejectedContent(
Zhi Huangd2248f82018-04-10 14:41:03 -0700735 const cricket::ContentInfo& content_info,
736 const cricket::SessionDescription* description) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800737 // If the content is rejected, let the
738 // BaseChannel/SctpTransport change the RtpTransport/DtlsTransport first,
Zhi Huang365381f2018-04-13 16:44:34 -0700739 // then destroy the cricket::JsepTransport.
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700740 RemoveTransportForMid(content_info.name);
Zhi Huange830e682018-03-30 10:48:35 -0700741 if (content_info.name == bundled_mid()) {
742 for (auto content_name : bundle_group_->content_names()) {
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700743 RemoveTransportForMid(content_name);
Zhi Huange830e682018-03-30 10:48:35 -0700744 }
745 bundle_group_.reset();
746 } else if (IsBundled(content_info.name)) {
747 // Remove the rejected content from the |bundle_group_|.
Zhi Huange818b6e2018-02-22 15:26:27 -0800748 bundle_group_->RemoveContentName(content_info.name);
Zhi Huange830e682018-03-30 10:48:35 -0700749 // Reset the bundle group if nothing left.
750 if (!bundle_group_->FirstContentName()) {
751 bundle_group_.reset();
752 }
Zhi Huange818b6e2018-02-22 15:26:27 -0800753 }
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700754 MaybeDestroyJsepTransport(content_info.name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800755}
756
Zhi Huang365381f2018-04-13 16:44:34 -0700757bool JsepTransportController::HandleBundledContent(
Zhi Huange818b6e2018-02-22 15:26:27 -0800758 const cricket::ContentInfo& content_info) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700759 auto jsep_transport = GetJsepTransportByName(*bundled_mid());
760 RTC_DCHECK(jsep_transport);
Zhi Huange818b6e2018-02-22 15:26:27 -0800761 // If the content is bundled, let the
762 // BaseChannel/SctpTransport change the RtpTransport/DtlsTransport first,
Zhi Huang365381f2018-04-13 16:44:34 -0700763 // then destroy the cricket::JsepTransport.
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700764 if (SetTransportForMid(content_info.name, jsep_transport)) {
Piotr (Peter) Slatala10aeb2a2018-11-14 10:57:24 -0800765 // TODO(bugs.webrtc.org/9719) For media transport this is far from ideal,
766 // because it means that we first create media transport and start
767 // connecting it, and then we destroy it. We will need to address it before
768 // video path is enabled.
Zhi Huang365381f2018-04-13 16:44:34 -0700769 MaybeDestroyJsepTransport(content_info.name);
770 return true;
771 }
772 return false;
Zhi Huange818b6e2018-02-22 15:26:27 -0800773}
774
Zhi Huang365381f2018-04-13 16:44:34 -0700775bool JsepTransportController::SetTransportForMid(
Zhi Huangd2248f82018-04-10 14:41:03 -0700776 const std::string& mid,
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700777 cricket::JsepTransport* jsep_transport) {
Zhi Huang365381f2018-04-13 16:44:34 -0700778 RTC_DCHECK(jsep_transport);
Zhi Huangd2248f82018-04-10 14:41:03 -0700779 if (mid_to_transport_[mid] == jsep_transport) {
Zhi Huang365381f2018-04-13 16:44:34 -0700780 return true;
Zhi Huangd2248f82018-04-10 14:41:03 -0700781 }
782
783 mid_to_transport_[mid] = jsep_transport;
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700784 return config_.transport_observer->OnTransportChanged(
785 mid, jsep_transport->rtp_transport(),
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -0800786 jsep_transport->rtp_dtls_transport(), jsep_transport->media_transport());
Zhi Huangd2248f82018-04-10 14:41:03 -0700787}
788
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700789void JsepTransportController::RemoveTransportForMid(const std::string& mid) {
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -0800790 bool ret = config_.transport_observer->OnTransportChanged(mid, nullptr,
791 nullptr, nullptr);
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700792 // Calling OnTransportChanged with nullptr should always succeed, since it is
793 // only expected to fail when adding media to a transport (not removing).
794 RTC_DCHECK(ret);
Zhi Huangd2248f82018-04-10 14:41:03 -0700795 mid_to_transport_.erase(mid);
796}
797
Zhi Huange818b6e2018-02-22 15:26:27 -0800798cricket::JsepTransportDescription
799JsepTransportController::CreateJsepTransportDescription(
800 cricket::ContentInfo content_info,
801 cricket::TransportInfo transport_info,
Zhi Huange830e682018-03-30 10:48:35 -0700802 const std::vector<int>& encrypted_extension_ids,
803 int rtp_abs_sendtime_extn_id) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800804 const cricket::MediaContentDescription* content_desc =
805 static_cast<const cricket::MediaContentDescription*>(
806 content_info.description);
807 RTC_DCHECK(content_desc);
808 bool rtcp_mux_enabled = content_info.type == cricket::MediaProtocolType::kSctp
809 ? true
810 : content_desc->rtcp_mux();
811
812 return cricket::JsepTransportDescription(
813 rtcp_mux_enabled, content_desc->cryptos(), encrypted_extension_ids,
Zhi Huange830e682018-03-30 10:48:35 -0700814 rtp_abs_sendtime_extn_id, transport_info.description);
Zhi Huange818b6e2018-02-22 15:26:27 -0800815}
816
817bool JsepTransportController::ShouldUpdateBundleGroup(
818 SdpType type,
819 const cricket::SessionDescription* description) {
820 if (config_.bundle_policy ==
821 PeerConnectionInterface::kBundlePolicyMaxBundle) {
822 return true;
823 }
824
825 if (type != SdpType::kAnswer) {
826 return false;
827 }
828
829 RTC_DCHECK(local_desc_ && remote_desc_);
830 const cricket::ContentGroup* local_bundle =
831 local_desc_->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
832 const cricket::ContentGroup* remote_bundle =
833 remote_desc_->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
834 return local_bundle && remote_bundle;
835}
836
837std::vector<int> JsepTransportController::GetEncryptedHeaderExtensionIds(
838 const cricket::ContentInfo& content_info) {
839 const cricket::MediaContentDescription* content_desc =
840 static_cast<const cricket::MediaContentDescription*>(
841 content_info.description);
842
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700843 if (!config_.crypto_options.srtp.enable_encrypted_rtp_header_extensions) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800844 return std::vector<int>();
845 }
846
847 std::vector<int> encrypted_header_extension_ids;
848 for (auto extension : content_desc->rtp_header_extensions()) {
849 if (!extension.encrypt) {
850 continue;
851 }
852 auto it = std::find(encrypted_header_extension_ids.begin(),
853 encrypted_header_extension_ids.end(), extension.id);
854 if (it == encrypted_header_extension_ids.end()) {
855 encrypted_header_extension_ids.push_back(extension.id);
856 }
857 }
858 return encrypted_header_extension_ids;
859}
860
861std::vector<int>
862JsepTransportController::MergeEncryptedHeaderExtensionIdsForBundle(
863 const cricket::SessionDescription* description) {
864 RTC_DCHECK(description);
865 RTC_DCHECK(bundle_group_);
866
867 std::vector<int> merged_ids;
868 // Union the encrypted header IDs in the group when bundle is enabled.
869 for (const cricket::ContentInfo& content_info : description->contents()) {
870 if (bundle_group_->HasContentName(content_info.name)) {
871 std::vector<int> extension_ids =
872 GetEncryptedHeaderExtensionIds(content_info);
873 for (int id : extension_ids) {
874 auto it = std::find(merged_ids.begin(), merged_ids.end(), id);
875 if (it == merged_ids.end()) {
876 merged_ids.push_back(id);
877 }
878 }
879 }
880 }
881 return merged_ids;
882}
883
Zhi Huange830e682018-03-30 10:48:35 -0700884int JsepTransportController::GetRtpAbsSendTimeHeaderExtensionId(
Zhi Huange818b6e2018-02-22 15:26:27 -0800885 const cricket::ContentInfo& content_info) {
Zhi Huange830e682018-03-30 10:48:35 -0700886 if (!config_.enable_external_auth) {
887 return -1;
Zhi Huange818b6e2018-02-22 15:26:27 -0800888 }
889
890 const cricket::MediaContentDescription* content_desc =
891 static_cast<const cricket::MediaContentDescription*>(
892 content_info.description);
Zhi Huange830e682018-03-30 10:48:35 -0700893
894 const webrtc::RtpExtension* send_time_extension =
895 webrtc::RtpExtension::FindHeaderExtensionByUri(
896 content_desc->rtp_header_extensions(),
897 webrtc::RtpExtension::kAbsSendTimeUri);
898 return send_time_extension ? send_time_extension->id : -1;
899}
900
Zhi Huang365381f2018-04-13 16:44:34 -0700901const cricket::JsepTransport* JsepTransportController::GetJsepTransportForMid(
Zhi Huange830e682018-03-30 10:48:35 -0700902 const std::string& mid) const {
Zhi Huangd2248f82018-04-10 14:41:03 -0700903 auto it = mid_to_transport_.find(mid);
904 return it == mid_to_transport_.end() ? nullptr : it->second;
Zhi Huange830e682018-03-30 10:48:35 -0700905}
906
Zhi Huang365381f2018-04-13 16:44:34 -0700907cricket::JsepTransport* JsepTransportController::GetJsepTransportForMid(
Zhi Huange830e682018-03-30 10:48:35 -0700908 const std::string& mid) {
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 -0700913const cricket::JsepTransport* JsepTransportController::GetJsepTransportByName(
Zhi Huange830e682018-03-30 10:48:35 -0700914 const std::string& transport_name) const {
915 auto it = jsep_transports_by_name_.find(transport_name);
916 return (it == jsep_transports_by_name_.end()) ? nullptr : it->second.get();
917}
918
Zhi Huang365381f2018-04-13 16:44:34 -0700919cricket::JsepTransport* JsepTransportController::GetJsepTransportByName(
Zhi Huange830e682018-03-30 10:48:35 -0700920 const std::string& transport_name) {
921 auto it = jsep_transports_by_name_.find(transport_name);
922 return (it == jsep_transports_by_name_.end()) ? nullptr : it->second.get();
923}
924
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -0800925std::unique_ptr<webrtc::MediaTransportInterface>
926JsepTransportController::MaybeCreateMediaTransport(
927 const cricket::ContentInfo& content_info,
Anton Sukhanov7940da02018-10-10 10:34:49 -0700928 bool local,
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -0800929 cricket::IceTransportInternal* ice_transport) {
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700930 absl::optional<cricket::CryptoParams> selected_crypto_for_media_transport;
931 if (content_info.media_description() &&
932 !content_info.media_description()->cryptos().empty()) {
933 // Order of cryptos is deterministic (rfc4568, 5.1.1), so we just select the
934 // first one (in fact the first one should be the most preferred one.) We
935 // ignore the HMAC size, as media transport crypto settings currently don't
936 // expose HMAC size, nor crypto protocol for that matter.
937 selected_crypto_for_media_transport =
938 content_info.media_description()->cryptos()[0];
939 }
940
Anton Sukhanov7940da02018-10-10 10:34:49 -0700941 if (config_.media_transport_factory != nullptr) {
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700942 if (!selected_crypto_for_media_transport.has_value()) {
943 RTC_LOG(LS_WARNING) << "a=cryto line was not found in the offer. Most "
944 "likely you did not enable SDES. "
945 "Make sure to pass config.enable_dtls_srtp=false "
946 "to RTCConfiguration. "
947 "Cannot continue with media transport. Falling "
948 "back to RTP. is_local="
949 << local;
Anton Sukhanov7940da02018-10-10 10:34:49 -0700950
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700951 // Remove media_transport_factory from config, because we don't want to
952 // use it on the subsequent call (for the other side of the offer).
953 config_.media_transport_factory = nullptr;
954 } else {
955 // Note that we ignore here lifetime and length.
956 // In fact we take those bits (inline, lifetime and length) and keep it as
957 // part of key derivation.
958 //
959 // Technically, we are also not following rfc4568, which requires us to
960 // send and answer with the key that we chose. In practice, for media
961 // transport, the current approach should be sufficient (we take the key
962 // that sender offered, and caller assumes we will use it. We are not
963 // signaling back that we indeed used it.)
964 std::unique_ptr<rtc::KeyDerivation> key_derivation =
965 rtc::KeyDerivation::Create(rtc::KeyDerivationAlgorithm::HKDF_SHA256);
966 const std::string label = "MediaTransportLabel";
967 constexpr int kDerivedKeyByteSize = 32;
Anton Sukhanov7940da02018-10-10 10:34:49 -0700968
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -0700969 int key_len, salt_len;
970 if (!rtc::GetSrtpKeyAndSaltLengths(
971 rtc::SrtpCryptoSuiteFromName(
972 selected_crypto_for_media_transport.value().cipher_suite),
973 &key_len, &salt_len)) {
974 RTC_CHECK(false) << "Cannot set up secure media transport";
975 }
976 rtc::ZeroOnFreeBuffer<uint8_t> raw_key(key_len + salt_len);
977
978 cricket::SrtpFilter::ParseKeyParams(
979 selected_crypto_for_media_transport.value().key_params,
980 raw_key.data(), raw_key.size());
981 absl::optional<rtc::ZeroOnFreeBuffer<uint8_t>> key =
982 key_derivation->DeriveKey(
983 raw_key,
984 /*salt=*/nullptr,
985 rtc::ArrayView<const uint8_t>(
986 reinterpret_cast<const uint8_t*>(label.data()), label.size()),
987 kDerivedKeyByteSize);
988
989 // We want to crash the app if we don't have a key, and not silently fall
990 // back to the unsecure communication.
991 RTC_CHECK(key.has_value());
992 MediaTransportSettings settings;
993 settings.is_caller = local;
994 settings.pre_shared_key =
995 std::string(reinterpret_cast<const char*>(key.value().data()),
996 key.value().size());
997 auto media_transport_result =
998 config_.media_transport_factory->CreateMediaTransport(
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -0800999 ice_transport, network_thread_, settings);
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -07001000
1001 // TODO(sukhanov): Proper error handling.
1002 RTC_CHECK(media_transport_result.ok());
1003
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001004 return media_transport_result.MoveValue();
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -07001005 }
Anton Sukhanov7940da02018-10-10 10:34:49 -07001006 }
1007
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001008 return nullptr;
1009}
1010
1011RTCError JsepTransportController::MaybeCreateJsepTransport(
1012 bool local,
1013 const cricket::ContentInfo& content_info) {
1014 RTC_DCHECK(network_thread_->IsCurrent());
1015 cricket::JsepTransport* transport = GetJsepTransportByName(content_info.name);
1016 if (transport) {
1017 return RTCError::OK();
1018 }
1019
1020 const cricket::MediaContentDescription* content_desc =
1021 static_cast<const cricket::MediaContentDescription*>(
1022 content_info.description);
1023 if (certificate_ && !content_desc->cryptos().empty()) {
1024 return RTCError(RTCErrorType::INVALID_PARAMETER,
1025 "SDES and DTLS-SRTP cannot be enabled at the same time.");
1026 }
1027
1028 std::unique_ptr<cricket::DtlsTransportInternal> rtp_dtls_transport =
1029 CreateDtlsTransport(content_info.name, /*rtcp =*/false);
1030
1031 std::unique_ptr<cricket::DtlsTransportInternal> rtcp_dtls_transport;
1032 std::unique_ptr<RtpTransport> unencrypted_rtp_transport;
1033 std::unique_ptr<SrtpTransport> sdes_transport;
1034 std::unique_ptr<DtlsSrtpTransport> dtls_srtp_transport;
1035 std::unique_ptr<MediaTransportInterface> media_transport;
1036
1037 if (config_.rtcp_mux_policy !=
1038 PeerConnectionInterface::kRtcpMuxPolicyRequire &&
1039 content_info.type == cricket::MediaProtocolType::kRtp) {
1040 rtcp_dtls_transport =
1041 CreateDtlsTransport(content_info.name, /*rtcp =*/true);
1042 }
1043 media_transport = MaybeCreateMediaTransport(
1044 content_info, local, rtp_dtls_transport->ice_transport());
1045
Anton Sukhanov7940da02018-10-10 10:34:49 -07001046 // TODO(sukhanov): Do not create RTP/RTCP transports if media transport is
1047 // used.
Zhi Huange818b6e2018-02-22 15:26:27 -08001048 if (config_.disable_encryption) {
1049 unencrypted_rtp_transport = CreateUnencryptedRtpTransport(
Zhi Huangd2248f82018-04-10 14:41:03 -07001050 content_info.name, rtp_dtls_transport.get(), rtcp_dtls_transport.get());
Zhi Huange818b6e2018-02-22 15:26:27 -08001051 } else if (!content_desc->cryptos().empty()) {
Zhi Huangd2248f82018-04-10 14:41:03 -07001052 sdes_transport = CreateSdesTransport(
1053 content_info.name, rtp_dtls_transport.get(), rtcp_dtls_transport.get());
Zhi Huange818b6e2018-02-22 15:26:27 -08001054 } else {
Zhi Huangd2248f82018-04-10 14:41:03 -07001055 dtls_srtp_transport = CreateDtlsSrtpTransport(
1056 content_info.name, rtp_dtls_transport.get(), rtcp_dtls_transport.get());
Zhi Huange818b6e2018-02-22 15:26:27 -08001057 }
1058
Zhi Huang365381f2018-04-13 16:44:34 -07001059 std::unique_ptr<cricket::JsepTransport> jsep_transport =
Karl Wiberg918f50c2018-07-05 11:40:33 +02001060 absl::make_unique<cricket::JsepTransport>(
Zhi Huangd2248f82018-04-10 14:41:03 -07001061 content_info.name, certificate_, std::move(unencrypted_rtp_transport),
Zhi Huange818b6e2018-02-22 15:26:27 -08001062 std::move(sdes_transport), std::move(dtls_srtp_transport),
Anton Sukhanov7940da02018-10-10 10:34:49 -07001063 std::move(rtp_dtls_transport), std::move(rtcp_dtls_transport),
1064 std::move(media_transport));
Zhi Huange818b6e2018-02-22 15:26:27 -08001065 jsep_transport->SignalRtcpMuxActive.connect(
1066 this, &JsepTransportController::UpdateAggregateStates_n);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001067 jsep_transport->SignalMediaTransportStateChanged.connect(
Bjorn Mellem175aa2e2018-11-08 11:23:22 -08001068 this, &JsepTransportController::OnMediaTransportStateChanged_n);
Taylor Brandstettercbaa2542018-04-16 16:42:14 -07001069 SetTransportForMid(content_info.name, jsep_transport.get());
Zhi Huange830e682018-03-30 10:48:35 -07001070
Zhi Huangd2248f82018-04-10 14:41:03 -07001071 jsep_transports_by_name_[content_info.name] = std::move(jsep_transport);
1072 UpdateAggregateStates_n();
Zhi Huange830e682018-03-30 10:48:35 -07001073 return RTCError::OK();
Zhi Huange818b6e2018-02-22 15:26:27 -08001074}
1075
1076void JsepTransportController::MaybeDestroyJsepTransport(
1077 const std::string& mid) {
Zhi Huangd2248f82018-04-10 14:41:03 -07001078 auto jsep_transport = GetJsepTransportByName(mid);
1079 if (!jsep_transport) {
1080 return;
1081 }
1082
1083 // Don't destroy the JsepTransport if there are still media sections referring
1084 // to it.
1085 for (const auto& kv : mid_to_transport_) {
1086 if (kv.second == jsep_transport) {
1087 return;
1088 }
1089 }
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -08001090
Zhi Huange830e682018-03-30 10:48:35 -07001091 jsep_transports_by_name_.erase(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -08001092 UpdateAggregateStates_n();
1093}
1094
1095void JsepTransportController::DestroyAllJsepTransports_n() {
1096 RTC_DCHECK(network_thread_->IsCurrent());
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -08001097
1098 for (const auto& jsep_transport : jsep_transports_by_name_) {
1099 config_.transport_observer->OnTransportChanged(jsep_transport.first,
1100 nullptr, nullptr, nullptr);
1101 }
1102
Zhi Huange830e682018-03-30 10:48:35 -07001103 jsep_transports_by_name_.clear();
Zhi Huange818b6e2018-02-22 15:26:27 -08001104}
1105
1106void JsepTransportController::SetIceRole_n(cricket::IceRole ice_role) {
1107 RTC_DCHECK(network_thread_->IsCurrent());
1108
1109 ice_role_ = ice_role;
1110 for (auto& dtls : GetDtlsTransports()) {
1111 dtls->ice_transport()->SetIceRole(ice_role_);
1112 }
1113}
1114
1115cricket::IceRole JsepTransportController::DetermineIceRole(
Zhi Huang365381f2018-04-13 16:44:34 -07001116 cricket::JsepTransport* jsep_transport,
Zhi Huange818b6e2018-02-22 15:26:27 -08001117 const cricket::TransportInfo& transport_info,
1118 SdpType type,
1119 bool local) {
1120 cricket::IceRole ice_role = ice_role_;
1121 auto tdesc = transport_info.description;
1122 if (local) {
1123 // The initial offer side may use ICE Lite, in which case, per RFC5245
1124 // Section 5.1.1, the answer side should take the controlling role if it is
1125 // in the full ICE mode.
1126 //
1127 // When both sides use ICE Lite, the initial offer side must take the
1128 // controlling role, and this is the default logic implemented in
1129 // SetLocalDescription in JsepTransportController.
1130 if (jsep_transport->remote_description() &&
1131 jsep_transport->remote_description()->transport_desc.ice_mode ==
1132 cricket::ICEMODE_LITE &&
1133 ice_role_ == cricket::ICEROLE_CONTROLLED &&
1134 tdesc.ice_mode == cricket::ICEMODE_FULL) {
1135 ice_role = cricket::ICEROLE_CONTROLLING;
1136 }
1137
1138 // Older versions of Chrome expect the ICE role to be re-determined when an
1139 // ICE restart occurs, and also don't perform conflict resolution correctly,
1140 // so for now we can't safely stop doing this, unless the application opts
1141 // in by setting |config_.redetermine_role_on_ice_restart_| to false. See:
1142 // https://bugs.chromium.org/p/chromium/issues/detail?id=628676
1143 // TODO(deadbeef): Remove this when these old versions of Chrome reach a low
1144 // enough population.
1145 if (config_.redetermine_role_on_ice_restart &&
1146 jsep_transport->local_description() &&
1147 cricket::IceCredentialsChanged(
1148 jsep_transport->local_description()->transport_desc.ice_ufrag,
1149 jsep_transport->local_description()->transport_desc.ice_pwd,
1150 tdesc.ice_ufrag, tdesc.ice_pwd) &&
1151 // Don't change the ICE role if the remote endpoint is ICE lite; we
1152 // should always be controlling in that case.
1153 (!jsep_transport->remote_description() ||
1154 jsep_transport->remote_description()->transport_desc.ice_mode !=
1155 cricket::ICEMODE_LITE)) {
1156 ice_role = (type == SdpType::kOffer) ? cricket::ICEROLE_CONTROLLING
1157 : cricket::ICEROLE_CONTROLLED;
1158 }
1159 } else {
1160 // If our role is cricket::ICEROLE_CONTROLLED and the remote endpoint
1161 // supports only ice_lite, this local endpoint should take the CONTROLLING
1162 // role.
1163 // TODO(deadbeef): This is a session-level attribute, so it really shouldn't
1164 // be in a TransportDescription in the first place...
1165 if (ice_role_ == cricket::ICEROLE_CONTROLLED &&
1166 tdesc.ice_mode == cricket::ICEMODE_LITE) {
1167 ice_role = cricket::ICEROLE_CONTROLLING;
1168 }
1169
1170 // If we use ICE Lite and the remote endpoint uses the full implementation
1171 // of ICE, the local endpoint must take the controlled role, and the other
1172 // side must be the controlling role.
1173 if (jsep_transport->local_description() &&
1174 jsep_transport->local_description()->transport_desc.ice_mode ==
1175 cricket::ICEMODE_LITE &&
1176 ice_role_ == cricket::ICEROLE_CONTROLLING &&
Zhi Huange830e682018-03-30 10:48:35 -07001177 tdesc.ice_mode == cricket::ICEMODE_FULL) {
Zhi Huange818b6e2018-02-22 15:26:27 -08001178 ice_role = cricket::ICEROLE_CONTROLLED;
1179 }
1180 }
1181
1182 return ice_role;
1183}
1184
1185void JsepTransportController::OnTransportWritableState_n(
1186 rtc::PacketTransportInternal* transport) {
1187 RTC_DCHECK(network_thread_->IsCurrent());
1188 RTC_LOG(LS_INFO) << " Transport " << transport->transport_name()
1189 << " writability changed to " << transport->writable()
1190 << ".";
1191 UpdateAggregateStates_n();
1192}
1193
1194void JsepTransportController::OnTransportReceivingState_n(
1195 rtc::PacketTransportInternal* transport) {
1196 RTC_DCHECK(network_thread_->IsCurrent());
1197 UpdateAggregateStates_n();
1198}
1199
1200void JsepTransportController::OnTransportGatheringState_n(
1201 cricket::IceTransportInternal* transport) {
1202 RTC_DCHECK(network_thread_->IsCurrent());
1203 UpdateAggregateStates_n();
1204}
1205
1206void JsepTransportController::OnTransportCandidateGathered_n(
1207 cricket::IceTransportInternal* transport,
1208 const cricket::Candidate& candidate) {
1209 RTC_DCHECK(network_thread_->IsCurrent());
1210
1211 // We should never signal peer-reflexive candidates.
1212 if (candidate.type() == cricket::PRFLX_PORT_TYPE) {
1213 RTC_NOTREACHED();
1214 return;
1215 }
Steve Antond25828a2018-08-31 13:06:05 -07001216 std::string transport_name = transport->transport_name();
1217 invoker_.AsyncInvoke<void>(
1218 RTC_FROM_HERE, signaling_thread_, [this, transport_name, candidate] {
1219 SignalIceCandidatesGathered(transport_name, {candidate});
1220 });
Zhi Huange818b6e2018-02-22 15:26:27 -08001221}
1222
1223void JsepTransportController::OnTransportCandidatesRemoved_n(
1224 cricket::IceTransportInternal* transport,
1225 const cricket::Candidates& candidates) {
1226 invoker_.AsyncInvoke<void>(
1227 RTC_FROM_HERE, signaling_thread_,
Steve Antond25828a2018-08-31 13:06:05 -07001228 [this, candidates] { SignalIceCandidatesRemoved(candidates); });
Zhi Huange818b6e2018-02-22 15:26:27 -08001229}
1230
1231void JsepTransportController::OnTransportRoleConflict_n(
1232 cricket::IceTransportInternal* transport) {
1233 RTC_DCHECK(network_thread_->IsCurrent());
1234 // Note: since the role conflict is handled entirely on the network thread,
1235 // we don't need to worry about role conflicts occurring on two ports at
1236 // once. The first one encountered should immediately reverse the role.
1237 cricket::IceRole reversed_role = (ice_role_ == cricket::ICEROLE_CONTROLLING)
1238 ? cricket::ICEROLE_CONTROLLED
1239 : cricket::ICEROLE_CONTROLLING;
1240 RTC_LOG(LS_INFO) << "Got role conflict; switching to "
1241 << (reversed_role == cricket::ICEROLE_CONTROLLING
1242 ? "controlling"
1243 : "controlled")
1244 << " role.";
1245 SetIceRole_n(reversed_role);
1246}
1247
1248void JsepTransportController::OnTransportStateChanged_n(
1249 cricket::IceTransportInternal* transport) {
1250 RTC_DCHECK(network_thread_->IsCurrent());
1251 RTC_LOG(LS_INFO) << transport->transport_name() << " Transport "
1252 << transport->component()
1253 << " state changed. Check if state is complete.";
1254 UpdateAggregateStates_n();
1255}
1256
Bjorn Mellem175aa2e2018-11-08 11:23:22 -08001257void JsepTransportController::OnMediaTransportStateChanged_n() {
1258 SignalMediaTransportStateChanged();
1259 UpdateAggregateStates_n();
1260}
1261
Zhi Huange818b6e2018-02-22 15:26:27 -08001262void JsepTransportController::UpdateAggregateStates_n() {
1263 RTC_DCHECK(network_thread_->IsCurrent());
1264
1265 auto dtls_transports = GetDtlsTransports();
1266 cricket::IceConnectionState new_connection_state =
1267 cricket::kIceConnectionConnecting;
Jonas Olsson635474e2018-10-18 15:58:17 +02001268 PeerConnectionInterface::IceConnectionState new_ice_connection_state =
1269 PeerConnectionInterface::IceConnectionState::kIceConnectionNew;
1270 PeerConnectionInterface::PeerConnectionState new_combined_state =
1271 PeerConnectionInterface::PeerConnectionState::kNew;
Zhi Huange818b6e2018-02-22 15:26:27 -08001272 cricket::IceGatheringState new_gathering_state = cricket::kIceGatheringNew;
1273 bool any_failed = false;
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001274
1275 // TODO(http://bugs.webrtc.org/9719) If(when) media_transport disables
1276 // dtls_transports entirely, the below line will have to be changed to account
1277 // for the fact that dtls transports might be absent.
Zhi Huange818b6e2018-02-22 15:26:27 -08001278 bool all_connected = !dtls_transports.empty();
1279 bool all_completed = !dtls_transports.empty();
1280 bool any_gathering = false;
1281 bool all_done_gathering = !dtls_transports.empty();
Jonas Olsson635474e2018-10-18 15:58:17 +02001282
1283 std::map<IceTransportState, int> ice_state_counts;
1284 std::map<cricket::DtlsTransportState, int> dtls_state_counts;
1285
Zhi Huange818b6e2018-02-22 15:26:27 -08001286 for (const auto& dtls : dtls_transports) {
1287 any_failed = any_failed || dtls->ice_transport()->GetState() ==
1288 cricket::IceTransportState::STATE_FAILED;
1289 all_connected = all_connected && dtls->writable();
1290 all_completed =
1291 all_completed && dtls->writable() &&
1292 dtls->ice_transport()->GetState() ==
1293 cricket::IceTransportState::STATE_COMPLETED &&
1294 dtls->ice_transport()->GetIceRole() == cricket::ICEROLE_CONTROLLING &&
1295 dtls->ice_transport()->gathering_state() ==
1296 cricket::kIceGatheringComplete;
1297 any_gathering = any_gathering || dtls->ice_transport()->gathering_state() !=
1298 cricket::kIceGatheringNew;
1299 all_done_gathering =
1300 all_done_gathering && dtls->ice_transport()->gathering_state() ==
1301 cricket::kIceGatheringComplete;
Jonas Olsson635474e2018-10-18 15:58:17 +02001302
1303 dtls_state_counts[dtls->dtls_state()]++;
1304 ice_state_counts[dtls->ice_transport()->GetIceTransportState()]++;
Zhi Huange818b6e2018-02-22 15:26:27 -08001305 }
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001306
1307 for (auto it = jsep_transports_by_name_.begin();
1308 it != jsep_transports_by_name_.end(); ++it) {
1309 auto jsep_transport = it->second.get();
1310 if (!jsep_transport->media_transport()) {
1311 continue;
1312 }
1313
1314 // There is no 'kIceConnectionDisconnected', so we only need to handle
1315 // connected and completed.
1316 // We treat kClosed as failed, because if it happens before shutting down
1317 // media transports it means that there was a failure.
1318 // MediaTransportInterface allows to flip back and forth between kWritable
1319 // and kPending, but there does not exist an implementation that does that,
1320 // and the contract of jsep transport controller doesn't quite expect that.
1321 // When this happens, we would go from connected to connecting state, but
1322 // this may change in future.
1323 any_failed |= jsep_transport->media_transport_state() ==
1324 webrtc::MediaTransportState::kClosed;
1325 all_completed &= jsep_transport->media_transport_state() ==
1326 webrtc::MediaTransportState::kWritable;
1327 all_connected &= jsep_transport->media_transport_state() ==
1328 webrtc::MediaTransportState::kWritable;
1329 }
1330
Zhi Huange818b6e2018-02-22 15:26:27 -08001331 if (any_failed) {
1332 new_connection_state = cricket::kIceConnectionFailed;
1333 } else if (all_completed) {
1334 new_connection_state = cricket::kIceConnectionCompleted;
1335 } else if (all_connected) {
1336 new_connection_state = cricket::kIceConnectionConnected;
1337 }
1338 if (ice_connection_state_ != new_connection_state) {
1339 ice_connection_state_ = new_connection_state;
Steve Antond25828a2018-08-31 13:06:05 -07001340 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_,
1341 [this, new_connection_state] {
1342 SignalIceConnectionState(new_connection_state);
1343 });
Zhi Huange818b6e2018-02-22 15:26:27 -08001344 }
1345
Jonas Olsson635474e2018-10-18 15:58:17 +02001346 // Compute the current RTCIceConnectionState as described in
1347 // https://www.w3.org/TR/webrtc/#dom-rtciceconnectionstate.
1348 // The PeerConnection is responsible for handling the "closed" state.
1349 int total_ice_checking = ice_state_counts[IceTransportState::kChecking];
1350 int total_ice_connected = ice_state_counts[IceTransportState::kConnected];
1351 int total_ice_completed = ice_state_counts[IceTransportState::kCompleted];
1352 int total_ice_failed = ice_state_counts[IceTransportState::kFailed];
1353 int total_ice_disconnected =
1354 ice_state_counts[IceTransportState::kDisconnected];
1355 int total_ice_closed = ice_state_counts[IceTransportState::kClosed];
1356 int total_ice_new = ice_state_counts[IceTransportState::kNew];
1357 int total_ice = dtls_transports.size();
1358
1359 if (total_ice_failed > 0) {
1360 // Any of the RTCIceTransports are in the "failed" state.
1361 new_ice_connection_state = PeerConnectionInterface::kIceConnectionFailed;
1362 } else if (total_ice_disconnected > 0) {
1363 // Any of the RTCIceTransports are in the "disconnected" state and none of
1364 // them are in the "failed" state.
1365 new_ice_connection_state =
1366 PeerConnectionInterface::kIceConnectionDisconnected;
1367 } else if (total_ice_checking > 0) {
1368 // Any of the RTCIceTransports are in the "checking" state and none of them
1369 // are in the "disconnected" or "failed" state.
1370 new_ice_connection_state = PeerConnectionInterface::kIceConnectionChecking;
1371 } else if (total_ice_completed + total_ice_closed == total_ice &&
1372 total_ice_completed > 0) {
1373 // All RTCIceTransports are in the "completed" or "closed" state and at
1374 // least one of them is in the "completed" state.
1375 new_ice_connection_state = PeerConnectionInterface::kIceConnectionCompleted;
1376 } else if (total_ice_connected + total_ice_completed + total_ice_closed ==
1377 total_ice &&
1378 total_ice_connected > 0) {
1379 // All RTCIceTransports are in the "connected", "completed" or "closed"
1380 // state and at least one of them is in the "connected" state.
1381 new_ice_connection_state = PeerConnectionInterface::kIceConnectionConnected;
1382 } else if ((total_ice_new > 0 &&
1383 total_ice_checking + total_ice_disconnected + total_ice_failed ==
1384 0) ||
1385 total_ice == total_ice_closed) {
1386 // Any of the RTCIceTransports are in the "new" state and none of them are
1387 // in the "checking", "disconnected" or "failed" state, or all
1388 // RTCIceTransports are in the "closed" state, or there are no transports.
1389 new_ice_connection_state = PeerConnectionInterface::kIceConnectionNew;
1390 } else {
1391 RTC_NOTREACHED();
1392 }
1393
1394 if (standardized_ice_connection_state_ != new_ice_connection_state) {
1395 standardized_ice_connection_state_ = new_ice_connection_state;
1396 invoker_.AsyncInvoke<void>(
1397 RTC_FROM_HERE, signaling_thread_, [this, new_ice_connection_state] {
1398 SignalStandardizedIceConnectionState(new_ice_connection_state);
1399 });
1400 }
1401
1402 // Compute the current RTCPeerConnectionState as described in
1403 // https://www.w3.org/TR/webrtc/#dom-rtcpeerconnectionstate.
1404 // The PeerConnection is responsible for handling the "closed" state.
1405 // Note that "connecting" is only a valid state for DTLS transports while
1406 // "checking", "completed" and "disconnected" are only valid for ICE
1407 // transports.
1408 int total_connected = total_ice_connected +
1409 dtls_state_counts[cricket::DTLS_TRANSPORT_CONNECTED];
1410 int total_dtls_connecting =
1411 dtls_state_counts[cricket::DTLS_TRANSPORT_CONNECTING];
1412 int total_failed =
1413 total_ice_failed + dtls_state_counts[cricket::DTLS_TRANSPORT_FAILED];
1414 int total_closed =
1415 total_ice_closed + dtls_state_counts[cricket::DTLS_TRANSPORT_CLOSED];
1416 int total_new =
1417 total_ice_new + dtls_state_counts[cricket::DTLS_TRANSPORT_NEW];
1418 int total_transports = total_ice * 2;
1419
1420 if (total_failed > 0) {
1421 // Any of the RTCIceTransports or RTCDtlsTransports are in a "failed" state.
1422 new_combined_state = PeerConnectionInterface::PeerConnectionState::kFailed;
1423 } else if (total_ice_disconnected > 0 &&
1424 total_dtls_connecting + total_ice_checking == 0) {
1425 // Any of the RTCIceTransports or RTCDtlsTransports are in the
1426 // "disconnected" state and none of them are in the "failed" or "connecting"
1427 // or "checking" state.
1428 new_combined_state =
1429 PeerConnectionInterface::PeerConnectionState::kDisconnected;
1430 } else if (total_dtls_connecting + total_ice_checking > 0) {
1431 // Any of the RTCIceTransports or RTCDtlsTransports are in the "connecting"
1432 // or "checking" state and none of them is in the "failed" state.
1433 new_combined_state =
1434 PeerConnectionInterface::PeerConnectionState::kConnecting;
1435 } else if (total_connected + total_ice_completed + total_closed ==
1436 total_transports &&
1437 total_connected + total_ice_completed > 0) {
1438 // All RTCIceTransports and RTCDtlsTransports are in the "connected",
1439 // "completed" or "closed" state and at least one of them is in the
1440 // "connected" or "completed" state.
1441 new_combined_state =
1442 PeerConnectionInterface::PeerConnectionState::kConnected;
1443 } else if ((total_new > 0 && total_dtls_connecting + total_ice_checking +
1444 total_failed + total_ice_disconnected ==
1445 0) ||
1446 total_transports == total_closed) {
1447 // Any of the RTCIceTransports or RTCDtlsTransports are in the "new" state
1448 // and none of the transports are in the "connecting", "checking", "failed"
1449 // or "disconnected" state, or all transports are in the "closed" state, or
1450 // there are no transports.
1451 //
1452 // Note that if none of the other conditions hold this is guaranteed to be
1453 // true.
1454 new_combined_state = PeerConnectionInterface::PeerConnectionState::kNew;
1455 } else {
1456 RTC_NOTREACHED();
1457 }
1458
1459 if (combined_connection_state_ != new_combined_state) {
1460 combined_connection_state_ = new_combined_state;
1461 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_,
1462 [this, new_combined_state] {
1463 SignalConnectionState(new_combined_state);
1464 });
1465 }
1466
Zhi Huange818b6e2018-02-22 15:26:27 -08001467 if (all_done_gathering) {
1468 new_gathering_state = cricket::kIceGatheringComplete;
1469 } else if (any_gathering) {
1470 new_gathering_state = cricket::kIceGatheringGathering;
1471 }
1472 if (ice_gathering_state_ != new_gathering_state) {
1473 ice_gathering_state_ = new_gathering_state;
Steve Antond25828a2018-08-31 13:06:05 -07001474 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_,
1475 [this, new_gathering_state] {
1476 SignalIceGatheringState(new_gathering_state);
1477 });
Zhi Huange818b6e2018-02-22 15:26:27 -08001478 }
1479}
1480
1481void JsepTransportController::OnDtlsHandshakeError(
1482 rtc::SSLHandshakeError error) {
1483 SignalDtlsHandshakeError(error);
1484}
1485
1486} // namespace webrtc