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