1/*
2 * Copyright (C) 2012 Google Inc. All rights reserved.
3 * Copyright (C) 2013 Nokia Corporation and/or its subsidiary(-ies).
4 * Copyright (C) 2015, 2016 Ericsson AB. All rights reserved.
5 * Copyright (C) 2017 Apple Inc. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer
15 * in the documentation and/or other materials provided with the
16 * distribution.
17 * 3. Neither the name of Google Inc. nor the names of its contributors
18 * may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#include "config.h"
35#include "RTCPeerConnection.h"
36
37#if ENABLE(WEB_RTC)
38
39#include "Document.h"
40#include "Event.h"
41#include "EventNames.h"
42#include "Frame.h"
43#include "JSRTCPeerConnection.h"
44#include "Logging.h"
45#include "MediaEndpointConfiguration.h"
46#include "MediaStream.h"
47#include "MediaStreamTrack.h"
48#include "Page.h"
49#include "RTCConfiguration.h"
50#include "RTCController.h"
51#include "RTCDataChannel.h"
52#include "RTCIceCandidate.h"
53#include "RTCPeerConnectionIceEvent.h"
54#include "RTCSessionDescription.h"
55#include <wtf/CryptographicallyRandomNumber.h>
56#include <wtf/IsoMallocInlines.h>
57#include <wtf/MainThread.h>
58#include <wtf/UUID.h>
59#include <wtf/text/Base64.h>
60
61namespace WebCore {
62
63using namespace PeerConnection;
64
65WTF_MAKE_ISO_ALLOCATED_IMPL(RTCPeerConnection);
66
67Ref<RTCPeerConnection> RTCPeerConnection::create(ScriptExecutionContext& context)
68{
69 auto peerConnection = adoptRef(*new RTCPeerConnection(context));
70 peerConnection->suspendIfNeeded();
71 // RTCPeerConnection may send events at about any time during its lifetime.
72 // Let's make it uncollectable until the pc is closed by JS or the page stops it.
73 if (!peerConnection->isClosed()) {
74 peerConnection->m_pendingActivity = peerConnection->makePendingActivity(peerConnection.get());
75 if (auto* page = downcast<Document>(context).page()) {
76 peerConnection->registerToController(page->rtcController());
77 page->libWebRTCProvider().setEnableLogging(!context.sessionID().isEphemeral());
78 }
79 }
80 return peerConnection;
81}
82
83RTCPeerConnection::RTCPeerConnection(ScriptExecutionContext& context)
84 : ActiveDOMObject(&context)
85#if !RELEASE_LOG_DISABLED
86 , m_logger(downcast<Document>(context).logger())
87 , m_logIdentifier(reinterpret_cast<const void*>(cryptographicallyRandomNumber()))
88#endif
89 , m_backend(PeerConnectionBackend::create(*this))
90{
91 ALWAYS_LOG(LOGIDENTIFIER);
92 if (!m_backend)
93 m_connectionState = RTCPeerConnectionState::Closed;
94}
95
96RTCPeerConnection::~RTCPeerConnection()
97{
98 ALWAYS_LOG(LOGIDENTIFIER);
99 unregisterFromController();
100 stop();
101}
102
103ExceptionOr<void> RTCPeerConnection::initializeWith(Document& document, RTCConfiguration&& configuration)
104{
105 if (!document.frame())
106 return Exception { NotSupportedError };
107
108 if (!m_backend)
109 return Exception { NotSupportedError };
110
111 return initializeConfiguration(WTFMove(configuration));
112}
113
114ExceptionOr<Ref<RTCRtpSender>> RTCPeerConnection::addTrack(Ref<MediaStreamTrack>&& track, const Vector<std::reference_wrapper<MediaStream>>& streams)
115{
116 INFO_LOG(LOGIDENTIFIER);
117
118 if (isClosed())
119 return Exception { InvalidStateError };
120
121 for (auto& transceiver : m_transceiverSet->list()) {
122 if (transceiver->sender().trackId() == track->id())
123 return Exception { InvalidAccessError };
124 }
125
126 Vector<String> mediaStreamIds;
127 for (auto stream : streams)
128 mediaStreamIds.append(stream.get().id());
129
130 return m_backend->addTrack(track.get(), WTFMove(mediaStreamIds));
131}
132
133ExceptionOr<void> RTCPeerConnection::removeTrack(RTCRtpSender& sender)
134{
135 INFO_LOG(LOGIDENTIFIER);
136
137 if (isClosed())
138 return Exception { InvalidStateError, "RTCPeerConnection is closed"_s };
139
140 if (!sender.isCreatedBy(*m_backend))
141 return Exception { InvalidAccessError, "RTCPeerConnection did not create the given sender"_s };
142
143 bool shouldAbort = true;
144 RTCRtpTransceiver* senderTransceiver = nullptr;
145 for (auto& transceiver : m_transceiverSet->list()) {
146 if (&sender == &transceiver->sender()) {
147 senderTransceiver = transceiver.get();
148 shouldAbort = sender.isStopped() || !sender.track();
149 break;
150 }
151 }
152 if (shouldAbort)
153 return { };
154
155 sender.setTrackToNull();
156 senderTransceiver->disableSendingDirection();
157 m_backend->removeTrack(sender);
158 return { };
159}
160
161ExceptionOr<Ref<RTCRtpTransceiver>> RTCPeerConnection::addTransceiver(AddTransceiverTrackOrKind&& withTrack, const RTCRtpTransceiverInit& init)
162{
163 INFO_LOG(LOGIDENTIFIER);
164
165 if (WTF::holds_alternative<String>(withTrack)) {
166 const String& kind = WTF::get<String>(withTrack);
167 if (kind != "audio"_s && kind != "video"_s)
168 return Exception { TypeError };
169
170 if (isClosed())
171 return Exception { InvalidStateError };
172
173 return m_backend->addTransceiver(kind, init);
174 }
175
176 if (isClosed())
177 return Exception { InvalidStateError };
178
179 auto track = WTF::get<RefPtr<MediaStreamTrack>>(withTrack).releaseNonNull();
180 return m_backend->addTransceiver(WTFMove(track), init);
181}
182
183void RTCPeerConnection::queuedCreateOffer(RTCOfferOptions&& options, SessionDescriptionPromise&& promise)
184{
185 ALWAYS_LOG(LOGIDENTIFIER);
186 if (isClosed()) {
187 promise.reject(InvalidStateError);
188 return;
189 }
190
191 m_backend->createOffer(WTFMove(options), WTFMove(promise));
192}
193
194void RTCPeerConnection::queuedCreateAnswer(RTCAnswerOptions&& options, SessionDescriptionPromise&& promise)
195{
196 ALWAYS_LOG(LOGIDENTIFIER);
197 if (isClosed()) {
198 promise.reject(InvalidStateError);
199 return;
200 }
201
202 m_backend->createAnswer(WTFMove(options), WTFMove(promise));
203}
204
205void RTCPeerConnection::queuedSetLocalDescription(RTCSessionDescription& description, DOMPromiseDeferred<void>&& promise)
206{
207 ALWAYS_LOG(LOGIDENTIFIER, "Setting local description to:\n", description.sdp());
208 if (isClosed()) {
209 promise.reject(InvalidStateError);
210 return;
211 }
212
213 m_backend->setLocalDescription(description, WTFMove(promise));
214}
215
216RefPtr<RTCSessionDescription> RTCPeerConnection::localDescription() const
217{
218 return m_backend->localDescription();
219}
220
221RefPtr<RTCSessionDescription> RTCPeerConnection::currentLocalDescription() const
222{
223 return m_backend->currentLocalDescription();
224}
225
226RefPtr<RTCSessionDescription> RTCPeerConnection::pendingLocalDescription() const
227{
228 return m_backend->pendingLocalDescription();
229}
230
231void RTCPeerConnection::queuedSetRemoteDescription(RTCSessionDescription& description, DOMPromiseDeferred<void>&& promise)
232{
233 ALWAYS_LOG(LOGIDENTIFIER, "Setting remote description to:\n", description.sdp());
234
235 if (isClosed()) {
236 promise.reject(InvalidStateError);
237 return;
238 }
239 m_backend->setRemoteDescription(description, WTFMove(promise));
240}
241
242RefPtr<RTCSessionDescription> RTCPeerConnection::remoteDescription() const
243{
244 return m_backend->remoteDescription();
245}
246
247RefPtr<RTCSessionDescription> RTCPeerConnection::currentRemoteDescription() const
248{
249 return m_backend->currentRemoteDescription();
250}
251
252RefPtr<RTCSessionDescription> RTCPeerConnection::pendingRemoteDescription() const
253{
254 return m_backend->pendingRemoteDescription();
255}
256
257void RTCPeerConnection::queuedAddIceCandidate(RTCIceCandidate* rtcCandidate, DOMPromiseDeferred<void>&& promise)
258{
259 ALWAYS_LOG(LOGIDENTIFIER, "Received ice candidate:\n", rtcCandidate ? rtcCandidate->candidate() : "null");
260
261 if (isClosed()) {
262 promise.reject(InvalidStateError);
263 return;
264 }
265
266 m_backend->addIceCandidate(rtcCandidate, WTFMove(promise));
267}
268
269// Implementation of https://w3c.github.io/webrtc-pc/#set-pc-configuration
270static inline ExceptionOr<Vector<MediaEndpointConfiguration::IceServerInfo>> iceServersFromConfiguration(RTCConfiguration& newConfiguration, const RTCConfiguration* existingConfiguration, bool isLocalDescriptionSet)
271{
272 if (existingConfiguration && newConfiguration.bundlePolicy != existingConfiguration->bundlePolicy)
273 return Exception { InvalidModificationError, "BundlePolicy does not match existing policy" };
274
275 if (existingConfiguration && newConfiguration.rtcpMuxPolicy != existingConfiguration->rtcpMuxPolicy)
276 return Exception { InvalidModificationError, "RTCPMuxPolicy does not match existing policy" };
277
278 if (existingConfiguration && newConfiguration.iceCandidatePoolSize != existingConfiguration->iceCandidatePoolSize && isLocalDescriptionSet)
279 return Exception { InvalidModificationError, "IceTransportPolicy pool size does not match existing pool size" };
280
281 Vector<MediaEndpointConfiguration::IceServerInfo> servers;
282 if (newConfiguration.iceServers) {
283 servers.reserveInitialCapacity(newConfiguration.iceServers->size());
284 for (auto& server : newConfiguration.iceServers.value()) {
285 Vector<URL> serverURLs;
286 WTF::switchOn(server.urls, [&serverURLs] (const String& string) {
287 serverURLs.reserveInitialCapacity(1);
288 serverURLs.uncheckedAppend(URL { URL { }, string });
289 }, [&serverURLs] (const Vector<String>& vector) {
290 serverURLs.reserveInitialCapacity(vector.size());
291 for (auto& string : vector)
292 serverURLs.uncheckedAppend(URL { URL { }, string });
293 });
294 for (auto& serverURL : serverURLs) {
295 if (serverURL.isNull())
296 return Exception { TypeError, "Bad ICE server URL" };
297 if (serverURL.protocolIs("turn") || serverURL.protocolIs("turns")) {
298 if (server.credential.isNull() || server.username.isNull())
299 return Exception { InvalidAccessError, "TURN/TURNS server requires both username and credential" };
300 } else if (!serverURL.protocolIs("stun"))
301 return Exception { NotSupportedError, "ICE server protocol not supported" };
302 }
303 if (serverURLs.size())
304 servers.uncheckedAppend({ WTFMove(serverURLs), server.credential, server.username });
305 }
306 }
307 return servers;
308}
309
310ExceptionOr<Vector<MediaEndpointConfiguration::CertificatePEM>> RTCPeerConnection::certificatesFromConfiguration(const RTCConfiguration& configuration)
311{
312 auto currentMilliSeconds = WallTime::now().secondsSinceEpoch().milliseconds();
313 auto& origin = downcast<Document>(*scriptExecutionContext()).securityOrigin();
314
315 Vector<MediaEndpointConfiguration::CertificatePEM> certificates;
316 certificates.reserveInitialCapacity(configuration.certificates.size());
317 for (auto& certificate : configuration.certificates) {
318 if (!origin.isSameOriginAs(certificate->origin()))
319 return Exception { InvalidAccessError, "Certificate does not have a valid origin" };
320
321 if (currentMilliSeconds > certificate->expires())
322 return Exception { InvalidAccessError, "Certificate has expired"_s };
323
324 certificates.uncheckedAppend(MediaEndpointConfiguration::CertificatePEM { certificate->pemCertificate(), certificate->pemPrivateKey(), });
325 }
326 return certificates;
327}
328
329ExceptionOr<void> RTCPeerConnection::initializeConfiguration(RTCConfiguration&& configuration)
330{
331 INFO_LOG(LOGIDENTIFIER);
332
333 auto servers = iceServersFromConfiguration(configuration, nullptr, false);
334 if (servers.hasException())
335 return servers.releaseException();
336
337 auto certificates = certificatesFromConfiguration(configuration);
338 if (certificates.hasException())
339 return certificates.releaseException();
340
341 if (!m_backend->setConfiguration({ servers.releaseReturnValue(), configuration.iceTransportPolicy, configuration.bundlePolicy, configuration.rtcpMuxPolicy, configuration.iceCandidatePoolSize, certificates.releaseReturnValue() }))
342 return Exception { InvalidAccessError, "Bad Configuration Parameters" };
343
344 m_configuration = WTFMove(configuration);
345 return { };
346}
347
348ExceptionOr<void> RTCPeerConnection::setConfiguration(RTCConfiguration&& configuration)
349{
350 if (isClosed())
351 return Exception { InvalidStateError };
352
353 INFO_LOG(LOGIDENTIFIER);
354
355 auto servers = iceServersFromConfiguration(configuration, &m_configuration, m_backend->isLocalDescriptionSet());
356 if (servers.hasException())
357 return servers.releaseException();
358
359 if (configuration.certificates.size()) {
360 if (configuration.certificates.size() != m_configuration.certificates.size())
361 return Exception { InvalidModificationError, "Certificates parameters are different" };
362
363 for (auto& certificate : configuration.certificates) {
364 bool isThere = m_configuration.certificates.findMatching([&certificate](const auto& item) {
365 return item.get() == certificate.get();
366 }) != notFound;
367 if (!isThere)
368 return Exception { InvalidModificationError, "A certificate given in constructor is not present" };
369 }
370 }
371
372 if (!m_backend->setConfiguration({ servers.releaseReturnValue(), configuration.iceTransportPolicy, configuration.bundlePolicy, configuration.rtcpMuxPolicy, configuration.iceCandidatePoolSize, { } }))
373 return Exception { InvalidAccessError, "Bad Configuration Parameters" };
374
375 m_configuration = WTFMove(configuration);
376 return { };
377}
378
379void RTCPeerConnection::getStats(MediaStreamTrack* selector, Ref<DeferredPromise>&& promise)
380{
381 if (selector) {
382 for (auto& transceiver : m_transceiverSet->list()) {
383 if (transceiver->sender().track() == selector) {
384 m_backend->getStats(transceiver->sender(), WTFMove(promise));
385 return;
386 }
387 if (&transceiver->receiver().track() == selector) {
388 m_backend->getStats(transceiver->receiver(), WTFMove(promise));
389 return;
390 }
391 }
392 }
393 m_backend->getStats(WTFMove(promise));
394}
395
396ExceptionOr<Ref<RTCDataChannel>> RTCPeerConnection::createDataChannel(ScriptExecutionContext& context, String&& label, RTCDataChannelInit&& options)
397{
398 ALWAYS_LOG(LOGIDENTIFIER);
399
400 if (isClosed())
401 return Exception { InvalidStateError };
402
403 if (options.negotiated && !options.negotiated.value() && (label.length() > 65535 || options.protocol.length() > 65535))
404 return Exception { TypeError };
405
406 if (options.maxPacketLifeTime && options.maxRetransmits)
407 return Exception { TypeError };
408
409 if (options.id && options.id.value() > 65534)
410 return Exception { TypeError };
411
412 auto channelHandler = m_backend->createDataChannelHandler(label, options);
413 if (!channelHandler)
414 return Exception { NotSupportedError };
415
416 return RTCDataChannel::create(context, WTFMove(channelHandler), WTFMove(label), WTFMove(options));
417}
418
419bool RTCPeerConnection::doClose()
420{
421 if (isClosed())
422 return false;
423
424 m_connectionState = RTCPeerConnectionState::Closed;
425 m_iceConnectionState = RTCIceConnectionState::Closed;
426 m_signalingState = RTCSignalingState::Closed;
427
428 for (auto& transceiver : m_transceiverSet->list()) {
429 transceiver->stop();
430 transceiver->sender().stop();
431 transceiver->receiver().stop();
432 }
433
434 return true;
435}
436
437void RTCPeerConnection::close()
438{
439 if (!doClose())
440 return;
441
442 updateConnectionState();
443 ASSERT(isClosed());
444 doStop();
445}
446
447void RTCPeerConnection::emulatePlatformEvent(const String& action)
448{
449 m_backend->emulatePlatformEvent(action);
450}
451
452void RTCPeerConnection::stop()
453{
454 if (!doClose())
455 return;
456
457 doStop();
458}
459
460void RTCPeerConnection::doStop()
461{
462 if (m_isStopped)
463 return;
464
465 m_isStopped = true;
466
467 m_backend->stop();
468 m_pendingActivity = nullptr;
469}
470
471void RTCPeerConnection::registerToController(RTCController& controller)
472{
473 m_controller = &controller;
474 m_controller->add(*this);
475}
476
477void RTCPeerConnection::unregisterFromController()
478{
479 if (m_controller)
480 m_controller->remove(*this);
481}
482
483const char* RTCPeerConnection::activeDOMObjectName() const
484{
485 return "RTCPeerConnection";
486}
487
488bool RTCPeerConnection::canSuspendForDocumentSuspension() const
489{
490 return !hasPendingActivity();
491}
492
493bool RTCPeerConnection::hasPendingActivity() const
494{
495 return !m_isStopped;
496}
497
498void RTCPeerConnection::addTransceiver(Ref<RTCRtpTransceiver>&& transceiver)
499{
500 INFO_LOG(LOGIDENTIFIER);
501 m_transceiverSet->append(WTFMove(transceiver));
502}
503
504void RTCPeerConnection::setSignalingState(RTCSignalingState newState)
505{
506 ALWAYS_LOG(LOGIDENTIFIER, newState);
507 m_signalingState = newState;
508}
509
510void RTCPeerConnection::updateIceGatheringState(RTCIceGatheringState newState)
511{
512 ALWAYS_LOG(LOGIDENTIFIER, newState);
513
514 scriptExecutionContext()->postTask([protectedThis = makeRef(*this), newState](ScriptExecutionContext&) {
515 if (protectedThis->isClosed() || protectedThis->m_iceGatheringState == newState)
516 return;
517
518 protectedThis->m_iceGatheringState = newState;
519 protectedThis->dispatchEvent(Event::create(eventNames().icegatheringstatechangeEvent, Event::CanBubble::No, Event::IsCancelable::No));
520 protectedThis->updateConnectionState();
521 });
522}
523
524void RTCPeerConnection::updateIceConnectionState(RTCIceConnectionState newState)
525{
526 ALWAYS_LOG(LOGIDENTIFIER, newState);
527
528 scriptExecutionContext()->postTask([protectedThis = makeRef(*this), newState](ScriptExecutionContext&) {
529 if (protectedThis->isClosed() || protectedThis->m_iceConnectionState == newState)
530 return;
531
532 protectedThis->m_iceConnectionState = newState;
533 protectedThis->dispatchEvent(Event::create(eventNames().iceconnectionstatechangeEvent, Event::CanBubble::No, Event::IsCancelable::No));
534 protectedThis->updateConnectionState();
535 });
536}
537
538void RTCPeerConnection::updateConnectionState()
539{
540 RTCPeerConnectionState state;
541
542 if (m_iceConnectionState == RTCIceConnectionState::Closed)
543 state = RTCPeerConnectionState::Closed;
544 else if (m_iceConnectionState == RTCIceConnectionState::Disconnected)
545 state = RTCPeerConnectionState::Disconnected;
546 else if (m_iceConnectionState == RTCIceConnectionState::Failed)
547 state = RTCPeerConnectionState::Failed;
548 else if (m_iceConnectionState == RTCIceConnectionState::New && m_iceGatheringState == RTCIceGatheringState::New)
549 state = RTCPeerConnectionState::New;
550 else if (m_iceConnectionState == RTCIceConnectionState::Checking || m_iceGatheringState == RTCIceGatheringState::Gathering)
551 state = RTCPeerConnectionState::Connecting;
552 else if ((m_iceConnectionState == RTCIceConnectionState::Completed || m_iceConnectionState == RTCIceConnectionState::Connected) && m_iceGatheringState == RTCIceGatheringState::Complete)
553 state = RTCPeerConnectionState::Connected;
554 else
555 return;
556
557 if (state == m_connectionState)
558 return;
559
560 INFO_LOG(LOGIDENTIFIER, "state changed from: " , m_connectionState, " to ", state);
561
562 m_connectionState = state;
563 dispatchEvent(Event::create(eventNames().connectionstatechangeEvent, Event::CanBubble::No, Event::IsCancelable::No));
564}
565
566void RTCPeerConnection::scheduleNegotiationNeededEvent()
567{
568 scriptExecutionContext()->postTask([protectedThis = makeRef(*this)](ScriptExecutionContext&) {
569 if (protectedThis->isClosed())
570 return;
571 if (!protectedThis->m_backend->isNegotiationNeeded())
572 return;
573 protectedThis->m_backend->clearNegotiationNeededState();
574 protectedThis->dispatchEvent(Event::create(eventNames().negotiationneededEvent, Event::CanBubble::No, Event::IsCancelable::No));
575 });
576}
577
578void RTCPeerConnection::fireEvent(Event& event)
579{
580 dispatchEvent(event);
581}
582
583void RTCPeerConnection::dispatchEvent(Event& event)
584{
585 INFO_LOG(LOGIDENTIFIER, "dispatching '", event.type(), "'");
586 EventTarget::dispatchEvent(event);
587}
588
589static inline ExceptionOr<PeerConnectionBackend::CertificateInformation> certificateTypeFromAlgorithmIdentifier(JSC::ExecState& state, RTCPeerConnection::AlgorithmIdentifier&& algorithmIdentifier)
590{
591 if (WTF::holds_alternative<String>(algorithmIdentifier))
592 return Exception { NotSupportedError, "Algorithm is not supported"_s };
593
594 auto& value = WTF::get<JSC::Strong<JSC::JSObject>>(algorithmIdentifier);
595
596 JSC::VM& vm = state.vm();
597 auto scope = DECLARE_CATCH_SCOPE(vm);
598
599 auto parameters = convertDictionary<RTCPeerConnection::CertificateParameters>(state, value.get());
600 if (UNLIKELY(scope.exception())) {
601 scope.clearException();
602 return Exception { TypeError, "Unable to read certificate parameters"_s };
603 }
604
605 if (parameters.expires && *parameters.expires < 0)
606 return Exception { TypeError, "Expire value is invalid"_s };
607
608 if (parameters.name == "RSASSA-PKCS1-v1_5"_s) {
609 if (!parameters.hash.isNull() && parameters.hash != "SHA-256"_s)
610 return Exception { NotSupportedError, "Only SHA-256 is supported for RSASSA-PKCS1-v1_5"_s };
611
612 auto result = PeerConnectionBackend::CertificateInformation::RSASSA_PKCS1_v1_5();
613 if (parameters.modulusLength && parameters.publicExponent) {
614 int publicExponent = 0;
615 int value = 1;
616 for (unsigned counter = 0; counter < parameters.publicExponent->byteLength(); ++counter) {
617 publicExponent += parameters.publicExponent->data()[counter] * value;
618 value <<= 8;
619 }
620
621 result.rsaParameters = PeerConnectionBackend::CertificateInformation::RSA { *parameters.modulusLength, publicExponent };
622 }
623 result.expires = parameters.expires;
624 return result;
625 }
626 if (parameters.name == "ECDSA"_s && parameters.namedCurve == "P-256"_s) {
627 auto result = PeerConnectionBackend::CertificateInformation::ECDSA_P256();
628 result.expires = parameters.expires;
629 return result;
630 }
631
632 return Exception { NotSupportedError, "Algorithm is not supported"_s };
633}
634
635void RTCPeerConnection::generateCertificate(JSC::ExecState& state, AlgorithmIdentifier&& algorithmIdentifier, DOMPromiseDeferred<IDLInterface<RTCCertificate>>&& promise)
636{
637 auto parameters = certificateTypeFromAlgorithmIdentifier(state, WTFMove(algorithmIdentifier));
638 if (parameters.hasException()) {
639 promise.reject(parameters.releaseException());
640 return;
641 }
642 auto& document = downcast<Document>(*JSC::jsCast<JSDOMGlobalObject*>(state.lexicalGlobalObject())->scriptExecutionContext());
643 PeerConnectionBackend::generateCertificate(document, parameters.returnValue(), WTFMove(promise));
644}
645
646Vector<std::reference_wrapper<RTCRtpSender>> RTCPeerConnection::getSenders() const
647{
648 m_backend->collectTransceivers();
649 return m_transceiverSet->senders();
650}
651
652Vector<std::reference_wrapper<RTCRtpReceiver>> RTCPeerConnection::getReceivers() const
653{
654 m_backend->collectTransceivers();
655 return m_transceiverSet->receivers();
656}
657
658const Vector<RefPtr<RTCRtpTransceiver>>& RTCPeerConnection::getTransceivers() const
659{
660 m_backend->collectTransceivers();
661 return m_transceiverSet->list();
662}
663
664#if !RELEASE_LOG_DISABLED
665WTFLogChannel& RTCPeerConnection::logChannel() const
666{
667 return LogWebRTC;
668}
669#endif
670
671} // namespace WebCore
672
673#endif // ENABLE(WEB_RTC)
674