blob: 894dce122d131ebe8773c0210a0ae1428a31dba9 [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
Zhi Huang365381f2018-04-13 16:44:34 -070011#include "pc/jseptransport.h"
Zhi Huange818b6e2018-02-22 15:26:27 -080012
13#include <memory>
14#include <utility> // for std::pair
15
16#include "api/candidate.h"
17#include "p2p/base/p2pconstants.h"
18#include "p2p/base/p2ptransportchannel.h"
19#include "p2p/base/port.h"
20#include "rtc_base/bind.h"
21#include "rtc_base/checks.h"
22#include "rtc_base/logging.h"
Zhi Huang365381f2018-04-13 16:44:34 -070023#include "rtc_base/strings/string_builder.h"
Zhi Huange818b6e2018-02-22 15:26:27 -080024
25using webrtc::SdpType;
26
27namespace cricket {
28
29static bool VerifyIceParams(const JsepTransportDescription& jsep_description) {
30 // For legacy protocols.
31 // TODO(zhihuang): Remove this once the legacy protocol is no longer
32 // supported.
33 if (jsep_description.transport_desc.ice_ufrag.empty() &&
34 jsep_description.transport_desc.ice_pwd.empty()) {
35 return true;
36 }
37
38 if (jsep_description.transport_desc.ice_ufrag.length() <
39 ICE_UFRAG_MIN_LENGTH ||
40 jsep_description.transport_desc.ice_ufrag.length() >
41 ICE_UFRAG_MAX_LENGTH) {
42 return false;
43 }
44 if (jsep_description.transport_desc.ice_pwd.length() < ICE_PWD_MIN_LENGTH ||
45 jsep_description.transport_desc.ice_pwd.length() > ICE_PWD_MAX_LENGTH) {
46 return false;
47 }
48 return true;
49}
50
51JsepTransportDescription::JsepTransportDescription() {}
52
53JsepTransportDescription::JsepTransportDescription(
54 bool rtcp_mux_enabled,
55 const std::vector<CryptoParams>& cryptos,
56 const std::vector<int>& encrypted_header_extension_ids,
Zhi Huange830e682018-03-30 10:48:35 -070057 int rtp_abs_sendtime_extn_id,
Zhi Huange818b6e2018-02-22 15:26:27 -080058 const TransportDescription& transport_desc)
59 : rtcp_mux_enabled(rtcp_mux_enabled),
60 cryptos(cryptos),
61 encrypted_header_extension_ids(encrypted_header_extension_ids),
Zhi Huange830e682018-03-30 10:48:35 -070062 rtp_abs_sendtime_extn_id(rtp_abs_sendtime_extn_id),
Zhi Huange818b6e2018-02-22 15:26:27 -080063 transport_desc(transport_desc) {}
64
65JsepTransportDescription::JsepTransportDescription(
66 const JsepTransportDescription& from)
67 : rtcp_mux_enabled(from.rtcp_mux_enabled),
68 cryptos(from.cryptos),
69 encrypted_header_extension_ids(from.encrypted_header_extension_ids),
Zhi Huange830e682018-03-30 10:48:35 -070070 rtp_abs_sendtime_extn_id(from.rtp_abs_sendtime_extn_id),
Zhi Huange818b6e2018-02-22 15:26:27 -080071 transport_desc(from.transport_desc) {}
72
73JsepTransportDescription::~JsepTransportDescription() = default;
74
75JsepTransportDescription& JsepTransportDescription::operator=(
76 const JsepTransportDescription& from) {
77 if (this == &from) {
78 return *this;
79 }
80 rtcp_mux_enabled = from.rtcp_mux_enabled;
81 cryptos = from.cryptos;
82 encrypted_header_extension_ids = from.encrypted_header_extension_ids;
Zhi Huange830e682018-03-30 10:48:35 -070083 rtp_abs_sendtime_extn_id = from.rtp_abs_sendtime_extn_id;
Zhi Huange818b6e2018-02-22 15:26:27 -080084 transport_desc = from.transport_desc;
85
86 return *this;
87}
88
Zhi Huang365381f2018-04-13 16:44:34 -070089JsepTransport::JsepTransport(
Zhi Huange818b6e2018-02-22 15:26:27 -080090 const std::string& mid,
91 const rtc::scoped_refptr<rtc::RTCCertificate>& local_certificate,
92 std::unique_ptr<webrtc::RtpTransport> unencrypted_rtp_transport,
93 std::unique_ptr<webrtc::SrtpTransport> sdes_transport,
94 std::unique_ptr<webrtc::DtlsSrtpTransport> dtls_srtp_transport,
95 std::unique_ptr<DtlsTransportInternal> rtp_dtls_transport,
Anton Sukhanov7940da02018-10-10 10:34:49 -070096 std::unique_ptr<DtlsTransportInternal> rtcp_dtls_transport,
97 std::unique_ptr<webrtc::MediaTransportInterface> media_transport)
Zhi Huange818b6e2018-02-22 15:26:27 -080098 : mid_(mid),
99 local_certificate_(local_certificate),
100 rtp_dtls_transport_(std::move(rtp_dtls_transport)),
Anton Sukhanov7940da02018-10-10 10:34:49 -0700101 rtcp_dtls_transport_(std::move(rtcp_dtls_transport)),
102 media_transport_(std::move(media_transport)) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800103 RTC_DCHECK(rtp_dtls_transport_);
104 if (unencrypted_rtp_transport) {
105 RTC_DCHECK(!sdes_transport);
106 RTC_DCHECK(!dtls_srtp_transport);
107 unencrypted_rtp_transport_ = std::move(unencrypted_rtp_transport);
108 } else if (sdes_transport) {
109 RTC_DCHECK(!unencrypted_rtp_transport);
110 RTC_DCHECK(!dtls_srtp_transport);
111 sdes_transport_ = std::move(sdes_transport);
112 } else {
113 RTC_DCHECK(dtls_srtp_transport);
114 RTC_DCHECK(!unencrypted_rtp_transport);
115 RTC_DCHECK(!sdes_transport);
116 dtls_srtp_transport_ = std::move(dtls_srtp_transport);
117 }
118}
119
Zhi Huang365381f2018-04-13 16:44:34 -0700120JsepTransport::~JsepTransport() {}
Zhi Huange818b6e2018-02-22 15:26:27 -0800121
Zhi Huang365381f2018-04-13 16:44:34 -0700122webrtc::RTCError JsepTransport::SetLocalJsepTransportDescription(
Zhi Huange818b6e2018-02-22 15:26:27 -0800123 const JsepTransportDescription& jsep_description,
124 SdpType type) {
125 webrtc::RTCError error;
126
127 if (!VerifyIceParams(jsep_description)) {
128 return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
129 "Invalid ice-ufrag or ice-pwd length.");
130 }
131
132 if (!SetRtcpMux(jsep_description.rtcp_mux_enabled, type,
133 ContentSource::CS_LOCAL)) {
134 return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
135 "Failed to setup RTCP mux.");
136 }
137
138 // If doing SDES, setup the SDES crypto parameters.
139 if (sdes_transport_) {
140 RTC_DCHECK(!unencrypted_rtp_transport_);
141 RTC_DCHECK(!dtls_srtp_transport_);
142 if (!SetSdes(jsep_description.cryptos,
143 jsep_description.encrypted_header_extension_ids, type,
144 ContentSource::CS_LOCAL)) {
145 return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
146 "Failed to setup SDES crypto parameters.");
147 }
148 } else if (dtls_srtp_transport_) {
149 RTC_DCHECK(!unencrypted_rtp_transport_);
150 RTC_DCHECK(!sdes_transport_);
151 dtls_srtp_transport_->UpdateRecvEncryptedHeaderExtensionIds(
152 jsep_description.encrypted_header_extension_ids);
153 }
154
155 bool ice_restarting =
156 local_description_ != nullptr &&
157 IceCredentialsChanged(local_description_->transport_desc.ice_ufrag,
158 local_description_->transport_desc.ice_pwd,
159 jsep_description.transport_desc.ice_ufrag,
160 jsep_description.transport_desc.ice_pwd);
161 local_description_.reset(new JsepTransportDescription(jsep_description));
162
163 rtc::SSLFingerprint* local_fp =
164 local_description_->transport_desc.identity_fingerprint.get();
165
166 if (!local_fp) {
167 local_certificate_ = nullptr;
168 } else {
169 error = VerifyCertificateFingerprint(local_certificate_.get(), local_fp);
170 if (!error.ok()) {
171 local_description_.reset();
172 return error;
173 }
174 }
175
176 SetLocalIceParameters(rtp_dtls_transport_->ice_transport());
177
178 if (rtcp_dtls_transport_) {
179 SetLocalIceParameters(rtcp_dtls_transport_->ice_transport());
180 }
181
182 // If PRANSWER/ANSWER is set, we should decide transport protocol type.
183 if (type == SdpType::kPrAnswer || type == SdpType::kAnswer) {
184 error = NegotiateAndSetDtlsParameters(type);
185 }
186 if (!error.ok()) {
187 local_description_.reset();
188 return error;
189 }
190
191 if (needs_ice_restart_ && ice_restarting) {
192 needs_ice_restart_ = false;
193 RTC_LOG(LS_VERBOSE) << "needs-ice-restart flag cleared for transport "
194 << mid();
195 }
196
197 return webrtc::RTCError::OK();
198}
199
Zhi Huang365381f2018-04-13 16:44:34 -0700200webrtc::RTCError JsepTransport::SetRemoteJsepTransportDescription(
Zhi Huange818b6e2018-02-22 15:26:27 -0800201 const JsepTransportDescription& jsep_description,
202 webrtc::SdpType type) {
203 webrtc::RTCError error;
204
205 if (!VerifyIceParams(jsep_description)) {
206 remote_description_.reset();
207 return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
208 "Invalid ice-ufrag or ice-pwd length.");
209 }
210
211 if (!SetRtcpMux(jsep_description.rtcp_mux_enabled, type,
212 ContentSource::CS_REMOTE)) {
213 return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
214 "Failed to setup RTCP mux.");
215 }
216
217 // If doing SDES, setup the SDES crypto parameters.
218 if (sdes_transport_) {
219 RTC_DCHECK(!unencrypted_rtp_transport_);
220 RTC_DCHECK(!dtls_srtp_transport_);
221 if (!SetSdes(jsep_description.cryptos,
222 jsep_description.encrypted_header_extension_ids, type,
223 ContentSource::CS_REMOTE)) {
224 return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
225 "Failed to setup SDES crypto parameters.");
226 }
Zhi Huange830e682018-03-30 10:48:35 -0700227 sdes_transport_->CacheRtpAbsSendTimeHeaderExtension(
228 jsep_description.rtp_abs_sendtime_extn_id);
Zhi Huange818b6e2018-02-22 15:26:27 -0800229 } else if (dtls_srtp_transport_) {
230 RTC_DCHECK(!unencrypted_rtp_transport_);
231 RTC_DCHECK(!sdes_transport_);
232 dtls_srtp_transport_->UpdateSendEncryptedHeaderExtensionIds(
233 jsep_description.encrypted_header_extension_ids);
Zhi Huange830e682018-03-30 10:48:35 -0700234 dtls_srtp_transport_->CacheRtpAbsSendTimeHeaderExtension(
235 jsep_description.rtp_abs_sendtime_extn_id);
Zhi Huange818b6e2018-02-22 15:26:27 -0800236 }
237
238 remote_description_.reset(new JsepTransportDescription(jsep_description));
239 SetRemoteIceParameters(rtp_dtls_transport_->ice_transport());
240
241 if (rtcp_dtls_transport_) {
242 SetRemoteIceParameters(rtcp_dtls_transport_->ice_transport());
243 }
244
245 // If PRANSWER/ANSWER is set, we should decide transport protocol type.
246 if (type == SdpType::kPrAnswer || type == SdpType::kAnswer) {
247 error = NegotiateAndSetDtlsParameters(SdpType::kOffer);
248 }
249 if (!error.ok()) {
250 remote_description_.reset();
251 return error;
252 }
253 return webrtc::RTCError::OK();
254}
255
Zhi Huang365381f2018-04-13 16:44:34 -0700256webrtc::RTCError JsepTransport::AddRemoteCandidates(
Zhi Huange818b6e2018-02-22 15:26:27 -0800257 const Candidates& candidates) {
Henrik Boström5d8f8fa2018-04-13 15:22:50 +0000258 if (!local_description_ || !remote_description_) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800259 return webrtc::RTCError(webrtc::RTCErrorType::INVALID_STATE,
260 mid() +
261 " is not ready to use the remote candidate "
Henrik Boström5d8f8fa2018-04-13 15:22:50 +0000262 "because the local or remote description is "
263 "not set.");
Zhi Huange818b6e2018-02-22 15:26:27 -0800264 }
265
266 for (const cricket::Candidate& candidate : candidates) {
267 auto transport =
268 candidate.component() == cricket::ICE_CANDIDATE_COMPONENT_RTP
269 ? rtp_dtls_transport_.get()
270 : rtcp_dtls_transport_.get();
271 if (!transport) {
272 return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
273 "Candidate has an unknown component: " +
274 candidate.ToString() + " for mid " + mid());
275 }
276 transport->ice_transport()->AddRemoteCandidate(candidate);
277 }
278 return webrtc::RTCError::OK();
279}
280
Zhi Huang365381f2018-04-13 16:44:34 -0700281void JsepTransport::SetNeedsIceRestartFlag() {
Zhi Huange818b6e2018-02-22 15:26:27 -0800282 if (!needs_ice_restart_) {
283 needs_ice_restart_ = true;
284 RTC_LOG(LS_VERBOSE) << "needs-ice-restart flag set for transport " << mid();
285 }
286}
287
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200288absl::optional<rtc::SSLRole> JsepTransport::GetDtlsRole() const {
Zhi Huange818b6e2018-02-22 15:26:27 -0800289 RTC_DCHECK(rtp_dtls_transport_);
290 rtc::SSLRole dtls_role;
291 if (!rtp_dtls_transport_->GetDtlsRole(&dtls_role)) {
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200292 return absl::optional<rtc::SSLRole>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800293 }
294
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200295 return absl::optional<rtc::SSLRole>(dtls_role);
Zhi Huange818b6e2018-02-22 15:26:27 -0800296}
297
Zhi Huang365381f2018-04-13 16:44:34 -0700298bool JsepTransport::GetStats(TransportStats* stats) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800299 stats->transport_name = mid();
300 stats->channel_stats.clear();
301 bool ret = GetTransportStats(rtp_dtls_transport_.get(), stats);
302 if (rtcp_dtls_transport_) {
303 ret &= GetTransportStats(rtcp_dtls_transport_.get(), stats);
304 }
305 return ret;
306}
307
Zhi Huang365381f2018-04-13 16:44:34 -0700308webrtc::RTCError JsepTransport::VerifyCertificateFingerprint(
Zhi Huange818b6e2018-02-22 15:26:27 -0800309 const rtc::RTCCertificate* certificate,
310 const rtc::SSLFingerprint* fingerprint) const {
311 if (!fingerprint) {
312 return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
313 "No fingerprint");
314 }
315 if (!certificate) {
316 return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
317 "Fingerprint provided but no identity available.");
318 }
Mirko Bonadei6932fb22018-10-15 14:18:03 +0000319 std::unique_ptr<rtc::SSLFingerprint> fp_tmp(rtc::SSLFingerprint::Create(
320 fingerprint->algorithm, certificate->identity()));
Zhi Huange818b6e2018-02-22 15:26:27 -0800321 RTC_DCHECK(fp_tmp.get() != NULL);
322 if (*fp_tmp == *fingerprint) {
323 return webrtc::RTCError::OK();
324 }
Zhi Huang365381f2018-04-13 16:44:34 -0700325 char ss_buf[1024];
326 rtc::SimpleStringBuilder desc(ss_buf);
Zhi Huange818b6e2018-02-22 15:26:27 -0800327 desc << "Local fingerprint does not match identity. Expected: ";
328 desc << fp_tmp->ToString();
329 desc << " Got: " << fingerprint->ToString();
Zhi Huang365381f2018-04-13 16:44:34 -0700330 return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
331 std::string(desc.str()));
Zhi Huange818b6e2018-02-22 15:26:27 -0800332}
333
Zhi Huangb57e1692018-06-12 11:41:11 -0700334void JsepTransport::SetActiveResetSrtpParams(bool active_reset_srtp_params) {
335 if (dtls_srtp_transport_) {
336 RTC_LOG(INFO)
337 << "Setting active_reset_srtp_params of DtlsSrtpTransport to: "
338 << active_reset_srtp_params;
339 dtls_srtp_transport_->SetActiveResetSrtpParams(active_reset_srtp_params);
340 }
341}
342
Zhi Huang365381f2018-04-13 16:44:34 -0700343void JsepTransport::SetLocalIceParameters(IceTransportInternal* ice_transport) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800344 RTC_DCHECK(ice_transport);
345 RTC_DCHECK(local_description_);
346 ice_transport->SetIceParameters(
347 local_description_->transport_desc.GetIceParameters());
348}
349
Zhi Huang365381f2018-04-13 16:44:34 -0700350void JsepTransport::SetRemoteIceParameters(
Zhi Huange818b6e2018-02-22 15:26:27 -0800351 IceTransportInternal* ice_transport) {
352 RTC_DCHECK(ice_transport);
353 RTC_DCHECK(remote_description_);
354 ice_transport->SetRemoteIceParameters(
355 remote_description_->transport_desc.GetIceParameters());
356 ice_transport->SetRemoteIceMode(remote_description_->transport_desc.ice_mode);
357}
358
Zhi Huang365381f2018-04-13 16:44:34 -0700359webrtc::RTCError JsepTransport::SetNegotiatedDtlsParameters(
Zhi Huange818b6e2018-02-22 15:26:27 -0800360 DtlsTransportInternal* dtls_transport,
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200361 absl::optional<rtc::SSLRole> dtls_role,
Zhi Huange818b6e2018-02-22 15:26:27 -0800362 rtc::SSLFingerprint* remote_fingerprint) {
363 RTC_DCHECK(dtls_transport);
364 // Set SSL role. Role must be set before fingerprint is applied, which
365 // initiates DTLS setup.
366 if (dtls_role && !dtls_transport->SetDtlsRole(*dtls_role)) {
367 return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
368 "Failed to set SSL role for the transport.");
369 }
370 // Apply remote fingerprint.
371 if (!remote_fingerprint ||
372 !dtls_transport->SetRemoteFingerprint(
373 remote_fingerprint->algorithm,
374 reinterpret_cast<const uint8_t*>(remote_fingerprint->digest.data()),
375 remote_fingerprint->digest.size())) {
376 return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
377 "Failed to apply remote fingerprint.");
378 }
379 return webrtc::RTCError::OK();
380}
381
Zhi Huang365381f2018-04-13 16:44:34 -0700382bool JsepTransport::SetRtcpMux(bool enable,
383 webrtc::SdpType type,
384 ContentSource source) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800385 bool ret = false;
386 switch (type) {
387 case SdpType::kOffer:
388 ret = rtcp_mux_negotiator_.SetOffer(enable, source);
389 break;
390 case SdpType::kPrAnswer:
391 // This may activate RTCP muxing, but we don't yet destroy the transport
392 // because the final answer may deactivate it.
393 ret = rtcp_mux_negotiator_.SetProvisionalAnswer(enable, source);
394 break;
395 case SdpType::kAnswer:
396 ret = rtcp_mux_negotiator_.SetAnswer(enable, source);
397 if (ret && rtcp_mux_negotiator_.IsActive()) {
398 ActivateRtcpMux();
399 }
400 break;
401 default:
402 RTC_NOTREACHED();
403 }
404
405 if (!ret) {
406 return false;
407 }
408
409 auto transport = rtp_transport();
410 transport->SetRtcpMuxEnabled(rtcp_mux_negotiator_.IsActive());
411 return ret;
412}
413
Zhi Huang365381f2018-04-13 16:44:34 -0700414void JsepTransport::ActivateRtcpMux() {
Zhi Huange818b6e2018-02-22 15:26:27 -0800415 if (unencrypted_rtp_transport_) {
416 RTC_DCHECK(!sdes_transport_);
417 RTC_DCHECK(!dtls_srtp_transport_);
418 unencrypted_rtp_transport_->SetRtcpPacketTransport(nullptr);
419 } else if (sdes_transport_) {
420 RTC_DCHECK(!unencrypted_rtp_transport_);
421 RTC_DCHECK(!dtls_srtp_transport_);
422 sdes_transport_->SetRtcpPacketTransport(nullptr);
423 } else {
424 RTC_DCHECK(dtls_srtp_transport_);
425 RTC_DCHECK(!unencrypted_rtp_transport_);
426 RTC_DCHECK(!sdes_transport_);
427 dtls_srtp_transport_->SetDtlsTransports(rtp_dtls_transport(),
428 /*rtcp_dtls_transport=*/nullptr);
429 }
430 rtcp_dtls_transport_.reset();
431 // Notify the JsepTransportController to update the aggregate states.
432 SignalRtcpMuxActive();
433}
434
Zhi Huang365381f2018-04-13 16:44:34 -0700435bool JsepTransport::SetSdes(const std::vector<CryptoParams>& cryptos,
436 const std::vector<int>& encrypted_extension_ids,
437 webrtc::SdpType type,
438 ContentSource source) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800439 bool ret = false;
440 ret = sdes_negotiator_.Process(cryptos, type, source);
441 if (!ret) {
442 return ret;
443 }
444
445 if (source == ContentSource::CS_LOCAL) {
446 recv_extension_ids_ = std::move(encrypted_extension_ids);
447 } else {
448 send_extension_ids_ = std::move(encrypted_extension_ids);
449 }
450
451 // If setting an SDES answer succeeded, apply the negotiated parameters
452 // to the SRTP transport.
453 if ((type == SdpType::kPrAnswer || type == SdpType::kAnswer) && ret) {
454 if (sdes_negotiator_.send_cipher_suite() &&
455 sdes_negotiator_.recv_cipher_suite()) {
456 RTC_DCHECK(send_extension_ids_);
457 RTC_DCHECK(recv_extension_ids_);
458 ret = sdes_transport_->SetRtpParams(
459 *(sdes_negotiator_.send_cipher_suite()),
460 sdes_negotiator_.send_key().data(),
461 static_cast<int>(sdes_negotiator_.send_key().size()),
462 *(send_extension_ids_), *(sdes_negotiator_.recv_cipher_suite()),
463 sdes_negotiator_.recv_key().data(),
464 static_cast<int>(sdes_negotiator_.recv_key().size()),
465 *(recv_extension_ids_));
466 } else {
467 RTC_LOG(LS_INFO) << "No crypto keys are provided for SDES.";
468 if (type == SdpType::kAnswer) {
469 // Explicitly reset the |sdes_transport_| if no crypto param is
470 // provided in the answer. No need to call |ResetParams()| for
471 // |sdes_negotiator_| because it resets the params inside |SetAnswer|.
472 sdes_transport_->ResetParams();
473 }
474 }
475 }
476 return ret;
477}
478
Zhi Huang365381f2018-04-13 16:44:34 -0700479webrtc::RTCError JsepTransport::NegotiateAndSetDtlsParameters(
Zhi Huange818b6e2018-02-22 15:26:27 -0800480 SdpType local_description_type) {
481 if (!local_description_ || !remote_description_) {
482 return webrtc::RTCError(webrtc::RTCErrorType::INVALID_STATE,
483 "Applying an answer transport description "
484 "without applying any offer.");
485 }
486 std::unique_ptr<rtc::SSLFingerprint> remote_fingerprint;
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200487 absl::optional<rtc::SSLRole> negotiated_dtls_role;
Zhi Huange818b6e2018-02-22 15:26:27 -0800488
489 rtc::SSLFingerprint* local_fp =
490 local_description_->transport_desc.identity_fingerprint.get();
491 rtc::SSLFingerprint* remote_fp =
492 remote_description_->transport_desc.identity_fingerprint.get();
493 if (remote_fp && local_fp) {
Karl Wiberg918f50c2018-07-05 11:40:33 +0200494 remote_fingerprint = absl::make_unique<rtc::SSLFingerprint>(*remote_fp);
Zhi Huange818b6e2018-02-22 15:26:27 -0800495 webrtc::RTCError error =
496 NegotiateDtlsRole(local_description_type,
497 local_description_->transport_desc.connection_role,
498 remote_description_->transport_desc.connection_role,
499 &negotiated_dtls_role);
500 if (!error.ok()) {
501 return error;
502 }
503 } else if (local_fp && (local_description_type == SdpType::kAnswer)) {
504 return webrtc::RTCError(
505 webrtc::RTCErrorType::INVALID_PARAMETER,
506 "Local fingerprint supplied when caller didn't offer DTLS.");
507 } else {
508 // We are not doing DTLS
Mirko Bonadei6932fb22018-10-15 14:18:03 +0000509 remote_fingerprint = absl::make_unique<rtc::SSLFingerprint>("", nullptr, 0);
Zhi Huange818b6e2018-02-22 15:26:27 -0800510 }
511 // Now that we have negotiated everything, push it downward.
512 // Note that we cache the result so that if we have race conditions
513 // between future SetRemote/SetLocal invocations and new transport
514 // creation, we have the negotiation state saved until a new
515 // negotiation happens.
516 webrtc::RTCError error = SetNegotiatedDtlsParameters(
517 rtp_dtls_transport_.get(), negotiated_dtls_role,
518 remote_fingerprint.get());
519 if (!error.ok()) {
520 return error;
521 }
522
523 if (rtcp_dtls_transport_) {
524 error = SetNegotiatedDtlsParameters(rtcp_dtls_transport_.get(),
525 negotiated_dtls_role,
526 remote_fingerprint.get());
527 }
528 return error;
529}
530
Zhi Huang365381f2018-04-13 16:44:34 -0700531webrtc::RTCError JsepTransport::NegotiateDtlsRole(
Zhi Huange818b6e2018-02-22 15:26:27 -0800532 SdpType local_description_type,
533 ConnectionRole local_connection_role,
534 ConnectionRole remote_connection_role,
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200535 absl::optional<rtc::SSLRole>* negotiated_dtls_role) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800536 // From RFC 4145, section-4.1, The following are the values that the
537 // 'setup' attribute can take in an offer/answer exchange:
538 // Offer Answer
539 // ________________
540 // active passive / holdconn
541 // passive active / holdconn
542 // actpass active / passive / holdconn
543 // holdconn holdconn
544 //
545 // Set the role that is most conformant with RFC 5763, Section 5, bullet 1
546 // The endpoint MUST use the setup attribute defined in [RFC4145].
547 // The endpoint that is the offerer MUST use the setup attribute
548 // value of setup:actpass and be prepared to receive a client_hello
549 // before it receives the answer. The answerer MUST use either a
550 // setup attribute value of setup:active or setup:passive. Note that
551 // if the answerer uses setup:passive, then the DTLS handshake will
552 // not begin until the answerer is received, which adds additional
553 // latency. setup:active allows the answer and the DTLS handshake to
554 // occur in parallel. Thus, setup:active is RECOMMENDED. Whichever
555 // party is active MUST initiate a DTLS handshake by sending a
556 // ClientHello over each flow (host/port quartet).
557 // IOW - actpass and passive modes should be treated as server and
558 // active as client.
559 bool is_remote_server = false;
560 if (local_description_type == SdpType::kOffer) {
561 if (local_connection_role != CONNECTIONROLE_ACTPASS) {
562 return webrtc::RTCError(
563 webrtc::RTCErrorType::INVALID_PARAMETER,
564 "Offerer must use actpass value for setup attribute.");
565 }
566
567 if (remote_connection_role == CONNECTIONROLE_ACTIVE ||
568 remote_connection_role == CONNECTIONROLE_PASSIVE ||
569 remote_connection_role == CONNECTIONROLE_NONE) {
570 is_remote_server = (remote_connection_role == CONNECTIONROLE_PASSIVE);
571 } else {
572 return webrtc::RTCError(
573 webrtc::RTCErrorType::INVALID_PARAMETER,
574 "Answerer must use either active or passive value "
575 "for setup attribute.");
576 }
577 // If remote is NONE or ACTIVE it will act as client.
578 } else {
579 if (remote_connection_role != CONNECTIONROLE_ACTPASS &&
580 remote_connection_role != CONNECTIONROLE_NONE) {
581 // Accept a remote role attribute that's not "actpass", but matches the
582 // current negotiated role. This is allowed by dtls-sdp, though our
583 // implementation will never generate such an offer as it's not
584 // recommended.
585 //
586 // See https://datatracker.ietf.org/doc/html/draft-ietf-mmusic-dtls-sdp,
587 // section 5.5.
588 auto current_dtls_role = GetDtlsRole();
589 if (!current_dtls_role ||
590 (*current_dtls_role == rtc::SSL_CLIENT &&
591 remote_connection_role == CONNECTIONROLE_ACTIVE) ||
592 (*current_dtls_role == rtc::SSL_SERVER &&
593 remote_connection_role == CONNECTIONROLE_PASSIVE)) {
594 return webrtc::RTCError(
595 webrtc::RTCErrorType::INVALID_PARAMETER,
596 "Offerer must use actpass value or current negotiated role for "
597 "setup attribute.");
598 }
599 }
600
601 if (local_connection_role == CONNECTIONROLE_ACTIVE ||
602 local_connection_role == CONNECTIONROLE_PASSIVE) {
603 is_remote_server = (local_connection_role == CONNECTIONROLE_ACTIVE);
604 } else {
605 return webrtc::RTCError(
606 webrtc::RTCErrorType::INVALID_PARAMETER,
607 "Answerer must use either active or passive value "
608 "for setup attribute.");
609 }
610
611 // If local is passive, local will act as server.
612 }
613
614 *negotiated_dtls_role = (is_remote_server ? std::move(rtc::SSL_CLIENT)
615 : std::move(rtc::SSL_SERVER));
616 return webrtc::RTCError::OK();
617}
618
Zhi Huang365381f2018-04-13 16:44:34 -0700619bool JsepTransport::GetTransportStats(DtlsTransportInternal* dtls_transport,
620 TransportStats* stats) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800621 RTC_DCHECK(dtls_transport);
622 TransportChannelStats substats;
623 substats.component = dtls_transport == rtcp_dtls_transport_.get()
624 ? ICE_CANDIDATE_COMPONENT_RTCP
625 : ICE_CANDIDATE_COMPONENT_RTP;
626 dtls_transport->GetSrtpCryptoSuite(&substats.srtp_crypto_suite);
627 dtls_transport->GetSslCipherSuite(&substats.ssl_cipher_suite);
628 substats.dtls_state = dtls_transport->dtls_state();
629 if (!dtls_transport->ice_transport()->GetStats(
630 &substats.connection_infos, &substats.candidate_stats_list)) {
631 return false;
632 }
633 stats->channel_stats.push_back(substats);
634 return true;
635}
636
637} // namespace cricket