OLD | NEW |
| (Empty) |
1 /* | |
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 | |
13 #include "webrtc/base/bind.h" | |
14 #include "webrtc/base/checks.h" | |
15 #include "webrtc/base/thread.h" | |
16 #include "webrtc/p2p/base/dtlstransport.h" | |
17 #include "webrtc/p2p/base/p2ptransport.h" | |
18 | |
19 namespace cricket { | |
20 | |
21 enum { | |
22 MSG_ICECONNECTIONSTATE, | |
23 MSG_RECEIVING, | |
24 MSG_ICEGATHERINGSTATE, | |
25 MSG_CANDIDATESGATHERED, | |
26 }; | |
27 | |
28 struct CandidatesData : public rtc::MessageData { | |
29 CandidatesData(const std::string& transport_name, | |
30 const Candidates& candidates) | |
31 : transport_name(transport_name), candidates(candidates) {} | |
32 | |
33 std::string transport_name; | |
34 Candidates candidates; | |
35 }; | |
36 | |
37 TransportController::TransportController(rtc::Thread* signaling_thread, | |
38 rtc::Thread* worker_thread, | |
39 PortAllocator* port_allocator) | |
40 : signaling_thread_(signaling_thread), | |
41 worker_thread_(worker_thread), | |
42 port_allocator_(port_allocator) {} | |
43 | |
44 TransportController::~TransportController() { | |
45 worker_thread_->Invoke<void>( | |
46 rtc::Bind(&TransportController::DestroyAllTransports_w, this)); | |
47 signaling_thread_->Clear(this); | |
48 } | |
49 | |
50 bool TransportController::SetSslMaxProtocolVersion( | |
51 rtc::SSLProtocolVersion version) { | |
52 return worker_thread_->Invoke<bool>(rtc::Bind( | |
53 &TransportController::SetSslMaxProtocolVersion_w, this, version)); | |
54 } | |
55 | |
56 void TransportController::SetIceConnectionReceivingTimeout(int timeout_ms) { | |
57 worker_thread_->Invoke<void>( | |
58 rtc::Bind(&TransportController::SetIceConnectionReceivingTimeout_w, this, | |
59 timeout_ms)); | |
60 } | |
61 | |
62 void TransportController::SetIceRole(IceRole ice_role) { | |
63 worker_thread_->Invoke<void>( | |
64 rtc::Bind(&TransportController::SetIceRole_w, this, ice_role)); | |
65 } | |
66 | |
67 bool TransportController::GetSslRole(rtc::SSLRole* role) { | |
68 return worker_thread_->Invoke<bool>( | |
69 rtc::Bind(&TransportController::GetSslRole_w, this, role)); | |
70 } | |
71 | |
72 bool TransportController::SetLocalCertificate( | |
73 const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) { | |
74 return worker_thread_->Invoke<bool>(rtc::Bind( | |
75 &TransportController::SetLocalCertificate_w, this, certificate)); | |
76 } | |
77 | |
78 bool TransportController::GetLocalCertificate( | |
79 const std::string& transport_name, | |
80 rtc::scoped_refptr<rtc::RTCCertificate>* certificate) { | |
81 return worker_thread_->Invoke<bool>( | |
82 rtc::Bind(&TransportController::GetLocalCertificate_w, this, | |
83 transport_name, certificate)); | |
84 } | |
85 | |
86 bool TransportController::GetRemoteSSLCertificate( | |
87 const std::string& transport_name, | |
88 rtc::SSLCertificate** cert) { | |
89 return worker_thread_->Invoke<bool>( | |
90 rtc::Bind(&TransportController::GetRemoteSSLCertificate_w, this, | |
91 transport_name, cert)); | |
92 } | |
93 | |
94 bool TransportController::SetLocalTransportDescription( | |
95 const std::string& transport_name, | |
96 const TransportDescription& tdesc, | |
97 ContentAction action, | |
98 std::string* err) { | |
99 return worker_thread_->Invoke<bool>( | |
100 rtc::Bind(&TransportController::SetLocalTransportDescription_w, this, | |
101 transport_name, tdesc, action, err)); | |
102 } | |
103 | |
104 bool TransportController::SetRemoteTransportDescription( | |
105 const std::string& transport_name, | |
106 const TransportDescription& tdesc, | |
107 ContentAction action, | |
108 std::string* err) { | |
109 return worker_thread_->Invoke<bool>( | |
110 rtc::Bind(&TransportController::SetRemoteTransportDescription_w, this, | |
111 transport_name, tdesc, action, err)); | |
112 } | |
113 | |
114 void TransportController::MaybeStartGathering() { | |
115 worker_thread_->Invoke<void>( | |
116 rtc::Bind(&TransportController::MaybeStartGathering_w, this)); | |
117 } | |
118 | |
119 bool TransportController::AddRemoteCandidates(const std::string& transport_name, | |
120 const Candidates& candidates, | |
121 std::string* err) { | |
122 return worker_thread_->Invoke<bool>( | |
123 rtc::Bind(&TransportController::AddRemoteCandidates_w, this, | |
124 transport_name, candidates, err)); | |
125 } | |
126 | |
127 bool TransportController::ReadyForRemoteCandidates( | |
128 const std::string& transport_name) { | |
129 return worker_thread_->Invoke<bool>(rtc::Bind( | |
130 &TransportController::ReadyForRemoteCandidates_w, this, transport_name)); | |
131 } | |
132 | |
133 bool TransportController::GetStats(const std::string& transport_name, | |
134 TransportStats* stats) { | |
135 return worker_thread_->Invoke<bool>( | |
136 rtc::Bind(&TransportController::GetStats_w, this, transport_name, stats)); | |
137 } | |
138 | |
139 TransportChannel* TransportController::CreateTransportChannel_w( | |
140 const std::string& transport_name, | |
141 int component) { | |
142 RTC_DCHECK(worker_thread_->IsCurrent()); | |
143 | |
144 Transport* transport = GetOrCreateTransport_w(transport_name); | |
145 return transport->CreateChannel(component); | |
146 } | |
147 | |
148 void TransportController::DestroyTransportChannel_w( | |
149 const std::string& transport_name, | |
150 int component) { | |
151 RTC_DCHECK(worker_thread_->IsCurrent()); | |
152 | |
153 Transport* transport = GetTransport_w(transport_name); | |
154 if (!transport) { | |
155 ASSERT(false); | |
156 return; | |
157 } | |
158 transport->DestroyChannel(component); | |
159 | |
160 // Just as we create a Transport when its first channel is created, | |
161 // we delete it when its last channel is deleted. | |
162 if (!transport->HasChannels()) { | |
163 DestroyTransport_w(transport_name); | |
164 } | |
165 } | |
166 | |
167 const rtc::scoped_refptr<rtc::RTCCertificate>& | |
168 TransportController::certificate_for_testing() { | |
169 return certificate_; | |
170 } | |
171 | |
172 Transport* TransportController::CreateTransport_w( | |
173 const std::string& transport_name) { | |
174 RTC_DCHECK(worker_thread_->IsCurrent()); | |
175 | |
176 Transport* transport = new DtlsTransport<P2PTransport>( | |
177 transport_name, port_allocator(), certificate_); | |
178 return transport; | |
179 } | |
180 | |
181 Transport* TransportController::GetTransport_w( | |
182 const std::string& transport_name) { | |
183 RTC_DCHECK(worker_thread_->IsCurrent()); | |
184 | |
185 auto iter = transports_.find(transport_name); | |
186 return (iter != transports_.end()) ? iter->second : nullptr; | |
187 } | |
188 | |
189 void TransportController::OnMessage(rtc::Message* pmsg) { | |
190 RTC_DCHECK(signaling_thread_->IsCurrent()); | |
191 | |
192 switch (pmsg->message_id) { | |
193 case MSG_ICECONNECTIONSTATE: { | |
194 rtc::TypedMessageData<IceConnectionState>* data = | |
195 static_cast<rtc::TypedMessageData<IceConnectionState>*>(pmsg->pdata); | |
196 SignalConnectionState(data->data()); | |
197 delete data; | |
198 break; | |
199 } | |
200 case MSG_RECEIVING: { | |
201 rtc::TypedMessageData<bool>* data = | |
202 static_cast<rtc::TypedMessageData<bool>*>(pmsg->pdata); | |
203 SignalReceiving(data->data()); | |
204 delete data; | |
205 break; | |
206 } | |
207 case MSG_ICEGATHERINGSTATE: { | |
208 rtc::TypedMessageData<IceGatheringState>* data = | |
209 static_cast<rtc::TypedMessageData<IceGatheringState>*>(pmsg->pdata); | |
210 SignalGatheringState(data->data()); | |
211 delete data; | |
212 break; | |
213 } | |
214 case MSG_CANDIDATESGATHERED: { | |
215 CandidatesData* data = static_cast<CandidatesData*>(pmsg->pdata); | |
216 SignalCandidatesGathered(data->transport_name, data->candidates); | |
217 delete data; | |
218 break; | |
219 } | |
220 default: | |
221 ASSERT(false); | |
222 } | |
223 } | |
224 | |
225 Transport* TransportController::GetOrCreateTransport_w( | |
226 const std::string& transport_name) { | |
227 RTC_DCHECK(worker_thread_->IsCurrent()); | |
228 | |
229 Transport* transport = GetTransport_w(transport_name); | |
230 if (transport) { | |
231 return transport; | |
232 } | |
233 | |
234 transport = CreateTransport_w(transport_name); | |
235 // The stuff below happens outside of CreateTransport_w so that unit tests | |
236 // can override CreateTransport_w to return a different type of transport. | |
237 transport->SetSslMaxProtocolVersion(ssl_max_version_); | |
238 transport->SetChannelReceivingTimeout(ice_receiving_timeout_ms_); | |
239 transport->SetIceRole(ice_role_); | |
240 transport->SetIceTiebreaker(ice_tiebreaker_); | |
241 if (certificate_) { | |
242 transport->SetLocalCertificate(certificate_); | |
243 } | |
244 transport->SignalConnecting.connect( | |
245 this, &TransportController::OnTransportConnecting_w); | |
246 transport->SignalWritableState.connect( | |
247 this, &TransportController::OnTransportWritableState_w); | |
248 transport->SignalReceivingState.connect( | |
249 this, &TransportController::OnTransportReceivingState_w); | |
250 transport->SignalCompleted.connect( | |
251 this, &TransportController::OnTransportCompleted_w); | |
252 transport->SignalFailed.connect(this, | |
253 &TransportController::OnTransportFailed_w); | |
254 transport->SignalGatheringState.connect( | |
255 this, &TransportController::OnTransportGatheringState_w); | |
256 transport->SignalCandidatesGathered.connect( | |
257 this, &TransportController::OnTransportCandidatesGathered_w); | |
258 transport->SignalRoleConflict.connect( | |
259 this, &TransportController::OnTransportRoleConflict_w); | |
260 transports_[transport_name] = transport; | |
261 | |
262 return transport; | |
263 } | |
264 | |
265 void TransportController::DestroyTransport_w( | |
266 const std::string& transport_name) { | |
267 RTC_DCHECK(worker_thread_->IsCurrent()); | |
268 | |
269 auto iter = transports_.find(transport_name); | |
270 if (iter != transports_.end()) { | |
271 delete iter->second; | |
272 transports_.erase(transport_name); | |
273 } | |
274 // Destroying a transport may cause aggregate state to change. | |
275 UpdateAggregateStates_w(); | |
276 } | |
277 | |
278 void TransportController::DestroyAllTransports_w() { | |
279 RTC_DCHECK(worker_thread_->IsCurrent()); | |
280 | |
281 for (const auto& kv : transports_) { | |
282 delete kv.second; | |
283 } | |
284 transports_.clear(); | |
285 } | |
286 | |
287 bool TransportController::SetSslMaxProtocolVersion_w( | |
288 rtc::SSLProtocolVersion version) { | |
289 RTC_DCHECK(worker_thread_->IsCurrent()); | |
290 | |
291 // Max SSL version can only be set before transports are created. | |
292 if (!transports_.empty()) { | |
293 return false; | |
294 } | |
295 | |
296 ssl_max_version_ = version; | |
297 return true; | |
298 } | |
299 | |
300 void TransportController::SetIceConnectionReceivingTimeout_w(int timeout_ms) { | |
301 RTC_DCHECK(worker_thread_->IsCurrent()); | |
302 ice_receiving_timeout_ms_ = timeout_ms; | |
303 for (const auto& kv : transports_) { | |
304 kv.second->SetChannelReceivingTimeout(timeout_ms); | |
305 } | |
306 } | |
307 | |
308 void TransportController::SetIceRole_w(IceRole ice_role) { | |
309 RTC_DCHECK(worker_thread_->IsCurrent()); | |
310 ice_role_ = ice_role; | |
311 for (const auto& kv : transports_) { | |
312 kv.second->SetIceRole(ice_role_); | |
313 } | |
314 } | |
315 | |
316 bool TransportController::GetSslRole_w(rtc::SSLRole* role) { | |
317 RTC_DCHECK(worker_thread()->IsCurrent()); | |
318 | |
319 if (transports_.empty()) { | |
320 return false; | |
321 } | |
322 return transports_.begin()->second->GetSslRole(role); | |
323 } | |
324 | |
325 bool TransportController::SetLocalCertificate_w( | |
326 const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) { | |
327 RTC_DCHECK(worker_thread_->IsCurrent()); | |
328 | |
329 if (certificate_) { | |
330 return false; | |
331 } | |
332 if (!certificate) { | |
333 return false; | |
334 } | |
335 certificate_ = certificate; | |
336 | |
337 for (const auto& kv : transports_) { | |
338 kv.second->SetLocalCertificate(certificate_); | |
339 } | |
340 return true; | |
341 } | |
342 | |
343 bool TransportController::GetLocalCertificate_w( | |
344 const std::string& transport_name, | |
345 rtc::scoped_refptr<rtc::RTCCertificate>* certificate) { | |
346 RTC_DCHECK(worker_thread_->IsCurrent()); | |
347 | |
348 Transport* t = GetTransport_w(transport_name); | |
349 if (!t) { | |
350 return false; | |
351 } | |
352 | |
353 return t->GetLocalCertificate(certificate); | |
354 } | |
355 | |
356 bool TransportController::GetRemoteSSLCertificate_w( | |
357 const std::string& transport_name, | |
358 rtc::SSLCertificate** cert) { | |
359 RTC_DCHECK(worker_thread_->IsCurrent()); | |
360 | |
361 Transport* t = GetTransport_w(transport_name); | |
362 if (!t) { | |
363 return false; | |
364 } | |
365 | |
366 return t->GetRemoteSSLCertificate(cert); | |
367 } | |
368 | |
369 bool TransportController::SetLocalTransportDescription_w( | |
370 const std::string& transport_name, | |
371 const TransportDescription& tdesc, | |
372 ContentAction action, | |
373 std::string* err) { | |
374 RTC_DCHECK(worker_thread()->IsCurrent()); | |
375 | |
376 Transport* transport = GetTransport_w(transport_name); | |
377 if (!transport) { | |
378 // If we didn't find a transport, that's not an error; | |
379 // it could have been deleted as a result of bundling. | |
380 // TODO(deadbeef): Make callers smarter so they won't attempt to set a | |
381 // description on a deleted transport. | |
382 return true; | |
383 } | |
384 | |
385 return transport->SetLocalTransportDescription(tdesc, action, err); | |
386 } | |
387 | |
388 bool TransportController::SetRemoteTransportDescription_w( | |
389 const std::string& transport_name, | |
390 const TransportDescription& tdesc, | |
391 ContentAction action, | |
392 std::string* err) { | |
393 RTC_DCHECK(worker_thread()->IsCurrent()); | |
394 | |
395 Transport* transport = GetTransport_w(transport_name); | |
396 if (!transport) { | |
397 // If we didn't find a transport, that's not an error; | |
398 // it could have been deleted as a result of bundling. | |
399 // TODO(deadbeef): Make callers smarter so they won't attempt to set a | |
400 // description on a deleted transport. | |
401 return true; | |
402 } | |
403 | |
404 return transport->SetRemoteTransportDescription(tdesc, action, err); | |
405 } | |
406 | |
407 void TransportController::MaybeStartGathering_w() { | |
408 for (const auto& kv : transports_) { | |
409 kv.second->MaybeStartGathering(); | |
410 } | |
411 } | |
412 | |
413 bool TransportController::AddRemoteCandidates_w( | |
414 const std::string& transport_name, | |
415 const Candidates& candidates, | |
416 std::string* err) { | |
417 RTC_DCHECK(worker_thread()->IsCurrent()); | |
418 | |
419 Transport* transport = GetTransport_w(transport_name); | |
420 if (!transport) { | |
421 // If we didn't find a transport, that's not an error; | |
422 // it could have been deleted as a result of bundling. | |
423 return true; | |
424 } | |
425 | |
426 return transport->AddRemoteCandidates(candidates, err); | |
427 } | |
428 | |
429 bool TransportController::ReadyForRemoteCandidates_w( | |
430 const std::string& transport_name) { | |
431 RTC_DCHECK(worker_thread()->IsCurrent()); | |
432 | |
433 Transport* transport = GetTransport_w(transport_name); | |
434 if (!transport) { | |
435 return false; | |
436 } | |
437 return transport->ready_for_remote_candidates(); | |
438 } | |
439 | |
440 bool TransportController::GetStats_w(const std::string& transport_name, | |
441 TransportStats* stats) { | |
442 RTC_DCHECK(worker_thread()->IsCurrent()); | |
443 | |
444 Transport* transport = GetTransport_w(transport_name); | |
445 if (!transport) { | |
446 return false; | |
447 } | |
448 return transport->GetStats(stats); | |
449 } | |
450 | |
451 void TransportController::OnTransportConnecting_w(Transport* transport) { | |
452 RTC_DCHECK(worker_thread_->IsCurrent()); | |
453 UpdateAggregateStates_w(); | |
454 } | |
455 | |
456 void TransportController::OnTransportWritableState_w(Transport* transport) { | |
457 RTC_DCHECK(worker_thread_->IsCurrent()); | |
458 UpdateAggregateStates_w(); | |
459 } | |
460 | |
461 void TransportController::OnTransportReceivingState_w(Transport* transport) { | |
462 RTC_DCHECK(worker_thread_->IsCurrent()); | |
463 UpdateAggregateStates_w(); | |
464 } | |
465 | |
466 void TransportController::OnTransportCompleted_w(Transport* transport) { | |
467 RTC_DCHECK(worker_thread_->IsCurrent()); | |
468 UpdateAggregateStates_w(); | |
469 } | |
470 | |
471 void TransportController::OnTransportFailed_w(Transport* transport) { | |
472 RTC_DCHECK(worker_thread_->IsCurrent()); | |
473 UpdateAggregateStates_w(); | |
474 } | |
475 | |
476 void TransportController::OnTransportGatheringState_w(Transport* transport) { | |
477 RTC_DCHECK(worker_thread_->IsCurrent()); | |
478 UpdateAggregateStates_w(); | |
479 } | |
480 | |
481 void TransportController::OnTransportCandidatesGathered_w( | |
482 Transport* transport, | |
483 const std::vector<Candidate>& candidates) { | |
484 RTC_DCHECK(worker_thread_->IsCurrent()); | |
485 CandidatesData* data = new CandidatesData(transport->name(), candidates); | |
486 signaling_thread_->Post(this, MSG_CANDIDATESGATHERED, data); | |
487 } | |
488 | |
489 void TransportController::OnTransportRoleConflict_w() { | |
490 RTC_DCHECK(worker_thread_->IsCurrent()); | |
491 | |
492 if (ice_role_switch_) { | |
493 LOG(LS_WARNING) << "Repeat of role conflict signal from Transport."; | |
494 return; | |
495 } | |
496 | |
497 ice_role_switch_ = true; | |
498 IceRole reversed_role = (ice_role_ == ICEROLE_CONTROLLING) | |
499 ? ICEROLE_CONTROLLED | |
500 : ICEROLE_CONTROLLING; | |
501 for (const auto& kv : transports_) { | |
502 kv.second->SetIceRole(reversed_role); | |
503 } | |
504 } | |
505 | |
506 void TransportController::UpdateAggregateStates_w() { | |
507 RTC_DCHECK(worker_thread_->IsCurrent()); | |
508 | |
509 IceConnectionState new_connection_state = kIceConnectionConnecting; | |
510 IceGatheringState new_gathering_state = kIceGatheringNew; | |
511 bool any_receiving = false; | |
512 bool any_failed = false; | |
513 bool all_connected = HasChannels_w(); | |
514 bool all_completed = HasChannels_w(); | |
515 bool any_gathering = false; | |
516 bool all_done_gathering = HasChannels_w(); | |
517 for (const auto& kv : transports_) { | |
518 // Ignore transports without channels since they're about to be deleted, | |
519 // and their state is meaningless. | |
520 if (!kv.second->HasChannels()) { | |
521 continue; | |
522 } | |
523 any_receiving = any_receiving || kv.second->any_channel_receiving(); | |
524 any_failed = any_failed || kv.second->AnyChannelFailed(); | |
525 all_connected = all_connected && kv.second->all_channels_writable(); | |
526 all_completed = all_completed && kv.second->AllChannelsCompleted(); | |
527 any_gathering = | |
528 any_gathering || kv.second->gathering_state() != kIceGatheringNew; | |
529 all_done_gathering = all_done_gathering && | |
530 kv.second->gathering_state() == kIceGatheringComplete; | |
531 } | |
532 | |
533 if (any_failed) { | |
534 new_connection_state = kIceConnectionFailed; | |
535 } else if (all_completed) { | |
536 new_connection_state = kIceConnectionCompleted; | |
537 } else if (all_connected) { | |
538 new_connection_state = kIceConnectionConnected; | |
539 } | |
540 if (connection_state_ != new_connection_state) { | |
541 connection_state_ = new_connection_state; | |
542 signaling_thread_->Post( | |
543 this, MSG_ICECONNECTIONSTATE, | |
544 new rtc::TypedMessageData<IceConnectionState>(new_connection_state)); | |
545 } | |
546 | |
547 if (receiving_ != any_receiving) { | |
548 receiving_ = any_receiving; | |
549 signaling_thread_->Post(this, MSG_RECEIVING, | |
550 new rtc::TypedMessageData<bool>(any_receiving)); | |
551 } | |
552 | |
553 if (all_done_gathering) { | |
554 new_gathering_state = kIceGatheringComplete; | |
555 } else if (any_gathering) { | |
556 new_gathering_state = kIceGatheringGathering; | |
557 } | |
558 if (gathering_state_ != new_gathering_state) { | |
559 gathering_state_ = new_gathering_state; | |
560 signaling_thread_->Post( | |
561 this, MSG_ICEGATHERINGSTATE, | |
562 new rtc::TypedMessageData<IceGatheringState>(new_gathering_state)); | |
563 } | |
564 } | |
565 | |
566 bool TransportController::HasChannels_w() { | |
567 for (const auto& kv : transports_) { | |
568 if (kv.second->HasChannels()) { | |
569 return true; | |
570 } | |
571 } | |
572 return false; | |
573 } | |
574 | |
575 } // namespace cricket | |
OLD | NEW |