blob: fd6bd0de23e6fcc9b3d25ff9d6a7a083c72d871d [file] [log] [blame]
Zhi Huange818b6e2018-02-22 15:26:27 -08001/*
2 * Copyright 2018 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.h"
Zhi Huange818b6e2018-02-22 15:26:27 -080012
Yves Gerey3e707812018-11-28 16:47:49 +010013#include <stddef.h>
14#include <stdint.h>
Zhi Huange818b6e2018-02-22 15:26:27 -080015#include <memory>
Yves Gerey3e707812018-11-28 16:47:49 +010016#include <type_traits>
Zhi Huange818b6e2018-02-22 15:26:27 -080017#include <utility> // for std::pair
18
Yves Gerey3e707812018-11-28 16:47:49 +010019#include "absl/memory/memory.h"
20#include "api/array_view.h"
Zhi Huange818b6e2018-02-22 15:26:27 -080021#include "api/candidate.h"
Steve Anton10542f22019-01-11 09:11:00 -080022#include "p2p/base/p2p_constants.h"
23#include "p2p/base/p2p_transport_channel.h"
Zhi Huange818b6e2018-02-22 15:26:27 -080024#include "rtc_base/checks.h"
Steve Anton10542f22019-01-11 09:11:00 -080025#include "rtc_base/copy_on_write_buffer.h"
Zhi Huange818b6e2018-02-22 15:26:27 -080026#include "rtc_base/logging.h"
Zhi Huang365381f2018-04-13 16:44:34 -070027#include "rtc_base/strings/string_builder.h"
Zhi Huange818b6e2018-02-22 15:26:27 -080028
29using webrtc::SdpType;
30
31namespace cricket {
32
33static bool VerifyIceParams(const JsepTransportDescription& jsep_description) {
34 // For legacy protocols.
35 // TODO(zhihuang): Remove this once the legacy protocol is no longer
36 // supported.
37 if (jsep_description.transport_desc.ice_ufrag.empty() &&
38 jsep_description.transport_desc.ice_pwd.empty()) {
39 return true;
40 }
41
42 if (jsep_description.transport_desc.ice_ufrag.length() <
43 ICE_UFRAG_MIN_LENGTH ||
44 jsep_description.transport_desc.ice_ufrag.length() >
45 ICE_UFRAG_MAX_LENGTH) {
46 return false;
47 }
48 if (jsep_description.transport_desc.ice_pwd.length() < ICE_PWD_MIN_LENGTH ||
49 jsep_description.transport_desc.ice_pwd.length() > ICE_PWD_MAX_LENGTH) {
50 return false;
51 }
52 return true;
53}
54
55JsepTransportDescription::JsepTransportDescription() {}
56
57JsepTransportDescription::JsepTransportDescription(
58 bool rtcp_mux_enabled,
59 const std::vector<CryptoParams>& cryptos,
60 const std::vector<int>& encrypted_header_extension_ids,
Zhi Huange830e682018-03-30 10:48:35 -070061 int rtp_abs_sendtime_extn_id,
Zhi Huange818b6e2018-02-22 15:26:27 -080062 const TransportDescription& transport_desc)
63 : rtcp_mux_enabled(rtcp_mux_enabled),
64 cryptos(cryptos),
65 encrypted_header_extension_ids(encrypted_header_extension_ids),
Zhi Huange830e682018-03-30 10:48:35 -070066 rtp_abs_sendtime_extn_id(rtp_abs_sendtime_extn_id),
Zhi Huange818b6e2018-02-22 15:26:27 -080067 transport_desc(transport_desc) {}
68
69JsepTransportDescription::JsepTransportDescription(
70 const JsepTransportDescription& from)
71 : rtcp_mux_enabled(from.rtcp_mux_enabled),
72 cryptos(from.cryptos),
73 encrypted_header_extension_ids(from.encrypted_header_extension_ids),
Zhi Huange830e682018-03-30 10:48:35 -070074 rtp_abs_sendtime_extn_id(from.rtp_abs_sendtime_extn_id),
Zhi Huange818b6e2018-02-22 15:26:27 -080075 transport_desc(from.transport_desc) {}
76
77JsepTransportDescription::~JsepTransportDescription() = default;
78
79JsepTransportDescription& JsepTransportDescription::operator=(
80 const JsepTransportDescription& from) {
81 if (this == &from) {
82 return *this;
83 }
84 rtcp_mux_enabled = from.rtcp_mux_enabled;
85 cryptos = from.cryptos;
86 encrypted_header_extension_ids = from.encrypted_header_extension_ids;
Zhi Huange830e682018-03-30 10:48:35 -070087 rtp_abs_sendtime_extn_id = from.rtp_abs_sendtime_extn_id;
Zhi Huange818b6e2018-02-22 15:26:27 -080088 transport_desc = from.transport_desc;
89
90 return *this;
91}
92
Zhi Huang365381f2018-04-13 16:44:34 -070093JsepTransport::JsepTransport(
Zhi Huange818b6e2018-02-22 15:26:27 -080094 const std::string& mid,
95 const rtc::scoped_refptr<rtc::RTCCertificate>& local_certificate,
96 std::unique_ptr<webrtc::RtpTransport> unencrypted_rtp_transport,
97 std::unique_ptr<webrtc::SrtpTransport> sdes_transport,
98 std::unique_ptr<webrtc::DtlsSrtpTransport> dtls_srtp_transport,
99 std::unique_ptr<DtlsTransportInternal> rtp_dtls_transport,
Anton Sukhanov7940da02018-10-10 10:34:49 -0700100 std::unique_ptr<DtlsTransportInternal> rtcp_dtls_transport,
101 std::unique_ptr<webrtc::MediaTransportInterface> media_transport)
Zhi Huange818b6e2018-02-22 15:26:27 -0800102 : mid_(mid),
103 local_certificate_(local_certificate),
Harald Alvestrandad88c882018-11-28 16:47:46 +0100104 rtp_dtls_transport_(
105 rtp_dtls_transport ? new rtc::RefCountedObject<webrtc::DtlsTransport>(
106 std::move(rtp_dtls_transport))
107 : nullptr),
108 rtcp_dtls_transport_(
109 rtcp_dtls_transport
110 ? new rtc::RefCountedObject<webrtc::DtlsTransport>(
111 std::move(rtcp_dtls_transport))
112 : nullptr),
Anton Sukhanov7940da02018-10-10 10:34:49 -0700113 media_transport_(std::move(media_transport)) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800114 RTC_DCHECK(rtp_dtls_transport_);
115 if (unencrypted_rtp_transport) {
116 RTC_DCHECK(!sdes_transport);
117 RTC_DCHECK(!dtls_srtp_transport);
118 unencrypted_rtp_transport_ = std::move(unencrypted_rtp_transport);
119 } else if (sdes_transport) {
120 RTC_DCHECK(!unencrypted_rtp_transport);
121 RTC_DCHECK(!dtls_srtp_transport);
122 sdes_transport_ = std::move(sdes_transport);
123 } else {
124 RTC_DCHECK(dtls_srtp_transport);
125 RTC_DCHECK(!unencrypted_rtp_transport);
126 RTC_DCHECK(!sdes_transport);
127 dtls_srtp_transport_ = std::move(dtls_srtp_transport);
128 }
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700129
130 if (media_transport_) {
131 media_transport_->SetMediaTransportStateCallback(this);
132 }
Zhi Huange818b6e2018-02-22 15:26:27 -0800133}
134
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700135JsepTransport::~JsepTransport() {
136 if (media_transport_) {
137 media_transport_->SetMediaTransportStateCallback(nullptr);
Anton Sukhanovd644feb2018-12-06 09:00:39 -0800138
139 // Make sure we delete media transport before ICE.
140 media_transport_.reset();
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700141 }
Harald Alvestrand628f37a2018-12-06 10:55:20 +0100142 // Clear all DtlsTransports. There may be pointers to these from
143 // other places, so we can't assume they'll be deleted by the destructor.
Harald Alvestrandd02541e2019-01-03 12:43:28 +0100144 rtp_dtls_transport_->Clear();
Harald Alvestrand628f37a2018-12-06 10:55:20 +0100145 if (rtcp_dtls_transport_) {
Harald Alvestrandd02541e2019-01-03 12:43:28 +0100146 rtcp_dtls_transport_->Clear();
Harald Alvestrand628f37a2018-12-06 10:55:20 +0100147 }
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700148}
Zhi Huange818b6e2018-02-22 15:26:27 -0800149
Zhi Huang365381f2018-04-13 16:44:34 -0700150webrtc::RTCError JsepTransport::SetLocalJsepTransportDescription(
Zhi Huange818b6e2018-02-22 15:26:27 -0800151 const JsepTransportDescription& jsep_description,
152 SdpType type) {
153 webrtc::RTCError error;
154
155 if (!VerifyIceParams(jsep_description)) {
156 return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
157 "Invalid ice-ufrag or ice-pwd length.");
158 }
159
160 if (!SetRtcpMux(jsep_description.rtcp_mux_enabled, type,
161 ContentSource::CS_LOCAL)) {
162 return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
163 "Failed to setup RTCP mux.");
164 }
165
166 // If doing SDES, setup the SDES crypto parameters.
167 if (sdes_transport_) {
168 RTC_DCHECK(!unencrypted_rtp_transport_);
169 RTC_DCHECK(!dtls_srtp_transport_);
170 if (!SetSdes(jsep_description.cryptos,
171 jsep_description.encrypted_header_extension_ids, type,
172 ContentSource::CS_LOCAL)) {
173 return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
174 "Failed to setup SDES crypto parameters.");
175 }
176 } else if (dtls_srtp_transport_) {
177 RTC_DCHECK(!unencrypted_rtp_transport_);
178 RTC_DCHECK(!sdes_transport_);
179 dtls_srtp_transport_->UpdateRecvEncryptedHeaderExtensionIds(
180 jsep_description.encrypted_header_extension_ids);
181 }
182
183 bool ice_restarting =
184 local_description_ != nullptr &&
185 IceCredentialsChanged(local_description_->transport_desc.ice_ufrag,
186 local_description_->transport_desc.ice_pwd,
187 jsep_description.transport_desc.ice_ufrag,
188 jsep_description.transport_desc.ice_pwd);
189 local_description_.reset(new JsepTransportDescription(jsep_description));
190
191 rtc::SSLFingerprint* local_fp =
192 local_description_->transport_desc.identity_fingerprint.get();
193
194 if (!local_fp) {
195 local_certificate_ = nullptr;
196 } else {
197 error = VerifyCertificateFingerprint(local_certificate_.get(), local_fp);
198 if (!error.ok()) {
199 local_description_.reset();
200 return error;
201 }
202 }
203
Harald Alvestrand628f37a2018-12-06 10:55:20 +0100204 RTC_DCHECK(rtp_dtls_transport_->internal());
Harald Alvestrandad88c882018-11-28 16:47:46 +0100205 SetLocalIceParameters(rtp_dtls_transport_->internal()->ice_transport());
Zhi Huange818b6e2018-02-22 15:26:27 -0800206
207 if (rtcp_dtls_transport_) {
Harald Alvestrand628f37a2018-12-06 10:55:20 +0100208 RTC_DCHECK(rtcp_dtls_transport_->internal());
Harald Alvestrandad88c882018-11-28 16:47:46 +0100209 SetLocalIceParameters(rtcp_dtls_transport_->internal()->ice_transport());
Zhi Huange818b6e2018-02-22 15:26:27 -0800210 }
211
212 // If PRANSWER/ANSWER is set, we should decide transport protocol type.
213 if (type == SdpType::kPrAnswer || type == SdpType::kAnswer) {
214 error = NegotiateAndSetDtlsParameters(type);
215 }
216 if (!error.ok()) {
217 local_description_.reset();
218 return error;
219 }
220
221 if (needs_ice_restart_ && ice_restarting) {
222 needs_ice_restart_ = false;
223 RTC_LOG(LS_VERBOSE) << "needs-ice-restart flag cleared for transport "
224 << mid();
225 }
226
227 return webrtc::RTCError::OK();
228}
229
Zhi Huang365381f2018-04-13 16:44:34 -0700230webrtc::RTCError JsepTransport::SetRemoteJsepTransportDescription(
Zhi Huange818b6e2018-02-22 15:26:27 -0800231 const JsepTransportDescription& jsep_description,
232 webrtc::SdpType type) {
233 webrtc::RTCError error;
234
235 if (!VerifyIceParams(jsep_description)) {
236 remote_description_.reset();
237 return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
238 "Invalid ice-ufrag or ice-pwd length.");
239 }
240
241 if (!SetRtcpMux(jsep_description.rtcp_mux_enabled, type,
242 ContentSource::CS_REMOTE)) {
243 return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
244 "Failed to setup RTCP mux.");
245 }
246
247 // If doing SDES, setup the SDES crypto parameters.
248 if (sdes_transport_) {
249 RTC_DCHECK(!unencrypted_rtp_transport_);
250 RTC_DCHECK(!dtls_srtp_transport_);
251 if (!SetSdes(jsep_description.cryptos,
252 jsep_description.encrypted_header_extension_ids, type,
253 ContentSource::CS_REMOTE)) {
254 return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
255 "Failed to setup SDES crypto parameters.");
256 }
Zhi Huange830e682018-03-30 10:48:35 -0700257 sdes_transport_->CacheRtpAbsSendTimeHeaderExtension(
258 jsep_description.rtp_abs_sendtime_extn_id);
Zhi Huange818b6e2018-02-22 15:26:27 -0800259 } else if (dtls_srtp_transport_) {
260 RTC_DCHECK(!unencrypted_rtp_transport_);
261 RTC_DCHECK(!sdes_transport_);
262 dtls_srtp_transport_->UpdateSendEncryptedHeaderExtensionIds(
263 jsep_description.encrypted_header_extension_ids);
Zhi Huange830e682018-03-30 10:48:35 -0700264 dtls_srtp_transport_->CacheRtpAbsSendTimeHeaderExtension(
265 jsep_description.rtp_abs_sendtime_extn_id);
Zhi Huange818b6e2018-02-22 15:26:27 -0800266 }
267
268 remote_description_.reset(new JsepTransportDescription(jsep_description));
Harald Alvestrand628f37a2018-12-06 10:55:20 +0100269 RTC_DCHECK(rtp_dtls_transport_->internal());
Harald Alvestrandad88c882018-11-28 16:47:46 +0100270 SetRemoteIceParameters(rtp_dtls_transport_->internal()->ice_transport());
Zhi Huange818b6e2018-02-22 15:26:27 -0800271
272 if (rtcp_dtls_transport_) {
Harald Alvestrand628f37a2018-12-06 10:55:20 +0100273 RTC_DCHECK(rtcp_dtls_transport_->internal());
Harald Alvestrandad88c882018-11-28 16:47:46 +0100274 SetRemoteIceParameters(rtcp_dtls_transport_->internal()->ice_transport());
Zhi Huange818b6e2018-02-22 15:26:27 -0800275 }
276
277 // If PRANSWER/ANSWER is set, we should decide transport protocol type.
278 if (type == SdpType::kPrAnswer || type == SdpType::kAnswer) {
279 error = NegotiateAndSetDtlsParameters(SdpType::kOffer);
280 }
281 if (!error.ok()) {
282 remote_description_.reset();
283 return error;
284 }
285 return webrtc::RTCError::OK();
286}
287
Zhi Huang365381f2018-04-13 16:44:34 -0700288webrtc::RTCError JsepTransport::AddRemoteCandidates(
Zhi Huange818b6e2018-02-22 15:26:27 -0800289 const Candidates& candidates) {
Henrik Boström5d8f8fa2018-04-13 15:22:50 +0000290 if (!local_description_ || !remote_description_) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800291 return webrtc::RTCError(webrtc::RTCErrorType::INVALID_STATE,
292 mid() +
293 " is not ready to use the remote candidate "
Henrik Boström5d8f8fa2018-04-13 15:22:50 +0000294 "because the local or remote description is "
295 "not set.");
Zhi Huange818b6e2018-02-22 15:26:27 -0800296 }
297
298 for (const cricket::Candidate& candidate : candidates) {
299 auto transport =
300 candidate.component() == cricket::ICE_CANDIDATE_COMPONENT_RTP
Harald Alvestrandad88c882018-11-28 16:47:46 +0100301 ? rtp_dtls_transport_
302 : rtcp_dtls_transport_;
Zhi Huange818b6e2018-02-22 15:26:27 -0800303 if (!transport) {
304 return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
305 "Candidate has an unknown component: " +
306 candidate.ToString() + " for mid " + mid());
307 }
Harald Alvestrand628f37a2018-12-06 10:55:20 +0100308 RTC_DCHECK(transport->internal() && transport->internal()->ice_transport());
Harald Alvestrandad88c882018-11-28 16:47:46 +0100309 transport->internal()->ice_transport()->AddRemoteCandidate(candidate);
Zhi Huange818b6e2018-02-22 15:26:27 -0800310 }
311 return webrtc::RTCError::OK();
312}
313
Zhi Huang365381f2018-04-13 16:44:34 -0700314void JsepTransport::SetNeedsIceRestartFlag() {
Zhi Huange818b6e2018-02-22 15:26:27 -0800315 if (!needs_ice_restart_) {
316 needs_ice_restart_ = true;
317 RTC_LOG(LS_VERBOSE) << "needs-ice-restart flag set for transport " << mid();
318 }
319}
320
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200321absl::optional<rtc::SSLRole> JsepTransport::GetDtlsRole() const {
Zhi Huange818b6e2018-02-22 15:26:27 -0800322 RTC_DCHECK(rtp_dtls_transport_);
Harald Alvestrand628f37a2018-12-06 10:55:20 +0100323 RTC_DCHECK(rtp_dtls_transport_->internal());
Zhi Huange818b6e2018-02-22 15:26:27 -0800324 rtc::SSLRole dtls_role;
Harald Alvestrandad88c882018-11-28 16:47:46 +0100325 if (!rtp_dtls_transport_->internal()->GetDtlsRole(&dtls_role)) {
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200326 return absl::optional<rtc::SSLRole>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800327 }
328
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200329 return absl::optional<rtc::SSLRole>(dtls_role);
Zhi Huange818b6e2018-02-22 15:26:27 -0800330}
331
Zhi Huang365381f2018-04-13 16:44:34 -0700332bool JsepTransport::GetStats(TransportStats* stats) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800333 stats->transport_name = mid();
334 stats->channel_stats.clear();
Harald Alvestrand628f37a2018-12-06 10:55:20 +0100335 RTC_DCHECK(rtp_dtls_transport_->internal());
Harald Alvestrandad88c882018-11-28 16:47:46 +0100336 bool ret = GetTransportStats(rtp_dtls_transport_->internal(), stats);
Zhi Huange818b6e2018-02-22 15:26:27 -0800337 if (rtcp_dtls_transport_) {
Harald Alvestrand628f37a2018-12-06 10:55:20 +0100338 RTC_DCHECK(rtcp_dtls_transport_->internal());
Harald Alvestrandad88c882018-11-28 16:47:46 +0100339 ret &= GetTransportStats(rtcp_dtls_transport_->internal(), stats);
Zhi Huange818b6e2018-02-22 15:26:27 -0800340 }
341 return ret;
342}
343
Zhi Huang365381f2018-04-13 16:44:34 -0700344webrtc::RTCError JsepTransport::VerifyCertificateFingerprint(
Zhi Huange818b6e2018-02-22 15:26:27 -0800345 const rtc::RTCCertificate* certificate,
346 const rtc::SSLFingerprint* fingerprint) const {
347 if (!fingerprint) {
348 return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
349 "No fingerprint");
350 }
351 if (!certificate) {
352 return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
353 "Fingerprint provided but no identity available.");
354 }
Steve Anton4905edb2018-10-15 19:27:44 -0700355 std::unique_ptr<rtc::SSLFingerprint> fp_tmp =
356 rtc::SSLFingerprint::CreateUnique(fingerprint->algorithm,
357 *certificate->identity());
Zhi Huange818b6e2018-02-22 15:26:27 -0800358 RTC_DCHECK(fp_tmp.get() != NULL);
359 if (*fp_tmp == *fingerprint) {
360 return webrtc::RTCError::OK();
361 }
Zhi Huang365381f2018-04-13 16:44:34 -0700362 char ss_buf[1024];
363 rtc::SimpleStringBuilder desc(ss_buf);
Zhi Huange818b6e2018-02-22 15:26:27 -0800364 desc << "Local fingerprint does not match identity. Expected: ";
365 desc << fp_tmp->ToString();
366 desc << " Got: " << fingerprint->ToString();
Zhi Huang365381f2018-04-13 16:44:34 -0700367 return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
368 std::string(desc.str()));
Zhi Huange818b6e2018-02-22 15:26:27 -0800369}
370
Zhi Huangb57e1692018-06-12 11:41:11 -0700371void JsepTransport::SetActiveResetSrtpParams(bool active_reset_srtp_params) {
372 if (dtls_srtp_transport_) {
373 RTC_LOG(INFO)
374 << "Setting active_reset_srtp_params of DtlsSrtpTransport to: "
375 << active_reset_srtp_params;
376 dtls_srtp_transport_->SetActiveResetSrtpParams(active_reset_srtp_params);
377 }
378}
379
Zhi Huang365381f2018-04-13 16:44:34 -0700380void JsepTransport::SetLocalIceParameters(IceTransportInternal* ice_transport) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800381 RTC_DCHECK(ice_transport);
382 RTC_DCHECK(local_description_);
383 ice_transport->SetIceParameters(
384 local_description_->transport_desc.GetIceParameters());
385}
386
Zhi Huang365381f2018-04-13 16:44:34 -0700387void JsepTransport::SetRemoteIceParameters(
Zhi Huange818b6e2018-02-22 15:26:27 -0800388 IceTransportInternal* ice_transport) {
389 RTC_DCHECK(ice_transport);
390 RTC_DCHECK(remote_description_);
391 ice_transport->SetRemoteIceParameters(
392 remote_description_->transport_desc.GetIceParameters());
393 ice_transport->SetRemoteIceMode(remote_description_->transport_desc.ice_mode);
394}
395
Zhi Huang365381f2018-04-13 16:44:34 -0700396webrtc::RTCError JsepTransport::SetNegotiatedDtlsParameters(
Zhi Huange818b6e2018-02-22 15:26:27 -0800397 DtlsTransportInternal* dtls_transport,
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200398 absl::optional<rtc::SSLRole> dtls_role,
Zhi Huange818b6e2018-02-22 15:26:27 -0800399 rtc::SSLFingerprint* remote_fingerprint) {
400 RTC_DCHECK(dtls_transport);
401 // Set SSL role. Role must be set before fingerprint is applied, which
402 // initiates DTLS setup.
403 if (dtls_role && !dtls_transport->SetDtlsRole(*dtls_role)) {
404 return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
405 "Failed to set SSL role for the transport.");
406 }
407 // Apply remote fingerprint.
408 if (!remote_fingerprint ||
409 !dtls_transport->SetRemoteFingerprint(
410 remote_fingerprint->algorithm,
411 reinterpret_cast<const uint8_t*>(remote_fingerprint->digest.data()),
412 remote_fingerprint->digest.size())) {
413 return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
414 "Failed to apply remote fingerprint.");
415 }
416 return webrtc::RTCError::OK();
417}
418
Zhi Huang365381f2018-04-13 16:44:34 -0700419bool JsepTransport::SetRtcpMux(bool enable,
420 webrtc::SdpType type,
421 ContentSource source) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800422 bool ret = false;
423 switch (type) {
424 case SdpType::kOffer:
425 ret = rtcp_mux_negotiator_.SetOffer(enable, source);
426 break;
427 case SdpType::kPrAnswer:
428 // This may activate RTCP muxing, but we don't yet destroy the transport
429 // because the final answer may deactivate it.
430 ret = rtcp_mux_negotiator_.SetProvisionalAnswer(enable, source);
431 break;
432 case SdpType::kAnswer:
433 ret = rtcp_mux_negotiator_.SetAnswer(enable, source);
434 if (ret && rtcp_mux_negotiator_.IsActive()) {
435 ActivateRtcpMux();
436 }
437 break;
438 default:
439 RTC_NOTREACHED();
440 }
441
442 if (!ret) {
443 return false;
444 }
445
446 auto transport = rtp_transport();
447 transport->SetRtcpMuxEnabled(rtcp_mux_negotiator_.IsActive());
448 return ret;
449}
450
Zhi Huang365381f2018-04-13 16:44:34 -0700451void JsepTransport::ActivateRtcpMux() {
Zhi Huange818b6e2018-02-22 15:26:27 -0800452 if (unencrypted_rtp_transport_) {
453 RTC_DCHECK(!sdes_transport_);
454 RTC_DCHECK(!dtls_srtp_transport_);
455 unencrypted_rtp_transport_->SetRtcpPacketTransport(nullptr);
456 } else if (sdes_transport_) {
457 RTC_DCHECK(!unencrypted_rtp_transport_);
458 RTC_DCHECK(!dtls_srtp_transport_);
459 sdes_transport_->SetRtcpPacketTransport(nullptr);
460 } else {
461 RTC_DCHECK(dtls_srtp_transport_);
462 RTC_DCHECK(!unencrypted_rtp_transport_);
463 RTC_DCHECK(!sdes_transport_);
464 dtls_srtp_transport_->SetDtlsTransports(rtp_dtls_transport(),
465 /*rtcp_dtls_transport=*/nullptr);
466 }
Harald Alvestrandad88c882018-11-28 16:47:46 +0100467 rtcp_dtls_transport_ = nullptr; // Destroy this reference.
Zhi Huange818b6e2018-02-22 15:26:27 -0800468 // Notify the JsepTransportController to update the aggregate states.
469 SignalRtcpMuxActive();
470}
471
Zhi Huang365381f2018-04-13 16:44:34 -0700472bool JsepTransport::SetSdes(const std::vector<CryptoParams>& cryptos,
473 const std::vector<int>& encrypted_extension_ids,
474 webrtc::SdpType type,
475 ContentSource source) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800476 bool ret = false;
477 ret = sdes_negotiator_.Process(cryptos, type, source);
478 if (!ret) {
479 return ret;
480 }
481
482 if (source == ContentSource::CS_LOCAL) {
483 recv_extension_ids_ = std::move(encrypted_extension_ids);
484 } else {
485 send_extension_ids_ = std::move(encrypted_extension_ids);
486 }
487
488 // If setting an SDES answer succeeded, apply the negotiated parameters
489 // to the SRTP transport.
490 if ((type == SdpType::kPrAnswer || type == SdpType::kAnswer) && ret) {
491 if (sdes_negotiator_.send_cipher_suite() &&
492 sdes_negotiator_.recv_cipher_suite()) {
493 RTC_DCHECK(send_extension_ids_);
494 RTC_DCHECK(recv_extension_ids_);
495 ret = sdes_transport_->SetRtpParams(
496 *(sdes_negotiator_.send_cipher_suite()),
497 sdes_negotiator_.send_key().data(),
498 static_cast<int>(sdes_negotiator_.send_key().size()),
499 *(send_extension_ids_), *(sdes_negotiator_.recv_cipher_suite()),
500 sdes_negotiator_.recv_key().data(),
501 static_cast<int>(sdes_negotiator_.recv_key().size()),
502 *(recv_extension_ids_));
503 } else {
504 RTC_LOG(LS_INFO) << "No crypto keys are provided for SDES.";
505 if (type == SdpType::kAnswer) {
506 // Explicitly reset the |sdes_transport_| if no crypto param is
507 // provided in the answer. No need to call |ResetParams()| for
508 // |sdes_negotiator_| because it resets the params inside |SetAnswer|.
509 sdes_transport_->ResetParams();
510 }
511 }
512 }
513 return ret;
514}
515
Zhi Huang365381f2018-04-13 16:44:34 -0700516webrtc::RTCError JsepTransport::NegotiateAndSetDtlsParameters(
Zhi Huange818b6e2018-02-22 15:26:27 -0800517 SdpType local_description_type) {
518 if (!local_description_ || !remote_description_) {
519 return webrtc::RTCError(webrtc::RTCErrorType::INVALID_STATE,
520 "Applying an answer transport description "
521 "without applying any offer.");
522 }
523 std::unique_ptr<rtc::SSLFingerprint> remote_fingerprint;
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200524 absl::optional<rtc::SSLRole> negotiated_dtls_role;
Zhi Huange818b6e2018-02-22 15:26:27 -0800525
526 rtc::SSLFingerprint* local_fp =
527 local_description_->transport_desc.identity_fingerprint.get();
528 rtc::SSLFingerprint* remote_fp =
529 remote_description_->transport_desc.identity_fingerprint.get();
530 if (remote_fp && local_fp) {
Karl Wiberg918f50c2018-07-05 11:40:33 +0200531 remote_fingerprint = absl::make_unique<rtc::SSLFingerprint>(*remote_fp);
Zhi Huange818b6e2018-02-22 15:26:27 -0800532 webrtc::RTCError error =
533 NegotiateDtlsRole(local_description_type,
534 local_description_->transport_desc.connection_role,
535 remote_description_->transport_desc.connection_role,
536 &negotiated_dtls_role);
537 if (!error.ok()) {
538 return error;
539 }
540 } else if (local_fp && (local_description_type == SdpType::kAnswer)) {
541 return webrtc::RTCError(
542 webrtc::RTCErrorType::INVALID_PARAMETER,
543 "Local fingerprint supplied when caller didn't offer DTLS.");
544 } else {
545 // We are not doing DTLS
Steve Anton4905edb2018-10-15 19:27:44 -0700546 remote_fingerprint = absl::make_unique<rtc::SSLFingerprint>(
547 "", rtc::ArrayView<const uint8_t>());
Zhi Huange818b6e2018-02-22 15:26:27 -0800548 }
549 // Now that we have negotiated everything, push it downward.
550 // Note that we cache the result so that if we have race conditions
551 // between future SetRemote/SetLocal invocations and new transport
552 // creation, we have the negotiation state saved until a new
553 // negotiation happens.
Harald Alvestrand628f37a2018-12-06 10:55:20 +0100554 RTC_DCHECK(rtp_dtls_transport_->internal());
Zhi Huange818b6e2018-02-22 15:26:27 -0800555 webrtc::RTCError error = SetNegotiatedDtlsParameters(
Harald Alvestrandad88c882018-11-28 16:47:46 +0100556 rtp_dtls_transport_->internal(), negotiated_dtls_role,
Zhi Huange818b6e2018-02-22 15:26:27 -0800557 remote_fingerprint.get());
558 if (!error.ok()) {
559 return error;
560 }
561
562 if (rtcp_dtls_transport_) {
Harald Alvestrand628f37a2018-12-06 10:55:20 +0100563 RTC_DCHECK(rtcp_dtls_transport_->internal());
Harald Alvestrandad88c882018-11-28 16:47:46 +0100564 error = SetNegotiatedDtlsParameters(rtcp_dtls_transport_->internal(),
Zhi Huange818b6e2018-02-22 15:26:27 -0800565 negotiated_dtls_role,
566 remote_fingerprint.get());
567 }
568 return error;
569}
570
Zhi Huang365381f2018-04-13 16:44:34 -0700571webrtc::RTCError JsepTransport::NegotiateDtlsRole(
Zhi Huange818b6e2018-02-22 15:26:27 -0800572 SdpType local_description_type,
573 ConnectionRole local_connection_role,
574 ConnectionRole remote_connection_role,
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200575 absl::optional<rtc::SSLRole>* negotiated_dtls_role) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800576 // From RFC 4145, section-4.1, The following are the values that the
577 // 'setup' attribute can take in an offer/answer exchange:
578 // Offer Answer
579 // ________________
580 // active passive / holdconn
581 // passive active / holdconn
582 // actpass active / passive / holdconn
583 // holdconn holdconn
584 //
585 // Set the role that is most conformant with RFC 5763, Section 5, bullet 1
586 // The endpoint MUST use the setup attribute defined in [RFC4145].
587 // The endpoint that is the offerer MUST use the setup attribute
588 // value of setup:actpass and be prepared to receive a client_hello
589 // before it receives the answer. The answerer MUST use either a
590 // setup attribute value of setup:active or setup:passive. Note that
591 // if the answerer uses setup:passive, then the DTLS handshake will
592 // not begin until the answerer is received, which adds additional
593 // latency. setup:active allows the answer and the DTLS handshake to
594 // occur in parallel. Thus, setup:active is RECOMMENDED. Whichever
595 // party is active MUST initiate a DTLS handshake by sending a
596 // ClientHello over each flow (host/port quartet).
597 // IOW - actpass and passive modes should be treated as server and
598 // active as client.
599 bool is_remote_server = false;
600 if (local_description_type == SdpType::kOffer) {
601 if (local_connection_role != CONNECTIONROLE_ACTPASS) {
602 return webrtc::RTCError(
603 webrtc::RTCErrorType::INVALID_PARAMETER,
604 "Offerer must use actpass value for setup attribute.");
605 }
606
607 if (remote_connection_role == CONNECTIONROLE_ACTIVE ||
608 remote_connection_role == CONNECTIONROLE_PASSIVE ||
609 remote_connection_role == CONNECTIONROLE_NONE) {
610 is_remote_server = (remote_connection_role == CONNECTIONROLE_PASSIVE);
611 } else {
612 return webrtc::RTCError(
613 webrtc::RTCErrorType::INVALID_PARAMETER,
614 "Answerer must use either active or passive value "
615 "for setup attribute.");
616 }
617 // If remote is NONE or ACTIVE it will act as client.
618 } else {
619 if (remote_connection_role != CONNECTIONROLE_ACTPASS &&
620 remote_connection_role != CONNECTIONROLE_NONE) {
621 // Accept a remote role attribute that's not "actpass", but matches the
622 // current negotiated role. This is allowed by dtls-sdp, though our
623 // implementation will never generate such an offer as it's not
624 // recommended.
625 //
626 // See https://datatracker.ietf.org/doc/html/draft-ietf-mmusic-dtls-sdp,
627 // section 5.5.
628 auto current_dtls_role = GetDtlsRole();
629 if (!current_dtls_role ||
630 (*current_dtls_role == rtc::SSL_CLIENT &&
631 remote_connection_role == CONNECTIONROLE_ACTIVE) ||
632 (*current_dtls_role == rtc::SSL_SERVER &&
633 remote_connection_role == CONNECTIONROLE_PASSIVE)) {
634 return webrtc::RTCError(
635 webrtc::RTCErrorType::INVALID_PARAMETER,
636 "Offerer must use actpass value or current negotiated role for "
637 "setup attribute.");
638 }
639 }
640
641 if (local_connection_role == CONNECTIONROLE_ACTIVE ||
642 local_connection_role == CONNECTIONROLE_PASSIVE) {
643 is_remote_server = (local_connection_role == CONNECTIONROLE_ACTIVE);
644 } else {
645 return webrtc::RTCError(
646 webrtc::RTCErrorType::INVALID_PARAMETER,
647 "Answerer must use either active or passive value "
648 "for setup attribute.");
649 }
650
651 // If local is passive, local will act as server.
652 }
653
654 *negotiated_dtls_role = (is_remote_server ? std::move(rtc::SSL_CLIENT)
655 : std::move(rtc::SSL_SERVER));
656 return webrtc::RTCError::OK();
657}
658
Zhi Huang365381f2018-04-13 16:44:34 -0700659bool JsepTransport::GetTransportStats(DtlsTransportInternal* dtls_transport,
660 TransportStats* stats) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800661 RTC_DCHECK(dtls_transport);
662 TransportChannelStats substats;
Harald Alvestrandad88c882018-11-28 16:47:46 +0100663 if (rtcp_dtls_transport_) {
664 substats.component = dtls_transport == rtcp_dtls_transport_->internal()
665 ? ICE_CANDIDATE_COMPONENT_RTCP
666 : ICE_CANDIDATE_COMPONENT_RTP;
667 } else {
668 substats.component = ICE_CANDIDATE_COMPONENT_RTP;
669 }
Zhi Huange818b6e2018-02-22 15:26:27 -0800670 dtls_transport->GetSrtpCryptoSuite(&substats.srtp_crypto_suite);
671 dtls_transport->GetSslCipherSuite(&substats.ssl_cipher_suite);
672 substats.dtls_state = dtls_transport->dtls_state();
673 if (!dtls_transport->ice_transport()->GetStats(
674 &substats.connection_infos, &substats.candidate_stats_list)) {
675 return false;
676 }
677 stats->channel_stats.push_back(substats);
678 return true;
679}
680
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -0700681void JsepTransport::OnStateChanged(webrtc::MediaTransportState state) {
682 // TODO(bugs.webrtc.org/9719) This method currently fires on the network
683 // thread, but media transport does not make such guarantees. We need to make
684 // sure this callback is guaranteed to be executed on the network thread.
685 media_transport_state_ = state;
686 SignalMediaTransportStateChanged();
687}
688
Zhi Huange818b6e2018-02-22 15:26:27 -0800689} // namespace cricket