OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright 2004 The WebRTC Project Authors. All rights reserved. | 2 * Copyright 2004 The WebRTC Project Authors. All rights reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 #include "webrtc/p2p/base/session.h" | 11 #include "webrtc/p2p/base/session.h" |
12 | 12 |
13 #include "webrtc/p2p/base/dtlstransport.h" | |
14 #include "webrtc/p2p/base/p2ptransport.h" | |
15 #include "webrtc/p2p/base/transport.h" | |
16 #include "webrtc/p2p/base/transportchannelproxy.h" | |
17 #include "webrtc/p2p/base/transportinfo.h" | |
18 #include "webrtc/base/bind.h" | 13 #include "webrtc/base/bind.h" |
19 #include "webrtc/base/common.h" | 14 #include "webrtc/base/common.h" |
20 #include "webrtc/base/helpers.h" | 15 #include "webrtc/base/helpers.h" |
21 #include "webrtc/base/logging.h" | 16 #include "webrtc/base/logging.h" |
22 #include "webrtc/base/scoped_ptr.h" | 17 #include "webrtc/base/scoped_ptr.h" |
23 #include "webrtc/base/stringencode.h" | 18 #include "webrtc/base/stringencode.h" |
24 #include "webrtc/base/sslstreamadapter.h" | 19 #include "webrtc/base/sslstreamadapter.h" |
25 | 20 #include "webrtc/p2p/base/transport.h" |
21 #include "webrtc/p2p/base/transportchannelproxy.h" | |
22 #include "webrtc/p2p/base/transportinfo.h" | |
23 #include "webrtc/p2p/base/transportcontroller.h" | |
26 #include "webrtc/p2p/base/constants.h" | 24 #include "webrtc/p2p/base/constants.h" |
27 | 25 |
28 namespace cricket { | 26 namespace cricket { |
29 | 27 |
30 using rtc::Bind; | 28 using rtc::Bind; |
31 | 29 |
32 TransportProxy::~TransportProxy() { | |
33 for (ChannelMap::iterator iter = channels_.begin(); | |
34 iter != channels_.end(); ++iter) { | |
35 iter->second->SignalDestroyed(iter->second); | |
36 delete iter->second; | |
37 } | |
38 } | |
39 | |
40 TransportChannel* TransportProxy::GetChannel(int component) { | |
41 ASSERT(rtc::Thread::Current() == worker_thread_); | |
42 return GetChannelProxy(component); | |
43 } | |
44 | |
45 TransportChannel* TransportProxy::CreateChannel(int component) { | |
46 ASSERT(rtc::Thread::Current() == worker_thread_); | |
47 ASSERT(GetChannel(component) == NULL); | |
48 ASSERT(!transport_->get()->HasChannel(component)); | |
49 | |
50 // We always create a proxy in case we need to change out the transport later. | |
51 TransportChannelProxy* channel_proxy = | |
52 new TransportChannelProxy(content_name(), component); | |
53 channels_[component] = channel_proxy; | |
54 | |
55 // If we're already negotiated, create an impl and hook it up to the proxy | |
56 // channel. If we're connecting, create an impl but don't hook it up yet. | |
57 if (negotiated_) { | |
58 CreateChannelImpl_w(component); | |
59 SetChannelImplFromTransport_w(channel_proxy, component); | |
60 } else if (connecting_) { | |
61 CreateChannelImpl_w(component); | |
62 } | |
63 return channel_proxy; | |
64 } | |
65 | |
66 bool TransportProxy::HasChannel(int component) { | |
67 return transport_->get()->HasChannel(component); | |
68 } | |
69 | |
70 void TransportProxy::DestroyChannel(int component) { | |
71 ASSERT(rtc::Thread::Current() == worker_thread_); | |
72 TransportChannelProxy* channel_proxy = GetChannelProxy(component); | |
73 if (channel_proxy) { | |
74 // If the state of TransportProxy is not NEGOTIATED then | |
75 // TransportChannelProxy and its impl are not connected. Both must | |
76 // be connected before deletion. | |
77 // | |
78 // However, if we haven't entered the connecting state then there | |
79 // is no implementation to hook up. | |
80 if (connecting_ && !negotiated_) { | |
81 SetChannelImplFromTransport_w(channel_proxy, component); | |
82 } | |
83 | |
84 channels_.erase(component); | |
85 channel_proxy->SignalDestroyed(channel_proxy); | |
86 delete channel_proxy; | |
87 } | |
88 } | |
89 | |
90 void TransportProxy::ConnectChannels() { | |
91 if (!connecting_) { | |
92 if (!negotiated_) { | |
93 for (auto& iter : channels_) { | |
94 CreateChannelImpl(iter.first); | |
95 } | |
96 } | |
97 connecting_ = true; | |
98 } | |
99 // TODO(juberti): Right now Transport::ConnectChannels doesn't work if we | |
100 // don't have any channels yet, so we need to allow this method to be called | |
101 // multiple times. Once we fix Transport, we can move this call inside the | |
102 // if (!connecting_) block. | |
103 transport_->get()->ConnectChannels(); | |
104 } | |
105 | |
106 void TransportProxy::CompleteNegotiation() { | |
107 if (!negotiated_) { | |
108 // Negotiating assumes connecting_ has happened and | |
109 // implementations exist. If not we need to create the | |
110 // implementations. | |
111 for (auto& iter : channels_) { | |
112 if (!connecting_) { | |
113 CreateChannelImpl(iter.first); | |
114 } | |
115 SetChannelImplFromTransport(iter.second, iter.first); | |
116 } | |
117 negotiated_ = true; | |
118 } | |
119 } | |
120 | |
121 void TransportProxy::AddSentCandidates(const Candidates& candidates) { | |
122 for (Candidates::const_iterator cand = candidates.begin(); | |
123 cand != candidates.end(); ++cand) { | |
124 sent_candidates_.push_back(*cand); | |
125 } | |
126 } | |
127 | |
128 void TransportProxy::AddUnsentCandidates(const Candidates& candidates) { | |
129 for (Candidates::const_iterator cand = candidates.begin(); | |
130 cand != candidates.end(); ++cand) { | |
131 unsent_candidates_.push_back(*cand); | |
132 } | |
133 } | |
134 | |
135 TransportChannelProxy* TransportProxy::GetChannelProxy(int component) const { | |
136 ChannelMap::const_iterator iter = channels_.find(component); | |
137 return (iter != channels_.end()) ? iter->second : NULL; | |
138 } | |
139 | |
140 void TransportProxy::CreateChannelImpl(int component) { | |
141 worker_thread_->Invoke<void>(Bind( | |
142 &TransportProxy::CreateChannelImpl_w, this, component)); | |
143 } | |
144 | |
145 void TransportProxy::CreateChannelImpl_w(int component) { | |
146 ASSERT(rtc::Thread::Current() == worker_thread_); | |
147 transport_->get()->CreateChannel(component); | |
148 } | |
149 | |
150 void TransportProxy::SetChannelImplFromTransport(TransportChannelProxy* proxy, | |
151 int component) { | |
152 worker_thread_->Invoke<void>(Bind( | |
153 &TransportProxy::SetChannelImplFromTransport_w, this, proxy, component)); | |
154 } | |
155 | |
156 void TransportProxy::SetChannelImplFromTransport_w(TransportChannelProxy* proxy, | |
157 int component) { | |
158 ASSERT(rtc::Thread::Current() == worker_thread_); | |
159 TransportChannelImpl* impl = transport_->get()->GetChannel(component); | |
160 ASSERT(impl != NULL); | |
161 ReplaceChannelImpl_w(proxy, impl); | |
162 } | |
163 | |
164 void TransportProxy::ReplaceChannelImpl(TransportChannelProxy* proxy, | |
165 TransportChannelImpl* impl) { | |
166 worker_thread_->Invoke<void>(Bind( | |
167 &TransportProxy::ReplaceChannelImpl_w, this, proxy, impl)); | |
168 } | |
169 | |
170 void TransportProxy::ReplaceChannelImpl_w(TransportChannelProxy* proxy, | |
171 TransportChannelImpl* impl) { | |
172 ASSERT(rtc::Thread::Current() == worker_thread_); | |
173 ASSERT(proxy != NULL); | |
174 proxy->SetImplementation(impl); | |
175 } | |
176 | |
177 // This function muxes |this| onto |target| by repointing |this| at | |
178 // |target|'s transport and setting our TransportChannelProxies | |
179 // to point to |target|'s underlying implementations. | |
180 bool TransportProxy::SetupMux(TransportProxy* target) { | |
181 // Bail out if there's nothing to do. | |
182 if (transport_ == target->transport_) { | |
183 return true; | |
184 } | |
185 | |
186 // Run through all channels and remove any non-rtp transport channels before | |
187 // setting target transport channels. | |
188 for (ChannelMap::const_iterator iter = channels_.begin(); | |
189 iter != channels_.end(); ++iter) { | |
190 if (!target->transport_->get()->HasChannel(iter->first)) { | |
191 // Remove if channel doesn't exist in |transport_|. | |
192 ReplaceChannelImpl(iter->second, NULL); | |
193 } else { | |
194 // Replace the impl for all the TransportProxyChannels with the channels | |
195 // from |target|'s transport. Fail if there's not an exact match. | |
196 ReplaceChannelImpl( | |
197 iter->second, target->transport_->get()->CreateChannel(iter->first)); | |
198 } | |
199 } | |
200 | |
201 // Now replace our transport. Must happen afterwards because | |
202 // it deletes all impls as a side effect. | |
203 transport_ = target->transport_; | |
204 transport_->get()->SignalCandidatesReady.connect( | |
205 this, &TransportProxy::OnTransportCandidatesReady); | |
206 set_candidates_allocated(target->candidates_allocated()); | |
207 return true; | |
208 } | |
209 | |
210 void TransportProxy::SetIceRole(IceRole role) { | |
211 transport_->get()->SetIceRole(role); | |
212 } | |
213 | |
214 bool TransportProxy::SetLocalTransportDescription( | |
215 const TransportDescription& description, | |
216 ContentAction action, | |
217 std::string* error_desc) { | |
218 // If this is an answer, finalize the negotiation. | |
219 if (action == CA_ANSWER) { | |
220 CompleteNegotiation(); | |
221 } | |
222 bool result = transport_->get()->SetLocalTransportDescription(description, | |
223 action, | |
224 error_desc); | |
225 if (result) | |
226 local_description_set_ = true; | |
227 return result; | |
228 } | |
229 | |
230 bool TransportProxy::SetRemoteTransportDescription( | |
231 const TransportDescription& description, | |
232 ContentAction action, | |
233 std::string* error_desc) { | |
234 // If this is an answer, finalize the negotiation. | |
235 if (action == CA_ANSWER) { | |
236 CompleteNegotiation(); | |
237 } | |
238 bool result = transport_->get()->SetRemoteTransportDescription(description, | |
239 action, | |
240 error_desc); | |
241 if (result) | |
242 remote_description_set_ = true; | |
243 return result; | |
244 } | |
245 | |
246 void TransportProxy::OnSignalingReady() { | |
247 // If we're starting a new allocation sequence, reset our state. | |
248 set_candidates_allocated(false); | |
249 transport_->get()->OnSignalingReady(); | |
250 } | |
251 | |
252 bool TransportProxy::OnRemoteCandidates(const Candidates& candidates, | |
253 std::string* error) { | |
254 // Ensure the transport is negotiated before handling candidates. | |
255 // TODO(juberti): Remove this once everybody calls SetLocalTD. | |
256 CompleteNegotiation(); | |
257 | |
258 // Ignore candidates for if the proxy content_name doesn't match the content | |
259 // name of the actual transport. This stops video candidates from being sent | |
260 // down to the audio transport when BUNDLE is enabled. | |
261 if (content_name_ != transport_->get()->content_name()) { | |
262 return true; | |
263 } | |
264 | |
265 // Verify each candidate before passing down to transport layer. | |
266 for (Candidates::const_iterator cand = candidates.begin(); | |
267 cand != candidates.end(); ++cand) { | |
268 if (!transport_->get()->VerifyCandidate(*cand, error)) | |
269 return false; | |
270 if (!HasChannel(cand->component())) { | |
271 *error = "Candidate has unknown component: " + cand->ToString() + | |
272 " for content: " + content_name_; | |
273 return false; | |
274 } | |
275 } | |
276 transport_->get()->OnRemoteCandidates(candidates); | |
277 return true; | |
278 } | |
279 | |
280 void TransportProxy::SetCertificate( | |
281 const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) { | |
282 transport_->get()->SetCertificate(certificate); | |
283 } | |
284 | |
285 std::string BaseSession::StateToString(State state) { | 30 std::string BaseSession::StateToString(State state) { |
286 switch (state) { | 31 switch (state) { |
287 case STATE_INIT: | 32 case STATE_INIT: |
288 return "STATE_INIT"; | 33 return "STATE_INIT"; |
289 case STATE_SENTINITIATE: | 34 case STATE_SENTINITIATE: |
290 return "STATE_SENTINITIATE"; | 35 return "STATE_SENTINITIATE"; |
291 case STATE_RECEIVEDINITIATE: | 36 case STATE_RECEIVEDINITIATE: |
292 return "STATE_RECEIVEDINITIATE"; | 37 return "STATE_RECEIVEDINITIATE"; |
293 case STATE_SENTPRACCEPT: | 38 case STATE_SENTPRACCEPT: |
294 return "STATE_SENTPRACCEPT"; | 39 return "STATE_SENTPRACCEPT"; |
(...skipping 24 matching lines...) Expand all Loading... | |
319 default: | 64 default: |
320 break; | 65 break; |
321 } | 66 } |
322 return "STATE_" + rtc::ToString(state); | 67 return "STATE_" + rtc::ToString(state); |
323 } | 68 } |
324 | 69 |
325 BaseSession::BaseSession(rtc::Thread* signaling_thread, | 70 BaseSession::BaseSession(rtc::Thread* signaling_thread, |
326 rtc::Thread* worker_thread, | 71 rtc::Thread* worker_thread, |
327 PortAllocator* port_allocator, | 72 PortAllocator* port_allocator, |
328 const std::string& sid, | 73 const std::string& sid, |
329 const std::string& content_type, | |
330 bool initiator) | 74 bool initiator) |
331 : state_(STATE_INIT), | 75 : state_(STATE_INIT), |
332 error_(ERROR_NONE), | 76 error_(ERROR_NONE), |
333 signaling_thread_(signaling_thread), | 77 signaling_thread_(signaling_thread), |
334 worker_thread_(worker_thread), | 78 worker_thread_(worker_thread), |
pthatcher1
2015/08/31 22:01:36
This is never used. I think we can remove it, alo
Taylor Brandstetter
2015/09/01 23:53:30
Done.
| |
335 port_allocator_(port_allocator), | 79 port_allocator_(port_allocator), |
336 sid_(sid), | 80 sid_(sid), |
337 content_type_(content_type), | 81 transport_controller_(new TransportController(signaling_thread, |
338 initiator_(initiator), | 82 worker_thread, |
339 ssl_max_version_(rtc::SSL_PROTOCOL_DTLS_10), | 83 port_allocator)) { |
340 ice_tiebreaker_(rtc::CreateRandomId64()), | |
341 role_switch_(false), | |
342 ice_receiving_timeout_(-1) { | |
343 ASSERT(signaling_thread->IsCurrent()); | 84 ASSERT(signaling_thread->IsCurrent()); |
85 set_initiator(initiator); | |
344 } | 86 } |
345 | 87 |
346 BaseSession::~BaseSession() { | 88 BaseSession::~BaseSession() { |
347 ASSERT(signaling_thread()->IsCurrent()); | 89 ASSERT(signaling_thread()->IsCurrent()); |
348 | 90 |
349 ASSERT(state_ != STATE_DEINIT); | 91 ASSERT(state_ != STATE_DEINIT); |
350 LogState(state_, STATE_DEINIT); | 92 LogState(state_, STATE_DEINIT); |
351 state_ = STATE_DEINIT; | 93 state_ = STATE_DEINIT; |
352 SignalState(this, state_); | 94 SignalState(this, state_); |
353 | |
354 for (TransportMap::iterator iter = transports_.begin(); | |
355 iter != transports_.end(); ++iter) { | |
356 delete iter->second; | |
357 } | |
358 } | 95 } |
359 | 96 |
360 const SessionDescription* BaseSession::local_description() const { | 97 const SessionDescription* BaseSession::local_description() const { |
361 // TODO(tommi): Assert on thread correctness. | 98 // TODO(tommi): Assert on thread correctness. |
362 return local_description_.get(); | 99 return local_description_.get(); |
363 } | 100 } |
364 | 101 |
365 const SessionDescription* BaseSession::remote_description() const { | 102 const SessionDescription* BaseSession::remote_description() const { |
366 // TODO(tommi): Assert on thread correctness. | 103 // TODO(tommi): Assert on thread correctness. |
367 return remote_description_.get(); | 104 return remote_description_.get(); |
368 } | 105 } |
369 | 106 |
370 SessionDescription* BaseSession::remote_description() { | 107 SessionDescription* BaseSession::remote_description() { |
371 // TODO(tommi): Assert on thread correctness. | 108 // TODO(tommi): Assert on thread correctness. |
372 return remote_description_.get(); | 109 return remote_description_.get(); |
373 } | 110 } |
374 | 111 |
375 void BaseSession::set_local_description(const SessionDescription* sdesc) { | 112 void BaseSession::set_local_description(const SessionDescription* sdesc) { |
376 // TODO(tommi): Assert on thread correctness. | 113 // TODO(tommi): Assert on thread correctness. |
377 if (sdesc != local_description_.get()) | 114 if (sdesc != local_description_.get()) |
378 local_description_.reset(sdesc); | 115 local_description_.reset(sdesc); |
379 } | 116 } |
380 | 117 |
381 void BaseSession::set_remote_description(SessionDescription* sdesc) { | 118 void BaseSession::set_remote_description(SessionDescription* sdesc) { |
382 // TODO(tommi): Assert on thread correctness. | 119 // TODO(tommi): Assert on thread correctness. |
383 if (sdesc != remote_description_) | 120 if (sdesc != remote_description_) |
384 remote_description_.reset(sdesc); | 121 remote_description_.reset(sdesc); |
385 } | 122 } |
386 | 123 |
124 void BaseSession::set_initiator(bool initiator) { | |
125 initiator_ = initiator; | |
126 | |
127 IceRole ice_role = initiator ? ICEROLE_CONTROLLING : ICEROLE_CONTROLLED; | |
128 transport_controller_->SetIceRole(ice_role); | |
129 } | |
130 | |
387 const SessionDescription* BaseSession::initiator_description() const { | 131 const SessionDescription* BaseSession::initiator_description() const { |
388 // TODO(tommi): Assert on thread correctness. | 132 // TODO(tommi): Assert on thread correctness. |
389 return initiator_ ? local_description_.get() : remote_description_.get(); | 133 return initiator_ ? local_description_.get() : remote_description_.get(); |
390 } | 134 } |
391 | 135 |
392 bool BaseSession::SetCertificate( | |
393 const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) { | |
394 if (certificate_) | |
395 return false; | |
396 if (!certificate) | |
397 return false; | |
398 certificate_ = certificate; | |
399 for (TransportMap::iterator iter = transports_.begin(); | |
400 iter != transports_.end(); ++iter) { | |
401 iter->second->SetCertificate(certificate_); | |
402 } | |
403 return true; | |
404 } | |
405 | |
406 bool BaseSession::SetSslMaxProtocolVersion(rtc::SSLProtocolVersion version) { | |
407 if (state_ != STATE_INIT) { | |
408 return false; | |
409 } | |
410 | |
411 ssl_max_version_ = version; | |
412 return true; | |
413 } | |
414 | |
415 bool BaseSession::PushdownTransportDescription(ContentSource source, | 136 bool BaseSession::PushdownTransportDescription(ContentSource source, |
416 ContentAction action, | 137 ContentAction action, |
417 std::string* error_desc) { | 138 std::string* error_desc) { |
139 ASSERT(signaling_thread()->IsCurrent()); | |
140 | |
418 if (source == CS_LOCAL) { | 141 if (source == CS_LOCAL) { |
419 return PushdownLocalTransportDescription(local_description(), | 142 return PushdownLocalTransportDescription(local_description(), |
420 action, | 143 action, |
421 error_desc); | 144 error_desc); |
422 } | 145 } |
423 return PushdownRemoteTransportDescription(remote_description(), | 146 return PushdownRemoteTransportDescription(remote_description(), |
424 action, | 147 action, |
425 error_desc); | 148 error_desc); |
426 } | 149 } |
427 | 150 |
428 bool BaseSession::PushdownLocalTransportDescription( | 151 bool BaseSession::PushdownLocalTransportDescription( |
429 const SessionDescription* sdesc, | 152 const SessionDescription* sdesc, |
430 ContentAction action, | 153 ContentAction action, |
431 std::string* error_desc) { | 154 std::string* err) { |
432 // Update the Transports with the right information, and trigger them to | 155 ASSERT(signaling_thread()->IsCurrent()); |
433 // start connecting. | |
434 for (TransportMap::iterator iter = transports_.begin(); | |
435 iter != transports_.end(); ++iter) { | |
436 // If no transport info was in this session description, ret == false | |
437 // and we just skip this one. | |
438 TransportDescription tdesc; | |
439 bool ret = GetTransportDescription( | |
440 sdesc, iter->second->content_name(), &tdesc); | |
441 if (ret) { | |
442 if (!iter->second->SetLocalTransportDescription(tdesc, action, | |
443 error_desc)) { | |
444 return false; | |
445 } | |
446 | 156 |
447 iter->second->ConnectChannels(); | 157 if (!sdesc) { |
158 return false; | |
159 } | |
160 | |
161 for (const TransportInfo& tinfo : sdesc->transport_infos()) { | |
162 if (!transport_controller_->SetLocalTransportDescription( | |
163 tinfo.content_name, tinfo.description, action, err)) { | |
164 return false; | |
448 } | 165 } |
449 } | 166 } |
450 | 167 |
451 return true; | 168 return true; |
452 } | 169 } |
453 | 170 |
454 bool BaseSession::PushdownRemoteTransportDescription( | 171 bool BaseSession::PushdownRemoteTransportDescription( |
455 const SessionDescription* sdesc, | 172 const SessionDescription* sdesc, |
456 ContentAction action, | 173 ContentAction action, |
457 std::string* error_desc) { | 174 std::string* err) { |
458 // Update the Transports with the right information. | 175 ASSERT(signaling_thread()->IsCurrent()); |
459 for (TransportMap::iterator iter = transports_.begin(); | |
460 iter != transports_.end(); ++iter) { | |
461 TransportDescription tdesc; | |
462 | 176 |
463 // If no transport info was in this session description, ret == false | 177 if (!sdesc) { |
464 // and we just skip this one. | 178 return false; |
465 bool ret = GetTransportDescription( | 179 } |
466 sdesc, iter->second->content_name(), &tdesc); | 180 |
467 if (ret) { | 181 for (const TransportInfo& tinfo : sdesc->transport_infos()) { |
468 if (!iter->second->SetRemoteTransportDescription(tdesc, action, | 182 if (!transport_controller_->SetRemoteTransportDescription( |
469 error_desc)) { | 183 tinfo.content_name, tinfo.description, action, err)) { |
470 return false; | 184 return false; |
471 } | |
472 } | 185 } |
473 } | 186 } |
474 | 187 |
475 return true; | 188 return true; |
476 } | 189 } |
477 | 190 |
478 void BaseSession::SetIceConnectionReceivingTimeout(int timeout_ms) { | |
479 ice_receiving_timeout_ = timeout_ms; | |
480 for (const auto& kv : transport_proxies()) { | |
481 Transport* transport = kv.second->impl(); | |
482 if (transport) { | |
483 transport->SetChannelReceivingTimeout(timeout_ms); | |
484 } | |
485 } | |
486 } | |
487 | |
488 TransportChannel* BaseSession::CreateChannel(const std::string& content_name, | |
489 int component) { | |
490 // We create the proxy "on demand" here because we need to support | |
491 // creating channels at any time, even before we send or receive | |
492 // initiate messages, which is before we create the transports. | |
493 TransportProxy* transproxy = GetOrCreateTransportProxy(content_name); | |
494 return transproxy->CreateChannel(component); | |
495 } | |
496 | |
497 TransportChannel* BaseSession::GetChannel(const std::string& content_name, | |
498 int component) { | |
499 TransportProxy* transproxy = GetTransportProxy(content_name); | |
500 if (transproxy == NULL) | |
501 return NULL; | |
502 | |
503 return transproxy->GetChannel(component); | |
504 } | |
505 | |
506 void BaseSession::DestroyChannel(const std::string& content_name, | |
507 int component) { | |
508 TransportProxy* transproxy = GetTransportProxy(content_name); | |
509 ASSERT(transproxy != NULL); | |
510 transproxy->DestroyChannel(component); | |
511 } | |
512 | |
513 TransportProxy* BaseSession::GetOrCreateTransportProxy( | |
514 const std::string& content_name) { | |
515 TransportProxy* transproxy = GetTransportProxy(content_name); | |
516 if (transproxy) | |
517 return transproxy; | |
518 | |
519 Transport* transport = CreateTransport(content_name); | |
520 transport->SetIceRole(initiator_ ? ICEROLE_CONTROLLING : ICEROLE_CONTROLLED); | |
521 transport->SetIceTiebreaker(ice_tiebreaker_); | |
522 transport->SetSslMaxProtocolVersion(ssl_max_version_); | |
523 // TODO: Connect all the Transport signals to TransportProxy | |
524 // then to the BaseSession. | |
525 transport->SignalConnecting.connect( | |
526 this, &BaseSession::OnTransportConnecting); | |
527 transport->SignalWritableState.connect( | |
528 this, &BaseSession::OnTransportWritable); | |
529 transport->SignalReceivingState.connect( | |
530 this, &BaseSession::OnTransportReceiving); | |
531 transport->SignalRequestSignaling.connect( | |
532 this, &BaseSession::OnTransportRequestSignaling); | |
533 transport->SignalRouteChange.connect( | |
534 this, &BaseSession::OnTransportRouteChange); | |
535 transport->SignalCandidatesAllocationDone.connect( | |
536 this, &BaseSession::OnTransportCandidatesAllocationDone); | |
537 transport->SignalRoleConflict.connect( | |
538 this, &BaseSession::OnRoleConflict); | |
539 transport->SignalCompleted.connect( | |
540 this, &BaseSession::OnTransportCompleted); | |
541 transport->SignalFailed.connect( | |
542 this, &BaseSession::OnTransportFailed); | |
543 | |
544 transproxy = new TransportProxy(worker_thread_, sid_, content_name, | |
545 new TransportWrapper(transport)); | |
546 transproxy->SignalCandidatesReady.connect( | |
547 this, &BaseSession::OnTransportProxyCandidatesReady); | |
548 if (certificate_) | |
549 transproxy->SetCertificate(certificate_); | |
550 transports_[content_name] = transproxy; | |
551 | |
552 return transproxy; | |
553 } | |
554 | |
555 Transport* BaseSession::GetTransport(const std::string& content_name) { | |
556 TransportProxy* transproxy = GetTransportProxy(content_name); | |
557 if (transproxy == NULL) | |
558 return NULL; | |
559 return transproxy->impl(); | |
560 } | |
561 | |
562 TransportProxy* BaseSession::GetTransportProxy( | |
563 const std::string& content_name) { | |
564 TransportMap::iterator iter = transports_.find(content_name); | |
565 return (iter != transports_.end()) ? iter->second : NULL; | |
566 } | |
567 | |
568 void BaseSession::DestroyTransportProxy( | |
569 const std::string& content_name) { | |
570 TransportMap::iterator iter = transports_.find(content_name); | |
571 if (iter != transports_.end()) { | |
572 delete iter->second; | |
573 transports_.erase(content_name); | |
574 } | |
575 } | |
576 | |
577 Transport* BaseSession::CreateTransport(const std::string& content_name) { | |
578 Transport* transport = new DtlsTransport<P2PTransport>( | |
579 signaling_thread(), worker_thread(), content_name, port_allocator(), | |
580 certificate_); | |
581 transport->SetChannelReceivingTimeout(ice_receiving_timeout_); | |
582 return transport; | |
583 } | |
584 | |
585 void BaseSession::SetState(State state) { | 191 void BaseSession::SetState(State state) { |
586 ASSERT(signaling_thread_->IsCurrent()); | 192 ASSERT(signaling_thread_->IsCurrent()); |
587 if (state != state_) { | 193 if (state != state_) { |
588 LogState(state_, state); | 194 LogState(state_, state); |
589 state_ = state; | 195 state_ = state; |
590 SignalState(this, state_); | 196 SignalState(this, state_); |
591 signaling_thread_->Post(this, MSG_STATE); | 197 signaling_thread_->Post(this, MSG_STATE); |
592 } | 198 } |
593 } | 199 } |
594 | 200 |
595 void BaseSession::SetError(Error error, const std::string& error_desc) { | 201 void BaseSession::SetError(Error error, const std::string& error_desc) { |
596 ASSERT(signaling_thread_->IsCurrent()); | 202 ASSERT(signaling_thread_->IsCurrent()); |
597 if (error != error_) { | 203 if (error != error_) { |
598 error_ = error; | 204 error_ = error; |
599 error_desc_ = error_desc; | 205 error_desc_ = error_desc; |
600 SignalError(this, error); | 206 SignalError(this, error); |
601 } | 207 } |
602 } | 208 } |
603 | 209 |
604 void BaseSession::OnSignalingReady() { | 210 void BaseSession::SetIceConnectionReceivingTimeout(int timeout_ms) { |
605 ASSERT(signaling_thread()->IsCurrent()); | 211 transport_controller_->SetIceConnectionReceivingTimeout(timeout_ms); |
606 for (TransportMap::iterator iter = transports_.begin(); | |
607 iter != transports_.end(); ++iter) { | |
608 iter->second->OnSignalingReady(); | |
609 } | |
610 } | |
611 | |
612 // TODO(juberti): Since PushdownLocalTD now triggers the connection process to | |
613 // start, remove this method once everyone calls PushdownLocalTD. | |
614 void BaseSession::SpeculativelyConnectAllTransportChannels() { | |
615 // Put all transports into the connecting state. | |
616 for (TransportMap::iterator iter = transports_.begin(); | |
617 iter != transports_.end(); ++iter) { | |
618 iter->second->ConnectChannels(); | |
619 } | |
620 } | |
621 | |
622 bool BaseSession::OnRemoteCandidates(const std::string& content_name, | |
623 const Candidates& candidates, | |
624 std::string* error) { | |
625 // Give candidates to the appropriate transport, and tell that transport | |
626 // to start connecting, if it's not already doing so. | |
627 TransportProxy* transproxy = GetTransportProxy(content_name); | |
628 if (!transproxy) { | |
629 *error = "Unknown content name " + content_name; | |
630 return false; | |
631 } | |
632 if (!transproxy->OnRemoteCandidates(candidates, error)) { | |
633 return false; | |
634 } | |
635 // TODO(juberti): Remove this call once we can be sure that we always have | |
636 // a local transport description (which will trigger the connection). | |
637 transproxy->ConnectChannels(); | |
638 return true; | |
639 } | |
640 | |
641 bool BaseSession::MaybeEnableMuxingSupport() { | |
642 // We need both a local and remote description to decide if we should mux. | |
643 if ((state_ == STATE_SENTINITIATE || | |
644 state_ == STATE_RECEIVEDINITIATE) && | |
645 ((local_description_ == NULL) || | |
646 (remote_description_ == NULL))) { | |
647 return false; | |
648 } | |
649 | |
650 // In order to perform the multiplexing, we need all proxies to be in the | |
651 // negotiated state, i.e. to have implementations underneath. | |
652 // Ensure that this is the case, regardless of whether we are going to mux. | |
653 for (TransportMap::iterator iter = transports_.begin(); | |
654 iter != transports_.end(); ++iter) { | |
655 ASSERT(iter->second->negotiated()); | |
656 if (!iter->second->negotiated()) { | |
657 return false; | |
658 } | |
659 } | |
660 | |
661 // If both sides agree to BUNDLE, mux all the specified contents onto the | |
662 // transport belonging to the first content name in the BUNDLE group. | |
663 // If the contents are already muxed, this will be a no-op. | |
664 // TODO(juberti): Should this check that local and remote have configured | |
665 // BUNDLE the same way? | |
666 bool candidates_allocated = IsCandidateAllocationDone(); | |
667 const ContentGroup* local_bundle_group = | |
668 local_description_->GetGroupByName(GROUP_TYPE_BUNDLE); | |
669 const ContentGroup* remote_bundle_group = | |
670 remote_description_->GetGroupByName(GROUP_TYPE_BUNDLE); | |
671 if (local_bundle_group && remote_bundle_group) { | |
672 if (!BundleContentGroup(local_bundle_group)) { | |
673 LOG(LS_WARNING) << "Failed to set up BUNDLE"; | |
674 return false; | |
675 } | |
676 | |
677 // If we weren't done gathering before, we might be done now, as a result | |
678 // of enabling mux. | |
679 if (!candidates_allocated) { | |
680 MaybeCandidateAllocationDone(); | |
681 } | |
682 } else { | |
683 LOG(LS_INFO) << "BUNDLE group missing from remote or local description."; | |
684 } | |
685 return true; | |
686 } | |
687 | |
688 bool BaseSession::BundleContentGroup(const ContentGroup* bundle_group) { | |
689 const std::string* content_name = bundle_group->FirstContentName(); | |
690 if (!content_name) { | |
691 LOG(LS_INFO) << "No content names specified in BUNDLE group."; | |
692 return true; | |
693 } | |
694 | |
695 TransportProxy* selected_proxy = GetTransportProxy(*content_name); | |
696 if (!selected_proxy) { | |
697 LOG(LS_WARNING) << "No transport found for content \"" | |
698 << *content_name << "\"."; | |
699 return false; | |
700 } | |
701 | |
702 for (TransportMap::iterator iter = transports_.begin(); | |
703 iter != transports_.end(); ++iter) { | |
704 // If content is part of the mux group, then repoint its proxy at the | |
705 // transport object that we have chosen to mux onto. If the proxy | |
706 // is already pointing at the right object, it will be a no-op. | |
707 if (bundle_group->HasContentName(iter->first) && | |
708 !iter->second->SetupMux(selected_proxy)) { | |
709 LOG(LS_WARNING) << "Failed to bundle " << iter->first << " to " | |
710 << *content_name; | |
711 return false; | |
712 } | |
713 LOG(LS_INFO) << "Bundling " << iter->first << " to " << *content_name; | |
714 } | |
715 | |
716 return true; | |
717 } | |
718 | |
719 void BaseSession::OnTransportCandidatesAllocationDone(Transport* transport) { | |
720 // TODO(juberti): This is a clunky way of processing the done signal. Instead, | |
721 // TransportProxy should receive the done signal directly, set its allocated | |
722 // flag internally, and then reissue the done signal to Session. | |
723 // Overall we should make TransportProxy receive *all* the signals from | |
724 // Transport, since this removes the need to manually iterate over all | |
725 // the transports, as is needed to make sure signals are handled properly | |
726 // when BUNDLEing. | |
727 // TODO(juberti): Per b/7998978, devs and QA are hitting this assert in ways | |
728 // that make it prohibitively difficult to run dbg builds. Disabled for now. | |
729 //ASSERT(!IsCandidateAllocationDone()); | |
730 for (TransportMap::iterator iter = transports_.begin(); | |
731 iter != transports_.end(); ++iter) { | |
732 if (iter->second->impl() == transport) { | |
733 iter->second->set_candidates_allocated(true); | |
734 } | |
735 } | |
736 MaybeCandidateAllocationDone(); | |
737 } | |
738 | |
739 bool BaseSession::IsCandidateAllocationDone() const { | |
740 for (TransportMap::const_iterator iter = transports_.begin(); | |
741 iter != transports_.end(); ++iter) { | |
742 if (!iter->second->candidates_allocated()) { | |
743 LOG(LS_INFO) << "Candidate allocation not done for " | |
744 << iter->second->content_name(); | |
745 return false; | |
746 } | |
747 } | |
748 return true; | |
749 } | |
750 | |
751 void BaseSession::MaybeCandidateAllocationDone() { | |
752 if (IsCandidateAllocationDone()) { | |
753 LOG(LS_INFO) << "Candidate gathering is complete."; | |
754 OnCandidatesAllocationDone(); | |
755 } | |
756 } | |
757 | |
758 void BaseSession::OnRoleConflict() { | |
759 if (role_switch_) { | |
760 LOG(LS_WARNING) << "Repeat of role conflict signal from Transport."; | |
761 return; | |
762 } | |
763 | |
764 role_switch_ = true; | |
765 for (TransportMap::iterator iter = transports_.begin(); | |
766 iter != transports_.end(); ++iter) { | |
767 // Role will be reverse of initial role setting. | |
768 IceRole role = initiator_ ? ICEROLE_CONTROLLED : ICEROLE_CONTROLLING; | |
769 iter->second->SetIceRole(role); | |
770 } | |
771 } | 212 } |
772 | 213 |
773 void BaseSession::LogState(State old_state, State new_state) { | 214 void BaseSession::LogState(State old_state, State new_state) { |
774 LOG(LS_INFO) << "Session:" << id() | 215 LOG(LS_INFO) << "Session:" << id() |
775 << " Old state:" << StateToString(old_state) | 216 << " Old state:" << StateToString(old_state) |
776 << " New state:" << StateToString(new_state) | 217 << " New state:" << StateToString(new_state); |
777 << " Type:" << content_type(); | |
778 } | 218 } |
779 | 219 |
780 // static | 220 // static |
781 bool BaseSession::GetTransportDescription(const SessionDescription* description, | 221 bool BaseSession::GetTransportDescription(const SessionDescription* description, |
782 const std::string& content_name, | 222 const std::string& content_name, |
783 TransportDescription* tdesc) { | 223 TransportDescription* tdesc) { |
784 if (!description || !tdesc) { | 224 if (!description || !tdesc) { |
785 return false; | 225 return false; |
786 } | 226 } |
787 const TransportInfo* transport_info = | 227 const TransportInfo* transport_info = |
(...skipping 21 matching lines...) Expand all Loading... | |
809 | 249 |
810 default: | 250 default: |
811 // Explicitly ignoring some states here. | 251 // Explicitly ignoring some states here. |
812 break; | 252 break; |
813 } | 253 } |
814 break; | 254 break; |
815 } | 255 } |
816 } | 256 } |
817 | 257 |
818 } // namespace cricket | 258 } // namespace cricket |
OLD | NEW |