1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.h"
6
7 #include "media/media_buildflags.h"
8 #include "third_party/blink/public/platform/platform.h"
9 #include "third_party/blink/public/web/web_local_frame.h"
10 #include "third_party/blink/renderer/bindings/modules/v8/v8_rtc_ice_gather_options.h"
11 #include "third_party/blink/renderer/bindings/modules/v8/v8_rtc_ice_parameters.h"
12 #include "third_party/blink/renderer/bindings/modules/v8/v8_rtc_ice_server.h"
13 #include "third_party/blink/renderer/bindings/modules/v8/v8_rtc_peer_connection_ice_event_init.h"
14 #include "third_party/blink/renderer/core/dom/document.h"
15 #include "third_party/blink/renderer/core/dom/events/event.h"
16 #include "third_party/blink/renderer/core/frame/local_frame.h"
17 #include "third_party/blink/renderer/core/frame/local_frame_client.h"
18 #include "third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter_cross_thread_factory.h"
19 #include "third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter_impl.h"
20 #include "third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_proxy.h"
21 #include "third_party/blink/renderer/modules/peerconnection/peer_connection_dependency_factory.h"
22 #include "third_party/blink/renderer/modules/peerconnection/rtc_error_util.h"
23 #include "third_party/blink/renderer/modules/peerconnection/rtc_ice_candidate.h"
24 #include "third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.h"
25 #include "third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_ice_event.h"
26 #include "third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.h"
27 #include "third_party/blink/renderer/platform/heap/heap.h"
28 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
29 #include "third_party/blink/renderer/platform/scheduler/public/thread.h"
30 #include "third_party/webrtc/api/ice_transport_factory.h"
31 #include "third_party/webrtc/api/ice_transport_interface.h"
32 #include "third_party/webrtc/api/jsep_ice_candidate.h"
33 #include "third_party/webrtc/api/peer_connection_interface.h"
34 #include "third_party/webrtc/p2p/base/port_allocator.h"
35 #include "third_party/webrtc/p2p/base/transport_description.h"
36 #include "third_party/webrtc/pc/ice_server_parsing.h"
37 #include "third_party/webrtc/pc/webrtc_sdp.h"
38
39 namespace blink {
40 namespace {
41
42 const char* kIceRoleControllingStr = "controlling";
43 const char* kIceRoleControlledStr = "controlled";
44
ConvertToCricketIceCandidate(const RTCIceCandidate & candidate)45 base::Optional<cricket::Candidate> ConvertToCricketIceCandidate(
46 const RTCIceCandidate& candidate) {
47 webrtc::JsepIceCandidate jsep_candidate("", 0);
48 webrtc::SdpParseError error;
49 if (!webrtc::SdpDeserializeCandidate(candidate.candidate().Utf8(),
50 &jsep_candidate, &error)) {
51 LOG(WARNING) << "Failed to deserialize candidate: " << error.description;
52 return base::nullopt;
53 }
54 return jsep_candidate.candidate();
55 }
56
ConvertToRtcIceCandidate(const cricket::Candidate & candidate)57 RTCIceCandidate* ConvertToRtcIceCandidate(const cricket::Candidate& candidate) {
58 return RTCIceCandidate::Create(MakeGarbageCollected<RTCIceCandidatePlatform>(
59 String::FromUTF8(webrtc::SdpSerializeCandidate(candidate)), "", 0));
60 }
61
62 class DtlsIceTransportAdapterCrossThreadFactory
63 : public IceTransportAdapterCrossThreadFactory {
64 public:
DtlsIceTransportAdapterCrossThreadFactory(rtc::scoped_refptr<webrtc::IceTransportInterface> ice_transport)65 explicit DtlsIceTransportAdapterCrossThreadFactory(
66 rtc::scoped_refptr<webrtc::IceTransportInterface> ice_transport)
67 : ice_transport_(ice_transport) {}
InitializeOnMainThread(LocalFrame & frame)68 void InitializeOnMainThread(LocalFrame& frame) override {
69 }
70
ConstructOnWorkerThread(IceTransportAdapter::Delegate * delegate)71 std::unique_ptr<IceTransportAdapter> ConstructOnWorkerThread(
72 IceTransportAdapter::Delegate* delegate) override {
73 #if BUILDFLAG(ENABLE_WEBRTC)
74 DCHECK(ice_transport_);
75 return std::make_unique<IceTransportAdapterImpl>(delegate,
76 std::move(ice_transport_));
77 #else
78 return nullptr;
79 #endif
80 }
81
82 private:
83 rtc::scoped_refptr<webrtc::IceTransportInterface> ice_transport_;
84 };
85
86 class DefaultIceTransportAdapterCrossThreadFactory
87 : public IceTransportAdapterCrossThreadFactory {
88 public:
InitializeOnMainThread(LocalFrame & frame)89 void InitializeOnMainThread(LocalFrame& frame) override {
90 #if BUILDFLAG(ENABLE_WEBRTC)
91 DCHECK(!port_allocator_);
92 DCHECK(!async_resolver_factory_);
93
94 auto* rtc_dependency_factory =
95 blink::PeerConnectionDependencyFactory::GetInstance();
96 port_allocator_ = rtc_dependency_factory->CreatePortAllocator(
97 frame.Client()->GetWebFrame());
98 async_resolver_factory_ =
99 rtc_dependency_factory->CreateAsyncResolverFactory();
100 #endif
101 }
102
ConstructOnWorkerThread(IceTransportAdapter::Delegate * delegate)103 std::unique_ptr<IceTransportAdapter> ConstructOnWorkerThread(
104 IceTransportAdapter::Delegate* delegate) override {
105 #if BUILDFLAG(ENABLE_WEBRTC)
106 DCHECK(port_allocator_);
107 DCHECK(async_resolver_factory_);
108 return std::make_unique<IceTransportAdapterImpl>(
109 delegate, std::move(port_allocator_),
110 std::move(async_resolver_factory_));
111 #else
112 return nullptr;
113 #endif
114 }
115
116 private:
117 std::unique_ptr<cricket::PortAllocator> port_allocator_;
118 std::unique_ptr<webrtc::AsyncResolverFactory> async_resolver_factory_;
119 };
120
121 } // namespace
122
Create(ExecutionContext * context)123 RTCIceTransport* RTCIceTransport::Create(ExecutionContext* context) {
124 #if BUILDFLAG(ENABLE_WEBRTC)
125 LocalFrame* frame = Document::From(context)->GetFrame();
126 scoped_refptr<base::SingleThreadTaskRunner> proxy_thread =
127 frame->GetTaskRunner(TaskType::kNetworking);
128
129 PeerConnectionDependencyFactory::GetInstance()->EnsureInitialized();
130 scoped_refptr<base::SingleThreadTaskRunner> host_thread =
131 PeerConnectionDependencyFactory::GetInstance()
132 ->GetWebRtcWorkerTaskRunner();
133 return MakeGarbageCollected<RTCIceTransport>(
134 context, std::move(proxy_thread), std::move(host_thread),
135 std::make_unique<DefaultIceTransportAdapterCrossThreadFactory>());
136 #else
137 return nullptr;
138 #endif
139 }
140
Create(ExecutionContext * context,rtc::scoped_refptr<webrtc::IceTransportInterface> ice_transport,RTCPeerConnection * peer_connection)141 RTCIceTransport* RTCIceTransport::Create(
142 ExecutionContext* context,
143 rtc::scoped_refptr<webrtc::IceTransportInterface> ice_transport,
144 RTCPeerConnection* peer_connection) {
145 #if BUILDFLAG(ENABLE_WEBRTC)
146 LocalFrame* frame = Document::From(context)->GetFrame();
147 scoped_refptr<base::SingleThreadTaskRunner> proxy_thread =
148 frame->GetTaskRunner(TaskType::kNetworking);
149
150 PeerConnectionDependencyFactory::GetInstance()->EnsureInitialized();
151 scoped_refptr<base::SingleThreadTaskRunner> host_thread =
152 PeerConnectionDependencyFactory::GetInstance()
153 ->GetWebRtcWorkerTaskRunner();
154 return MakeGarbageCollected<RTCIceTransport>(
155 context, std::move(proxy_thread), std::move(host_thread),
156 std::make_unique<DtlsIceTransportAdapterCrossThreadFactory>(
157 std::move(ice_transport)),
158 peer_connection);
159 #else
160 return nullptr;
161 #endif
162 }
163
Create(ExecutionContext * context,scoped_refptr<base::SingleThreadTaskRunner> proxy_thread,scoped_refptr<base::SingleThreadTaskRunner> host_thread,std::unique_ptr<IceTransportAdapterCrossThreadFactory> adapter_factory)164 RTCIceTransport* RTCIceTransport::Create(
165 ExecutionContext* context,
166 scoped_refptr<base::SingleThreadTaskRunner> proxy_thread,
167 scoped_refptr<base::SingleThreadTaskRunner> host_thread,
168 std::unique_ptr<IceTransportAdapterCrossThreadFactory> adapter_factory) {
169 return MakeGarbageCollected<RTCIceTransport>(context, std::move(proxy_thread),
170 std::move(host_thread),
171 std::move(adapter_factory));
172 }
173
RTCIceTransport(ExecutionContext * context,scoped_refptr<base::SingleThreadTaskRunner> proxy_thread,scoped_refptr<base::SingleThreadTaskRunner> host_thread,std::unique_ptr<IceTransportAdapterCrossThreadFactory> adapter_factory,RTCPeerConnection * peer_connection)174 RTCIceTransport::RTCIceTransport(
175 ExecutionContext* context,
176 scoped_refptr<base::SingleThreadTaskRunner> proxy_thread,
177 scoped_refptr<base::SingleThreadTaskRunner> host_thread,
178 std::unique_ptr<IceTransportAdapterCrossThreadFactory> adapter_factory,
179 RTCPeerConnection* peer_connection)
180 : ExecutionContextLifecycleObserver(context),
181 peer_connection_(peer_connection) {
182 DCHECK(context);
183 DCHECK(proxy_thread);
184 DCHECK(host_thread);
185 DCHECK(adapter_factory);
186 DCHECK(proxy_thread->BelongsToCurrentThread());
187
188 LocalFrame* frame = Document::From(context)->GetFrame();
189 DCHECK(frame);
190 proxy_ = std::make_unique<IceTransportProxy>(*frame, std::move(proxy_thread),
191 std::move(host_thread), this,
192 std::move(adapter_factory));
193
194 GenerateLocalParameters();
195 }
196
RTCIceTransport(ExecutionContext * context,scoped_refptr<base::SingleThreadTaskRunner> proxy_thread,scoped_refptr<base::SingleThreadTaskRunner> host_thread,std::unique_ptr<IceTransportAdapterCrossThreadFactory> adapter_factory)197 RTCIceTransport::RTCIceTransport(
198 ExecutionContext* context,
199 scoped_refptr<base::SingleThreadTaskRunner> proxy_thread,
200 scoped_refptr<base::SingleThreadTaskRunner> host_thread,
201 std::unique_ptr<IceTransportAdapterCrossThreadFactory> adapter_factory)
202 : RTCIceTransport(context,
203 std::move(proxy_thread),
204 std::move(host_thread),
205 std::move(adapter_factory),
206 nullptr) {}
207
~RTCIceTransport()208 RTCIceTransport::~RTCIceTransport() {
209 DCHECK(!proxy_);
210 }
211
HasConsumer() const212 bool RTCIceTransport::HasConsumer() const {
213 return consumer_;
214 }
215
IsFromPeerConnection() const216 bool RTCIceTransport::IsFromPeerConnection() const {
217 return peer_connection_;
218 }
219
ConnectConsumer(RTCQuicTransport * consumer)220 IceTransportProxy* RTCIceTransport::ConnectConsumer(
221 RTCQuicTransport* consumer) {
222 DCHECK(consumer);
223 DCHECK(proxy_);
224 DCHECK(!peer_connection_);
225 if (!consumer_) {
226 consumer_ = consumer;
227 } else {
228 DCHECK_EQ(consumer_, consumer);
229 }
230 return proxy_.get();
231 }
232
DisconnectConsumer(RTCQuicTransport * consumer)233 void RTCIceTransport::DisconnectConsumer(RTCQuicTransport* consumer) {
234 DCHECK(consumer);
235 DCHECK(proxy_);
236 DCHECK_EQ(consumer, consumer_);
237 consumer_ = nullptr;
238 }
239
role() const240 String RTCIceTransport::role() const {
241 switch (role_) {
242 case cricket::ICEROLE_CONTROLLING:
243 return kIceRoleControllingStr;
244 case cricket::ICEROLE_CONTROLLED:
245 return kIceRoleControlledStr;
246 case cricket::ICEROLE_UNKNOWN:
247 return String();
248 }
249 NOTREACHED();
250 return String();
251 }
252
state() const253 String RTCIceTransport::state() const {
254 switch (state_) {
255 case webrtc::IceTransportState::kNew:
256 return "new";
257 case webrtc::IceTransportState::kChecking:
258 return "checking";
259 case webrtc::IceTransportState::kConnected:
260 return "connected";
261 case webrtc::IceTransportState::kCompleted:
262 return "completed";
263 case webrtc::IceTransportState::kDisconnected:
264 return "disconnected";
265 case webrtc::IceTransportState::kFailed:
266 return "failed";
267 case webrtc::IceTransportState::kClosed:
268 return "closed";
269 }
270 NOTREACHED();
271 return g_empty_string;
272 }
273
gatheringState() const274 String RTCIceTransport::gatheringState() const {
275 switch (gathering_state_) {
276 case cricket::kIceGatheringNew:
277 return "new";
278 case cricket::kIceGatheringGathering:
279 return "gathering";
280 case cricket::kIceGatheringComplete:
281 return "complete";
282 default:
283 NOTREACHED();
284 return g_empty_string;
285 }
286 }
287
getLocalCandidates() const288 const HeapVector<Member<RTCIceCandidate>>& RTCIceTransport::getLocalCandidates()
289 const {
290 return local_candidates_;
291 }
292
293 const HeapVector<Member<RTCIceCandidate>>&
getRemoteCandidates() const294 RTCIceTransport::getRemoteCandidates() const {
295 return remote_candidates_;
296 }
297
getSelectedCandidatePair() const298 RTCIceCandidatePair* RTCIceTransport::getSelectedCandidatePair() const {
299 return selected_candidate_pair_;
300 }
301
getLocalParameters() const302 RTCIceParameters* RTCIceTransport::getLocalParameters() const {
303 return local_parameters_;
304 }
305
getRemoteParameters() const306 RTCIceParameters* RTCIceTransport::getRemoteParameters() const {
307 return remote_parameters_;
308 }
309
ConvertIceServer(const RTCIceServer * ice_server)310 static webrtc::PeerConnectionInterface::IceServer ConvertIceServer(
311 const RTCIceServer* ice_server) {
312 webrtc::PeerConnectionInterface::IceServer converted_ice_server;
313 // Prefer standardized 'urls' field over deprecated 'url' field.
314 Vector<String> url_strings;
315 if (ice_server->hasUrls()) {
316 if (ice_server->urls().IsString()) {
317 url_strings.push_back(ice_server->urls().GetAsString());
318 } else if (ice_server->urls().IsStringSequence()) {
319 url_strings = ice_server->urls().GetAsStringSequence();
320 }
321 } else if (ice_server->hasUrl()) {
322 url_strings.push_back(ice_server->url());
323 }
324 for (const String& url_string : url_strings) {
325 converted_ice_server.urls.push_back(url_string.Utf8());
326 }
327 converted_ice_server.username = ice_server->username().Utf8();
328 converted_ice_server.password = ice_server->credential().Utf8();
329 return converted_ice_server;
330 }
331
ConvertIceParameters(const RTCIceParameters * raw_ice_parameters)332 static webrtc::RTCErrorOr<cricket::IceParameters> ConvertIceParameters(
333 const RTCIceParameters* raw_ice_parameters) {
334 std::string raw_ufrag = raw_ice_parameters->usernameFragment().Utf8();
335 std::string raw_pwd = raw_ice_parameters->password().Utf8();
336 return cricket::IceParameters::Parse(raw_ufrag, raw_pwd);
337 }
338
ConvertIceServers(const HeapVector<Member<RTCIceServer>> & ice_servers)339 static WebVector<webrtc::PeerConnectionInterface::IceServer> ConvertIceServers(
340 const HeapVector<Member<RTCIceServer>>& ice_servers) {
341 WebVector<webrtc::PeerConnectionInterface::IceServer> converted_ice_servers;
342 for (const RTCIceServer* ice_server : ice_servers) {
343 converted_ice_servers.emplace_back(ConvertIceServer(ice_server));
344 }
345 return converted_ice_servers;
346 }
347
IceTransportPolicyFromString(const String & str)348 static IceTransportPolicy IceTransportPolicyFromString(const String& str) {
349 if (str == "relay") {
350 return IceTransportPolicy::kRelay;
351 }
352 if (str == "all") {
353 return IceTransportPolicy::kAll;
354 }
355 NOTREACHED();
356 return IceTransportPolicy::kAll;
357 }
358
gather(RTCIceGatherOptions * options,ExceptionState & exception_state)359 void RTCIceTransport::gather(RTCIceGatherOptions* options,
360 ExceptionState& exception_state) {
361 if (RaiseExceptionIfClosed(exception_state)) {
362 return;
363 }
364 // TODO(github.com/w3c/webrtc-ice/issues/7): Possibly support calling gather()
365 // more than once.
366 if (gathering_state_ != cricket::kIceGatheringNew) {
367 exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
368 "Can only call gather() once.");
369 return;
370 }
371 WebVector<webrtc::PeerConnectionInterface::IceServer> ice_servers;
372 if (options->hasIceServers()) {
373 ice_servers = ConvertIceServers(options->iceServers());
374 }
375 cricket::ServerAddresses stun_servers;
376 std::vector<cricket::RelayServerConfig> turn_servers;
377 webrtc::RTCErrorType error_type = webrtc::ParseIceServers(
378 ice_servers.ReleaseVector(), &stun_servers, &turn_servers);
379 if (error_type != webrtc::RTCErrorType::NONE) {
380 ThrowExceptionFromRTCError(
381 webrtc::RTCError(error_type, "Invalid ICE server URL(s)."),
382 exception_state);
383 return;
384 }
385 gathering_state_ = cricket::kIceGatheringGathering;
386 proxy_->StartGathering(ConvertIceParameters(local_parameters_).value(),
387 stun_servers, turn_servers,
388 IceTransportPolicyFromString(options->gatherPolicy()));
389 }
390
IceRoleFromString(const String & role_string)391 static cricket::IceRole IceRoleFromString(const String& role_string) {
392 if (role_string == kIceRoleControllingStr) {
393 return cricket::ICEROLE_CONTROLLING;
394 }
395 if (role_string == kIceRoleControlledStr) {
396 return cricket::ICEROLE_CONTROLLED;
397 }
398 NOTREACHED();
399 return cricket::ICEROLE_UNKNOWN;
400 }
401
RTCIceParametersAreEqual(const RTCIceParameters * a,const RTCIceParameters * b)402 static bool RTCIceParametersAreEqual(const RTCIceParameters* a,
403 const RTCIceParameters* b) {
404 return a->usernameFragment() == b->usernameFragment() &&
405 a->password() == b->password();
406 }
407
start(RTCIceParameters * raw_remote_parameters,const String & role_string,ExceptionState & exception_state)408 void RTCIceTransport::start(RTCIceParameters* raw_remote_parameters,
409 const String& role_string,
410 ExceptionState& exception_state) {
411 if (RaiseExceptionIfClosed(exception_state)) {
412 return;
413 }
414 if (!raw_remote_parameters->hasUsernameFragment() ||
415 !raw_remote_parameters->hasPassword()) {
416 exception_state.ThrowTypeError(
417 "remoteParameters must have usernameFragment and password fields set.");
418 return;
419 }
420 webrtc::RTCErrorOr<cricket::IceParameters> maybe_remote_parameters =
421 ConvertIceParameters(raw_remote_parameters);
422 if (!maybe_remote_parameters.ok()) {
423 ThrowExceptionFromRTCError(maybe_remote_parameters.error(),
424 exception_state);
425 return;
426 }
427 cricket::IceParameters remote_parameters =
428 maybe_remote_parameters.MoveValue();
429 cricket::IceRole role = IceRoleFromString(role_string);
430 if (role_ != cricket::ICEROLE_UNKNOWN && role != role_) {
431 exception_state.ThrowDOMException(
432 DOMExceptionCode::kInvalidStateError,
433 "Cannot change role once start() has been called.");
434 return;
435 }
436 if (remote_parameters_ &&
437 RTCIceParametersAreEqual(remote_parameters_, raw_remote_parameters)) {
438 // No change to remote parameters: do nothing.
439 return;
440 }
441 if (!remote_parameters_) {
442 // Calling start() for the first time.
443 role_ = role;
444 if (remote_candidates_.size() > 0) {
445 state_ = webrtc::IceTransportState::kChecking;
446 }
447 Vector<cricket::Candidate> initial_remote_candidates;
448 for (RTCIceCandidate* remote_candidate : remote_candidates_) {
449 // This conversion is safe since we throw an exception in
450 // addRemoteCandidate on malformed ICE candidates.
451 initial_remote_candidates.push_back(
452 *ConvertToCricketIceCandidate(*remote_candidate));
453 }
454 proxy_->Start(remote_parameters, role, initial_remote_candidates);
455 if (consumer_) {
456 consumer_->OnIceTransportStarted();
457 }
458 } else {
459 remote_candidates_.clear();
460 state_ = webrtc::IceTransportState::kNew;
461 proxy_->HandleRemoteRestart(remote_parameters);
462 }
463
464 remote_parameters_ = raw_remote_parameters;
465 }
466
stop()467 void RTCIceTransport::stop() {
468 Close(CloseReason::kStopped);
469 }
470
addRemoteCandidate(RTCIceCandidate * remote_candidate,ExceptionState & exception_state)471 void RTCIceTransport::addRemoteCandidate(RTCIceCandidate* remote_candidate,
472 ExceptionState& exception_state) {
473 if (RaiseExceptionIfClosed(exception_state)) {
474 return;
475 }
476 base::Optional<cricket::Candidate> converted_remote_candidate =
477 ConvertToCricketIceCandidate(*remote_candidate);
478 if (!converted_remote_candidate) {
479 exception_state.ThrowDOMException(DOMExceptionCode::kOperationError,
480 "Invalid ICE candidate.");
481 return;
482 }
483 remote_candidates_.push_back(remote_candidate);
484 if (remote_parameters_) {
485 proxy_->AddRemoteCandidate(*converted_remote_candidate);
486 state_ = webrtc::IceTransportState::kChecking;
487 }
488 }
489
GenerateLocalParameters()490 void RTCIceTransport::GenerateLocalParameters() {
491 local_parameters_ = RTCIceParameters::Create();
492 local_parameters_->setUsernameFragment(
493 String::FromUTF8(rtc::CreateRandomString(cricket::ICE_UFRAG_LENGTH)));
494 local_parameters_->setPassword(
495 String::FromUTF8(rtc::CreateRandomString(cricket::ICE_PWD_LENGTH)));
496 }
497
OnGatheringStateChanged(cricket::IceGatheringState new_state)498 void RTCIceTransport::OnGatheringStateChanged(
499 cricket::IceGatheringState new_state) {
500 if (new_state == gathering_state_) {
501 return;
502 }
503 if (new_state == cricket::kIceGatheringComplete) {
504 // Generate a null ICE candidate to signal the end of candidates.
505 DispatchEvent(*RTCPeerConnectionIceEvent::Create(nullptr));
506 }
507 gathering_state_ = new_state;
508 DispatchEvent(*Event::Create(event_type_names::kGatheringstatechange));
509 }
510
OnCandidateGathered(const cricket::Candidate & parsed_candidate)511 void RTCIceTransport::OnCandidateGathered(
512 const cricket::Candidate& parsed_candidate) {
513 RTCIceCandidate* candidate = ConvertToRtcIceCandidate(parsed_candidate);
514 local_candidates_.push_back(candidate);
515 RTCPeerConnectionIceEventInit* event_init =
516 RTCPeerConnectionIceEventInit::Create();
517 event_init->setCandidate(candidate);
518 DispatchEvent(*RTCPeerConnectionIceEvent::Create(
519 event_type_names::kIcecandidate, event_init));
520 }
521
OnStateChanged(webrtc::IceTransportState new_state)522 void RTCIceTransport::OnStateChanged(webrtc::IceTransportState new_state) {
523 // MONKEY PATCH:
524 // Due to crbug.com/957487, the lower layers signal kFailed when they
525 // should have been sending kDisconnected. Remap the state.
526 if (new_state == webrtc::IceTransportState::kFailed) {
527 LOG(INFO) << "crbug/957487: Remapping ICE state failed to disconnected";
528 new_state = webrtc::IceTransportState::kDisconnected;
529 }
530 if (new_state == state_) {
531 return;
532 }
533 state_ = new_state;
534 if (state_ == webrtc::IceTransportState::kFailed) {
535 selected_candidate_pair_ = nullptr;
536 }
537 // Make sure the peerconnection's state is updated before the event fires.
538 if (peer_connection_) {
539 peer_connection_->UpdateIceConnectionState();
540 }
541 DispatchEvent(*Event::Create(event_type_names::kStatechange));
542 if (state_ == webrtc::IceTransportState::kClosed ||
543 state_ == webrtc::IceTransportState::kFailed) {
544 stop();
545 }
546 }
547
OnSelectedCandidatePairChanged(const std::pair<cricket::Candidate,cricket::Candidate> & selected_candidate_pair)548 void RTCIceTransport::OnSelectedCandidatePairChanged(
549 const std::pair<cricket::Candidate, cricket::Candidate>&
550 selected_candidate_pair) {
551 RTCIceCandidate* local =
552 ConvertToRtcIceCandidate(selected_candidate_pair.first);
553 RTCIceCandidate* remote =
554 ConvertToRtcIceCandidate(selected_candidate_pair.second);
555 selected_candidate_pair_ = RTCIceCandidatePair::Create();
556 selected_candidate_pair_->setLocal(local);
557 selected_candidate_pair_->setRemote(remote);
558 DispatchEvent(*Event::Create(event_type_names::kSelectedcandidatepairchange));
559 }
560
Close(CloseReason reason)561 void RTCIceTransport::Close(CloseReason reason) {
562 if (IsClosed()) {
563 return;
564 }
565 if (HasConsumer()) {
566 consumer_->OnIceTransportClosed(reason);
567 }
568 // Notifying the consumer that we're closing should cause it to disconnect.
569 DCHECK(!HasConsumer());
570 state_ = webrtc::IceTransportState::kClosed;
571 selected_candidate_pair_ = nullptr;
572 proxy_.reset();
573 }
574
RaiseExceptionIfClosed(ExceptionState & exception_state) const575 bool RTCIceTransport::RaiseExceptionIfClosed(
576 ExceptionState& exception_state) const {
577 if (IsClosed()) {
578 exception_state.ThrowDOMException(
579 DOMExceptionCode::kInvalidStateError,
580 "The RTCIceTransport's state is 'closed'.");
581 return true;
582 }
583 return false;
584 }
585
InterfaceName() const586 const AtomicString& RTCIceTransport::InterfaceName() const {
587 return event_target_names::kRTCIceTransport;
588 }
589
GetExecutionContext() const590 ExecutionContext* RTCIceTransport::GetExecutionContext() const {
591 return ExecutionContextLifecycleObserver::GetExecutionContext();
592 }
593
ContextDestroyed()594 void RTCIceTransport::ContextDestroyed() {
595 Close(CloseReason::kContextDestroyed);
596 }
597
HasPendingActivity() const598 bool RTCIceTransport::HasPendingActivity() const {
599 // Only allow the RTCIceTransport to be garbage collected if the ICE
600 // implementation is not active.
601 return !!proxy_;
602 }
603
Trace(Visitor * visitor)604 void RTCIceTransport::Trace(Visitor* visitor) {
605 visitor->Trace(local_candidates_);
606 visitor->Trace(remote_candidates_);
607 visitor->Trace(local_parameters_);
608 visitor->Trace(remote_parameters_);
609 visitor->Trace(selected_candidate_pair_);
610 visitor->Trace(consumer_);
611 visitor->Trace(peer_connection_);
612 EventTargetWithInlineData::Trace(visitor);
613 ExecutionContextLifecycleObserver::Trace(visitor);
614 }
615
Dispose()616 void RTCIceTransport::Dispose() {
617 Close(CloseReason::kDisposed);
618 }
619
620 } // namespace blink
621