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