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