blob: 128d2fc656406d75b7b094baf1e8a57cd32513e1 [file] [log] [blame]
deadbeefcbecd352015-09-23 11:50:27 -07001/*
2 * Copyright 2015 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "webrtc/p2p/base/transportcontroller.h"
12
Taylor Brandstetterc4d3a5d2015-09-30 10:32:59 -070013#include <algorithm>
14
deadbeefcbecd352015-09-23 11:50:27 -070015#include "webrtc/base/bind.h"
16#include "webrtc/base/checks.h"
17#include "webrtc/base/thread.h"
18#include "webrtc/p2p/base/dtlstransport.h"
19#include "webrtc/p2p/base/p2ptransport.h"
Taylor Brandstetterc4d3a5d2015-09-30 10:32:59 -070020#include "webrtc/p2p/base/port.h"
deadbeefcbecd352015-09-23 11:50:27 -070021
22namespace cricket {
23
24enum {
25 MSG_ICECONNECTIONSTATE,
26 MSG_RECEIVING,
27 MSG_ICEGATHERINGSTATE,
28 MSG_CANDIDATESGATHERED,
29};
30
31struct CandidatesData : public rtc::MessageData {
32 CandidatesData(const std::string& transport_name,
33 const Candidates& candidates)
34 : transport_name(transport_name), candidates(candidates) {}
35
36 std::string transport_name;
37 Candidates candidates;
38};
39
40TransportController::TransportController(rtc::Thread* signaling_thread,
41 rtc::Thread* worker_thread,
42 PortAllocator* port_allocator)
43 : signaling_thread_(signaling_thread),
44 worker_thread_(worker_thread),
45 port_allocator_(port_allocator) {}
46
47TransportController::~TransportController() {
48 worker_thread_->Invoke<void>(
49 rtc::Bind(&TransportController::DestroyAllTransports_w, this));
50 signaling_thread_->Clear(this);
51}
52
53bool TransportController::SetSslMaxProtocolVersion(
54 rtc::SSLProtocolVersion version) {
55 return worker_thread_->Invoke<bool>(rtc::Bind(
56 &TransportController::SetSslMaxProtocolVersion_w, this, version));
57}
58
honghaiz1f429e32015-09-28 07:57:34 -070059void TransportController::SetIceConfig(const IceConfig& config) {
deadbeefcbecd352015-09-23 11:50:27 -070060 worker_thread_->Invoke<void>(
honghaiz1f429e32015-09-28 07:57:34 -070061 rtc::Bind(&TransportController::SetIceConfig_w, this, config));
deadbeefcbecd352015-09-23 11:50:27 -070062}
63
64void TransportController::SetIceRole(IceRole ice_role) {
65 worker_thread_->Invoke<void>(
66 rtc::Bind(&TransportController::SetIceRole_w, this, ice_role));
67}
68
Taylor Brandstetterf475d362016-01-08 15:35:57 -080069bool TransportController::GetSslRole(const std::string& transport_name,
70 rtc::SSLRole* role) {
71 return worker_thread_->Invoke<bool>(rtc::Bind(
72 &TransportController::GetSslRole_w, this, transport_name, role));
deadbeefcbecd352015-09-23 11:50:27 -070073}
74
75bool TransportController::SetLocalCertificate(
76 const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) {
77 return worker_thread_->Invoke<bool>(rtc::Bind(
78 &TransportController::SetLocalCertificate_w, this, certificate));
79}
80
81bool TransportController::GetLocalCertificate(
82 const std::string& transport_name,
83 rtc::scoped_refptr<rtc::RTCCertificate>* certificate) {
84 return worker_thread_->Invoke<bool>(
85 rtc::Bind(&TransportController::GetLocalCertificate_w, this,
86 transport_name, certificate));
87}
88
89bool TransportController::GetRemoteSSLCertificate(
90 const std::string& transport_name,
91 rtc::SSLCertificate** cert) {
92 return worker_thread_->Invoke<bool>(
93 rtc::Bind(&TransportController::GetRemoteSSLCertificate_w, this,
94 transport_name, cert));
95}
96
97bool TransportController::SetLocalTransportDescription(
98 const std::string& transport_name,
99 const TransportDescription& tdesc,
100 ContentAction action,
101 std::string* err) {
102 return worker_thread_->Invoke<bool>(
103 rtc::Bind(&TransportController::SetLocalTransportDescription_w, this,
104 transport_name, tdesc, action, err));
105}
106
107bool TransportController::SetRemoteTransportDescription(
108 const std::string& transport_name,
109 const TransportDescription& tdesc,
110 ContentAction action,
111 std::string* err) {
112 return worker_thread_->Invoke<bool>(
113 rtc::Bind(&TransportController::SetRemoteTransportDescription_w, this,
114 transport_name, tdesc, action, err));
115}
116
117void TransportController::MaybeStartGathering() {
118 worker_thread_->Invoke<void>(
119 rtc::Bind(&TransportController::MaybeStartGathering_w, this));
120}
121
122bool TransportController::AddRemoteCandidates(const std::string& transport_name,
123 const Candidates& candidates,
124 std::string* err) {
125 return worker_thread_->Invoke<bool>(
126 rtc::Bind(&TransportController::AddRemoteCandidates_w, this,
127 transport_name, candidates, err));
128}
129
Honghai Zhang7fb69db2016-03-14 11:59:18 -0700130bool TransportController::RemoveRemoteCandidates(const Candidates& candidates,
131 std::string* err) {
132 return worker_thread_->Invoke<bool>(rtc::Bind(
133 &TransportController::RemoveRemoteCandidates_w, this, candidates, err));
134}
135
deadbeefcbecd352015-09-23 11:50:27 -0700136bool TransportController::ReadyForRemoteCandidates(
137 const std::string& transport_name) {
138 return worker_thread_->Invoke<bool>(rtc::Bind(
139 &TransportController::ReadyForRemoteCandidates_w, this, transport_name));
140}
141
142bool TransportController::GetStats(const std::string& transport_name,
143 TransportStats* stats) {
144 return worker_thread_->Invoke<bool>(
145 rtc::Bind(&TransportController::GetStats_w, this, transport_name, stats));
146}
147
148TransportChannel* TransportController::CreateTransportChannel_w(
149 const std::string& transport_name,
150 int component) {
151 RTC_DCHECK(worker_thread_->IsCurrent());
152
Taylor Brandstetterc4d3a5d2015-09-30 10:32:59 -0700153 auto it = FindChannel_w(transport_name, component);
154 if (it != channels_.end()) {
155 // Channel already exists; increment reference count and return.
156 it->AddRef();
157 return it->get();
158 }
159
160 // Need to create a new channel.
deadbeefcbecd352015-09-23 11:50:27 -0700161 Transport* transport = GetOrCreateTransport_w(transport_name);
Taylor Brandstetterc4d3a5d2015-09-30 10:32:59 -0700162 TransportChannelImpl* channel = transport->CreateChannel(component);
163 channel->SignalWritableState.connect(
164 this, &TransportController::OnChannelWritableState_w);
165 channel->SignalReceivingState.connect(
166 this, &TransportController::OnChannelReceivingState_w);
167 channel->SignalGatheringState.connect(
168 this, &TransportController::OnChannelGatheringState_w);
169 channel->SignalCandidateGathered.connect(
170 this, &TransportController::OnChannelCandidateGathered_w);
Honghai Zhang7fb69db2016-03-14 11:59:18 -0700171 channel->SignalCandidatesRemoved.connect(
172 this, &TransportController::OnChannelCandidatesRemoved_w);
Taylor Brandstetterc4d3a5d2015-09-30 10:32:59 -0700173 channel->SignalRoleConflict.connect(
174 this, &TransportController::OnChannelRoleConflict_w);
175 channel->SignalConnectionRemoved.connect(
176 this, &TransportController::OnChannelConnectionRemoved_w);
177 channels_.insert(channels_.end(), RefCountedChannel(channel))->AddRef();
178 // Adding a channel could cause aggregate state to change.
179 UpdateAggregateStates_w();
180 return channel;
deadbeefcbecd352015-09-23 11:50:27 -0700181}
182
183void TransportController::DestroyTransportChannel_w(
184 const std::string& transport_name,
185 int component) {
186 RTC_DCHECK(worker_thread_->IsCurrent());
187
Taylor Brandstetterc4d3a5d2015-09-30 10:32:59 -0700188 auto it = FindChannel_w(transport_name, component);
189 if (it == channels_.end()) {
190 LOG(LS_WARNING) << "Attempting to delete " << transport_name
191 << " TransportChannel " << component
192 << ", which doesn't exist.";
deadbeefcbecd352015-09-23 11:50:27 -0700193 return;
194 }
deadbeefcbecd352015-09-23 11:50:27 -0700195
Taylor Brandstetterc4d3a5d2015-09-30 10:32:59 -0700196 it->DecRef();
197 if (it->ref() > 0) {
198 return;
199 }
200
201 channels_.erase(it);
202 Transport* transport = GetTransport_w(transport_name);
203 transport->DestroyChannel(component);
deadbeefcbecd352015-09-23 11:50:27 -0700204 // Just as we create a Transport when its first channel is created,
205 // we delete it when its last channel is deleted.
206 if (!transport->HasChannels()) {
207 DestroyTransport_w(transport_name);
208 }
Taylor Brandstetterc4d3a5d2015-09-30 10:32:59 -0700209 // Removing a channel could cause aggregate state to change.
210 UpdateAggregateStates_w();
deadbeefcbecd352015-09-23 11:50:27 -0700211}
212
213const rtc::scoped_refptr<rtc::RTCCertificate>&
214TransportController::certificate_for_testing() {
215 return certificate_;
216}
217
218Transport* TransportController::CreateTransport_w(
219 const std::string& transport_name) {
220 RTC_DCHECK(worker_thread_->IsCurrent());
221
222 Transport* transport = new DtlsTransport<P2PTransport>(
223 transport_name, port_allocator(), certificate_);
224 return transport;
225}
226
227Transport* TransportController::GetTransport_w(
228 const std::string& transport_name) {
229 RTC_DCHECK(worker_thread_->IsCurrent());
230
231 auto iter = transports_.find(transport_name);
232 return (iter != transports_.end()) ? iter->second : nullptr;
233}
234
235void TransportController::OnMessage(rtc::Message* pmsg) {
236 RTC_DCHECK(signaling_thread_->IsCurrent());
237
238 switch (pmsg->message_id) {
239 case MSG_ICECONNECTIONSTATE: {
240 rtc::TypedMessageData<IceConnectionState>* data =
241 static_cast<rtc::TypedMessageData<IceConnectionState>*>(pmsg->pdata);
242 SignalConnectionState(data->data());
243 delete data;
244 break;
245 }
246 case MSG_RECEIVING: {
247 rtc::TypedMessageData<bool>* data =
248 static_cast<rtc::TypedMessageData<bool>*>(pmsg->pdata);
249 SignalReceiving(data->data());
250 delete data;
251 break;
252 }
253 case MSG_ICEGATHERINGSTATE: {
254 rtc::TypedMessageData<IceGatheringState>* data =
255 static_cast<rtc::TypedMessageData<IceGatheringState>*>(pmsg->pdata);
256 SignalGatheringState(data->data());
257 delete data;
258 break;
259 }
260 case MSG_CANDIDATESGATHERED: {
261 CandidatesData* data = static_cast<CandidatesData*>(pmsg->pdata);
262 SignalCandidatesGathered(data->transport_name, data->candidates);
263 delete data;
264 break;
265 }
266 default:
267 ASSERT(false);
268 }
269}
270
Taylor Brandstetterc4d3a5d2015-09-30 10:32:59 -0700271std::vector<TransportController::RefCountedChannel>::iterator
272TransportController::FindChannel_w(const std::string& transport_name,
273 int component) {
274 return std::find_if(
275 channels_.begin(), channels_.end(),
276 [transport_name, component](const RefCountedChannel& channel) {
277 return channel->transport_name() == transport_name &&
278 channel->component() == component;
279 });
280}
281
deadbeefcbecd352015-09-23 11:50:27 -0700282Transport* TransportController::GetOrCreateTransport_w(
283 const std::string& transport_name) {
284 RTC_DCHECK(worker_thread_->IsCurrent());
285
286 Transport* transport = GetTransport_w(transport_name);
287 if (transport) {
288 return transport;
289 }
290
291 transport = CreateTransport_w(transport_name);
292 // The stuff below happens outside of CreateTransport_w so that unit tests
293 // can override CreateTransport_w to return a different type of transport.
294 transport->SetSslMaxProtocolVersion(ssl_max_version_);
honghaiz1f429e32015-09-28 07:57:34 -0700295 transport->SetIceConfig(ice_config_);
deadbeefcbecd352015-09-23 11:50:27 -0700296 transport->SetIceRole(ice_role_);
297 transport->SetIceTiebreaker(ice_tiebreaker_);
298 if (certificate_) {
299 transport->SetLocalCertificate(certificate_);
300 }
deadbeefcbecd352015-09-23 11:50:27 -0700301 transports_[transport_name] = transport;
302
303 return transport;
304}
305
306void TransportController::DestroyTransport_w(
307 const std::string& transport_name) {
308 RTC_DCHECK(worker_thread_->IsCurrent());
309
310 auto iter = transports_.find(transport_name);
311 if (iter != transports_.end()) {
312 delete iter->second;
313 transports_.erase(transport_name);
314 }
deadbeefcbecd352015-09-23 11:50:27 -0700315}
316
317void TransportController::DestroyAllTransports_w() {
318 RTC_DCHECK(worker_thread_->IsCurrent());
319
320 for (const auto& kv : transports_) {
321 delete kv.second;
322 }
323 transports_.clear();
324}
325
326bool TransportController::SetSslMaxProtocolVersion_w(
327 rtc::SSLProtocolVersion version) {
328 RTC_DCHECK(worker_thread_->IsCurrent());
329
330 // Max SSL version can only be set before transports are created.
331 if (!transports_.empty()) {
332 return false;
333 }
334
335 ssl_max_version_ = version;
336 return true;
337}
338
honghaiz1f429e32015-09-28 07:57:34 -0700339void TransportController::SetIceConfig_w(const IceConfig& config) {
deadbeefcbecd352015-09-23 11:50:27 -0700340 RTC_DCHECK(worker_thread_->IsCurrent());
honghaiz1f429e32015-09-28 07:57:34 -0700341 ice_config_ = config;
deadbeefcbecd352015-09-23 11:50:27 -0700342 for (const auto& kv : transports_) {
honghaiz1f429e32015-09-28 07:57:34 -0700343 kv.second->SetIceConfig(ice_config_);
deadbeefcbecd352015-09-23 11:50:27 -0700344 }
345}
346
347void TransportController::SetIceRole_w(IceRole ice_role) {
348 RTC_DCHECK(worker_thread_->IsCurrent());
349 ice_role_ = ice_role;
350 for (const auto& kv : transports_) {
351 kv.second->SetIceRole(ice_role_);
352 }
353}
354
Taylor Brandstetterf475d362016-01-08 15:35:57 -0800355bool TransportController::GetSslRole_w(const std::string& transport_name,
356 rtc::SSLRole* role) {
deadbeefcbecd352015-09-23 11:50:27 -0700357 RTC_DCHECK(worker_thread()->IsCurrent());
358
Taylor Brandstetterf475d362016-01-08 15:35:57 -0800359 Transport* t = GetTransport_w(transport_name);
360 if (!t) {
deadbeefcbecd352015-09-23 11:50:27 -0700361 return false;
362 }
Taylor Brandstetterf475d362016-01-08 15:35:57 -0800363
364 return t->GetSslRole(role);
deadbeefcbecd352015-09-23 11:50:27 -0700365}
366
367bool TransportController::SetLocalCertificate_w(
368 const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) {
369 RTC_DCHECK(worker_thread_->IsCurrent());
370
371 if (certificate_) {
372 return false;
373 }
374 if (!certificate) {
375 return false;
376 }
377 certificate_ = certificate;
378
379 for (const auto& kv : transports_) {
380 kv.second->SetLocalCertificate(certificate_);
381 }
382 return true;
383}
384
385bool TransportController::GetLocalCertificate_w(
386 const std::string& transport_name,
387 rtc::scoped_refptr<rtc::RTCCertificate>* certificate) {
388 RTC_DCHECK(worker_thread_->IsCurrent());
389
390 Transport* t = GetTransport_w(transport_name);
391 if (!t) {
392 return false;
393 }
394
395 return t->GetLocalCertificate(certificate);
396}
397
398bool TransportController::GetRemoteSSLCertificate_w(
399 const std::string& transport_name,
400 rtc::SSLCertificate** cert) {
401 RTC_DCHECK(worker_thread_->IsCurrent());
402
403 Transport* t = GetTransport_w(transport_name);
404 if (!t) {
405 return false;
406 }
407
408 return t->GetRemoteSSLCertificate(cert);
409}
410
411bool TransportController::SetLocalTransportDescription_w(
412 const std::string& transport_name,
413 const TransportDescription& tdesc,
414 ContentAction action,
415 std::string* err) {
416 RTC_DCHECK(worker_thread()->IsCurrent());
417
418 Transport* transport = GetTransport_w(transport_name);
419 if (!transport) {
420 // If we didn't find a transport, that's not an error;
421 // it could have been deleted as a result of bundling.
422 // TODO(deadbeef): Make callers smarter so they won't attempt to set a
423 // description on a deleted transport.
424 return true;
425 }
426
427 return transport->SetLocalTransportDescription(tdesc, action, err);
428}
429
430bool TransportController::SetRemoteTransportDescription_w(
431 const std::string& transport_name,
432 const TransportDescription& tdesc,
433 ContentAction action,
434 std::string* err) {
435 RTC_DCHECK(worker_thread()->IsCurrent());
436
437 Transport* transport = GetTransport_w(transport_name);
438 if (!transport) {
439 // If we didn't find a transport, that's not an error;
440 // it could have been deleted as a result of bundling.
441 // TODO(deadbeef): Make callers smarter so they won't attempt to set a
442 // description on a deleted transport.
443 return true;
444 }
445
446 return transport->SetRemoteTransportDescription(tdesc, action, err);
447}
448
449void TransportController::MaybeStartGathering_w() {
450 for (const auto& kv : transports_) {
451 kv.second->MaybeStartGathering();
452 }
453}
454
455bool TransportController::AddRemoteCandidates_w(
456 const std::string& transport_name,
457 const Candidates& candidates,
458 std::string* err) {
459 RTC_DCHECK(worker_thread()->IsCurrent());
460
461 Transport* transport = GetTransport_w(transport_name);
462 if (!transport) {
463 // If we didn't find a transport, that's not an error;
464 // it could have been deleted as a result of bundling.
465 return true;
466 }
467
468 return transport->AddRemoteCandidates(candidates, err);
469}
470
Honghai Zhang7fb69db2016-03-14 11:59:18 -0700471bool TransportController::RemoveRemoteCandidates_w(const Candidates& candidates,
472 std::string* err) {
473 RTC_DCHECK(worker_thread()->IsCurrent());
474 std::map<std::string, Candidates> candidates_by_transport_name;
475 for (const Candidate& cand : candidates) {
476 RTC_DCHECK(!cand.transport_name().empty());
477 candidates_by_transport_name[cand.transport_name()].push_back(cand);
478 }
479
480 bool result = true;
481 for (auto kv : candidates_by_transport_name) {
482 Transport* transport = GetTransport_w(kv.first);
483 if (!transport) {
484 // If we didn't find a transport, that's not an error;
485 // it could have been deleted as a result of bundling.
486 continue;
487 }
488 result &= transport->RemoveRemoteCandidates(kv.second, err);
489 }
490 return result;
491}
492
deadbeefcbecd352015-09-23 11:50:27 -0700493bool TransportController::ReadyForRemoteCandidates_w(
494 const std::string& transport_name) {
495 RTC_DCHECK(worker_thread()->IsCurrent());
496
497 Transport* transport = GetTransport_w(transport_name);
498 if (!transport) {
499 return false;
500 }
501 return transport->ready_for_remote_candidates();
502}
503
504bool TransportController::GetStats_w(const std::string& transport_name,
505 TransportStats* stats) {
506 RTC_DCHECK(worker_thread()->IsCurrent());
507
508 Transport* transport = GetTransport_w(transport_name);
509 if (!transport) {
510 return false;
511 }
512 return transport->GetStats(stats);
513}
514
Taylor Brandstetterc4d3a5d2015-09-30 10:32:59 -0700515void TransportController::OnChannelWritableState_w(TransportChannel* channel) {
516 RTC_DCHECK(worker_thread_->IsCurrent());
517 LOG(LS_INFO) << channel->transport_name() << " TransportChannel "
518 << channel->component() << " writability changed to "
519 << channel->writable() << ".";
520 UpdateAggregateStates_w();
521}
522
523void TransportController::OnChannelReceivingState_w(TransportChannel* channel) {
deadbeefcbecd352015-09-23 11:50:27 -0700524 RTC_DCHECK(worker_thread_->IsCurrent());
525 UpdateAggregateStates_w();
526}
527
Taylor Brandstetterc4d3a5d2015-09-30 10:32:59 -0700528void TransportController::OnChannelGatheringState_w(
529 TransportChannelImpl* channel) {
deadbeefcbecd352015-09-23 11:50:27 -0700530 RTC_DCHECK(worker_thread_->IsCurrent());
531 UpdateAggregateStates_w();
532}
533
Taylor Brandstetterc4d3a5d2015-09-30 10:32:59 -0700534void TransportController::OnChannelCandidateGathered_w(
535 TransportChannelImpl* channel,
536 const Candidate& candidate) {
deadbeefcbecd352015-09-23 11:50:27 -0700537 RTC_DCHECK(worker_thread_->IsCurrent());
deadbeefcbecd352015-09-23 11:50:27 -0700538
Taylor Brandstetterc4d3a5d2015-09-30 10:32:59 -0700539 // We should never signal peer-reflexive candidates.
540 if (candidate.type() == PRFLX_PORT_TYPE) {
541 RTC_DCHECK(false);
542 return;
543 }
544 std::vector<Candidate> candidates;
545 candidates.push_back(candidate);
546 CandidatesData* data =
547 new CandidatesData(channel->transport_name(), candidates);
deadbeefcbecd352015-09-23 11:50:27 -0700548 signaling_thread_->Post(this, MSG_CANDIDATESGATHERED, data);
549}
550
Honghai Zhang7fb69db2016-03-14 11:59:18 -0700551void TransportController::OnChannelCandidatesRemoved_w(
552 TransportChannelImpl* channel,
553 const Candidates& candidates) {
554 invoker_.AsyncInvoke<void>(
555 signaling_thread_,
556 rtc::Bind(&TransportController::OnChannelCandidatesRemoved, this,
557 candidates));
558}
559
560void TransportController::OnChannelCandidatesRemoved(
561 const Candidates& candidates) {
562 RTC_DCHECK(signaling_thread_->IsCurrent());
563 SignalCandidatesRemoved(candidates);
564}
565
Taylor Brandstetterc4d3a5d2015-09-30 10:32:59 -0700566void TransportController::OnChannelRoleConflict_w(
567 TransportChannelImpl* channel) {
deadbeefcbecd352015-09-23 11:50:27 -0700568 RTC_DCHECK(worker_thread_->IsCurrent());
569
570 if (ice_role_switch_) {
Taylor Brandstetterc4d3a5d2015-09-30 10:32:59 -0700571 LOG(LS_WARNING)
572 << "Repeat of role conflict signal from TransportChannelImpl.";
deadbeefcbecd352015-09-23 11:50:27 -0700573 return;
574 }
575
576 ice_role_switch_ = true;
577 IceRole reversed_role = (ice_role_ == ICEROLE_CONTROLLING)
578 ? ICEROLE_CONTROLLED
579 : ICEROLE_CONTROLLING;
580 for (const auto& kv : transports_) {
581 kv.second->SetIceRole(reversed_role);
582 }
583}
584
Taylor Brandstetterc4d3a5d2015-09-30 10:32:59 -0700585void TransportController::OnChannelConnectionRemoved_w(
586 TransportChannelImpl* channel) {
587 RTC_DCHECK(worker_thread_->IsCurrent());
588 LOG(LS_INFO) << channel->transport_name() << " TransportChannel "
589 << channel->component()
590 << " connection removed. Check if state is complete.";
591 UpdateAggregateStates_w();
592}
593
deadbeefcbecd352015-09-23 11:50:27 -0700594void TransportController::UpdateAggregateStates_w() {
595 RTC_DCHECK(worker_thread_->IsCurrent());
596
597 IceConnectionState new_connection_state = kIceConnectionConnecting;
598 IceGatheringState new_gathering_state = kIceGatheringNew;
599 bool any_receiving = false;
600 bool any_failed = false;
Taylor Brandstetterc4d3a5d2015-09-30 10:32:59 -0700601 bool all_connected = !channels_.empty();
602 bool all_completed = !channels_.empty();
deadbeefcbecd352015-09-23 11:50:27 -0700603 bool any_gathering = false;
Taylor Brandstetterc4d3a5d2015-09-30 10:32:59 -0700604 bool all_done_gathering = !channels_.empty();
605 for (const auto& channel : channels_) {
606 any_receiving = any_receiving || channel->receiving();
607 any_failed = any_failed ||
608 channel->GetState() == TransportChannelState::STATE_FAILED;
609 all_connected = all_connected && channel->writable();
610 all_completed =
611 all_completed && channel->writable() &&
612 channel->GetState() == TransportChannelState::STATE_COMPLETED &&
613 channel->GetIceRole() == ICEROLE_CONTROLLING &&
614 channel->gathering_state() == kIceGatheringComplete;
deadbeefcbecd352015-09-23 11:50:27 -0700615 any_gathering =
Taylor Brandstetterc4d3a5d2015-09-30 10:32:59 -0700616 any_gathering || channel->gathering_state() != kIceGatheringNew;
deadbeefcbecd352015-09-23 11:50:27 -0700617 all_done_gathering = all_done_gathering &&
Taylor Brandstetterc4d3a5d2015-09-30 10:32:59 -0700618 channel->gathering_state() == kIceGatheringComplete;
deadbeefcbecd352015-09-23 11:50:27 -0700619 }
620
621 if (any_failed) {
622 new_connection_state = kIceConnectionFailed;
623 } else if (all_completed) {
624 new_connection_state = kIceConnectionCompleted;
625 } else if (all_connected) {
626 new_connection_state = kIceConnectionConnected;
627 }
628 if (connection_state_ != new_connection_state) {
629 connection_state_ = new_connection_state;
630 signaling_thread_->Post(
631 this, MSG_ICECONNECTIONSTATE,
632 new rtc::TypedMessageData<IceConnectionState>(new_connection_state));
633 }
634
635 if (receiving_ != any_receiving) {
636 receiving_ = any_receiving;
637 signaling_thread_->Post(this, MSG_RECEIVING,
638 new rtc::TypedMessageData<bool>(any_receiving));
639 }
640
641 if (all_done_gathering) {
642 new_gathering_state = kIceGatheringComplete;
643 } else if (any_gathering) {
644 new_gathering_state = kIceGatheringGathering;
645 }
646 if (gathering_state_ != new_gathering_state) {
647 gathering_state_ = new_gathering_state;
648 signaling_thread_->Post(
649 this, MSG_ICEGATHERINGSTATE,
650 new rtc::TypedMessageData<IceGatheringState>(new_gathering_state));
651 }
652}
653
deadbeefcbecd352015-09-23 11:50:27 -0700654} // namespace cricket