1 /*
2 * libjingle
3 * Copyright 2004, Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #include "talk/p2p/base/transport.h"
29
30 #include "talk/p2p/base/candidate.h"
31 #include "talk/p2p/base/constants.h"
32 #include "talk/p2p/base/parsing.h"
33 #include "talk/p2p/base/port.h"
34 #include "talk/p2p/base/sessionmanager.h"
35 #include "talk/p2p/base/transportchannelimpl.h"
36 #include "webrtc/libjingle/xmllite/xmlelement.h"
37 #include "talk/xmpp/constants.h"
38 #include "webrtc/base/bind.h"
39 #include "webrtc/base/common.h"
40 #include "webrtc/base/logging.h"
41
42 namespace cricket {
43
44 using rtc::Bind;
45
46 enum {
47 MSG_ONSIGNALINGREADY = 1,
48 MSG_ONREMOTECANDIDATE,
49 MSG_READSTATE,
50 MSG_WRITESTATE,
51 MSG_REQUESTSIGNALING,
52 MSG_CANDIDATEREADY,
53 MSG_ROUTECHANGE,
54 MSG_CONNECTING,
55 MSG_CANDIDATEALLOCATIONCOMPLETE,
56 MSG_ROLECONFLICT,
57 MSG_COMPLETED,
58 MSG_FAILED,
59 };
60
61 struct ChannelParams : public rtc::MessageData {
ChannelParamscricket::ChannelParams62 ChannelParams() : channel(NULL), candidate(NULL) {}
ChannelParamscricket::ChannelParams63 explicit ChannelParams(int component)
64 : component(component), channel(NULL), candidate(NULL) {}
ChannelParamscricket::ChannelParams65 explicit ChannelParams(Candidate* candidate)
66 : channel(NULL), candidate(candidate) {
67 }
68
~ChannelParamscricket::ChannelParams69 ~ChannelParams() {
70 delete candidate;
71 }
72
73 std::string name;
74 int component;
75 TransportChannelImpl* channel;
76 Candidate* candidate;
77 };
78
IceProtoToString(TransportProtocol proto)79 static std::string IceProtoToString(TransportProtocol proto) {
80 std::string proto_str;
81 switch (proto) {
82 case ICEPROTO_GOOGLE:
83 proto_str = "gice";
84 break;
85 case ICEPROTO_HYBRID:
86 proto_str = "hybrid";
87 break;
88 case ICEPROTO_RFC5245:
89 proto_str = "ice";
90 break;
91 default:
92 ASSERT(false);
93 break;
94 }
95 return proto_str;
96 }
97
VerifyIceParams(const TransportDescription & desc)98 static bool VerifyIceParams(const TransportDescription& desc) {
99 // For legacy protocols.
100 if (desc.ice_ufrag.empty() && desc.ice_pwd.empty())
101 return true;
102
103 if (desc.ice_ufrag.length() < ICE_UFRAG_MIN_LENGTH ||
104 desc.ice_ufrag.length() > ICE_UFRAG_MAX_LENGTH) {
105 return false;
106 }
107 if (desc.ice_pwd.length() < ICE_PWD_MIN_LENGTH ||
108 desc.ice_pwd.length() > ICE_PWD_MAX_LENGTH) {
109 return false;
110 }
111 return true;
112 }
113
BadTransportDescription(const std::string & desc,std::string * err_desc)114 bool BadTransportDescription(const std::string& desc, std::string* err_desc) {
115 if (err_desc) {
116 *err_desc = desc;
117 }
118 LOG(LS_ERROR) << desc;
119 return false;
120 }
121
IceCredentialsChanged(const std::string & old_ufrag,const std::string & old_pwd,const std::string & new_ufrag,const std::string & new_pwd)122 bool IceCredentialsChanged(const std::string& old_ufrag,
123 const std::string& old_pwd,
124 const std::string& new_ufrag,
125 const std::string& new_pwd) {
126 // TODO(jiayl): The standard (RFC 5245 Section 9.1.1.1) says that ICE should
127 // restart when both the ufrag and password are changed, but we do restart
128 // when either ufrag or passwrod is changed to keep compatible with GICE. We
129 // should clean this up when GICE is no longer used.
130 return (old_ufrag != new_ufrag) || (old_pwd != new_pwd);
131 }
132
IceCredentialsChanged(const TransportDescription & old_desc,const TransportDescription & new_desc)133 static bool IceCredentialsChanged(const TransportDescription& old_desc,
134 const TransportDescription& new_desc) {
135 return IceCredentialsChanged(old_desc.ice_ufrag, old_desc.ice_pwd,
136 new_desc.ice_ufrag, new_desc.ice_pwd);
137 }
138
Transport(rtc::Thread * signaling_thread,rtc::Thread * worker_thread,const std::string & content_name,const std::string & type,PortAllocator * allocator)139 Transport::Transport(rtc::Thread* signaling_thread,
140 rtc::Thread* worker_thread,
141 const std::string& content_name,
142 const std::string& type,
143 PortAllocator* allocator)
144 : signaling_thread_(signaling_thread),
145 worker_thread_(worker_thread),
146 content_name_(content_name),
147 type_(type),
148 allocator_(allocator),
149 destroyed_(false),
150 readable_(TRANSPORT_STATE_NONE),
151 writable_(TRANSPORT_STATE_NONE),
152 was_writable_(false),
153 connect_requested_(false),
154 ice_role_(ICEROLE_UNKNOWN),
155 tiebreaker_(0),
156 protocol_(ICEPROTO_HYBRID),
157 remote_ice_mode_(ICEMODE_FULL) {
158 }
159
~Transport()160 Transport::~Transport() {
161 ASSERT(signaling_thread_->IsCurrent());
162 ASSERT(destroyed_);
163 }
164
SetIceRole(IceRole role)165 void Transport::SetIceRole(IceRole role) {
166 worker_thread_->Invoke<void>(Bind(&Transport::SetIceRole_w, this, role));
167 }
168
SetIdentity(rtc::SSLIdentity * identity)169 void Transport::SetIdentity(rtc::SSLIdentity* identity) {
170 worker_thread_->Invoke<void>(Bind(&Transport::SetIdentity_w, this, identity));
171 }
172
GetIdentity(rtc::SSLIdentity ** identity)173 bool Transport::GetIdentity(rtc::SSLIdentity** identity) {
174 // The identity is set on the worker thread, so for safety it must also be
175 // acquired on the worker thread.
176 return worker_thread_->Invoke<bool>(
177 Bind(&Transport::GetIdentity_w, this, identity));
178 }
179
GetRemoteCertificate(rtc::SSLCertificate ** cert)180 bool Transport::GetRemoteCertificate(rtc::SSLCertificate** cert) {
181 // Channels can be deleted on the worker thread, so for safety the remote
182 // certificate is acquired on the worker thread.
183 return worker_thread_->Invoke<bool>(
184 Bind(&Transport::GetRemoteCertificate_w, this, cert));
185 }
186
GetRemoteCertificate_w(rtc::SSLCertificate ** cert)187 bool Transport::GetRemoteCertificate_w(rtc::SSLCertificate** cert) {
188 ASSERT(worker_thread()->IsCurrent());
189 if (channels_.empty())
190 return false;
191
192 ChannelMap::iterator iter = channels_.begin();
193 return iter->second->GetRemoteCertificate(cert);
194 }
195
SetLocalTransportDescription(const TransportDescription & description,ContentAction action,std::string * error_desc)196 bool Transport::SetLocalTransportDescription(
197 const TransportDescription& description,
198 ContentAction action,
199 std::string* error_desc) {
200 return worker_thread_->Invoke<bool>(Bind(
201 &Transport::SetLocalTransportDescription_w, this,
202 description, action, error_desc));
203 }
204
SetRemoteTransportDescription(const TransportDescription & description,ContentAction action,std::string * error_desc)205 bool Transport::SetRemoteTransportDescription(
206 const TransportDescription& description,
207 ContentAction action,
208 std::string* error_desc) {
209 return worker_thread_->Invoke<bool>(Bind(
210 &Transport::SetRemoteTransportDescription_w, this,
211 description, action, error_desc));
212 }
213
CreateChannel(int component)214 TransportChannelImpl* Transport::CreateChannel(int component) {
215 return worker_thread_->Invoke<TransportChannelImpl*>(Bind(
216 &Transport::CreateChannel_w, this, component));
217 }
218
CreateChannel_w(int component)219 TransportChannelImpl* Transport::CreateChannel_w(int component) {
220 ASSERT(worker_thread()->IsCurrent());
221 TransportChannelImpl *impl;
222 rtc::CritScope cs(&crit_);
223
224 // Create the entry if it does not exist.
225 bool impl_exists = false;
226 if (channels_.find(component) == channels_.end()) {
227 impl = CreateTransportChannel(component);
228 channels_[component] = ChannelMapEntry(impl);
229 } else {
230 impl = channels_[component].get();
231 impl_exists = true;
232 }
233
234 // Increase the ref count.
235 channels_[component].AddRef();
236 destroyed_ = false;
237
238 if (impl_exists) {
239 // If this is an existing channel, we should just return it without
240 // connecting to all the signal again.
241 return impl;
242 }
243
244 // Push down our transport state to the new channel.
245 impl->SetIceRole(ice_role_);
246 impl->SetIceTiebreaker(tiebreaker_);
247 // TODO(ronghuawu): Change CreateChannel_w to be able to return error since
248 // below Apply**Description_w calls can fail.
249 if (local_description_)
250 ApplyLocalTransportDescription_w(impl, NULL);
251 if (remote_description_)
252 ApplyRemoteTransportDescription_w(impl, NULL);
253 if (local_description_ && remote_description_)
254 ApplyNegotiatedTransportDescription_w(impl, NULL);
255
256 impl->SignalReadableState.connect(this, &Transport::OnChannelReadableState);
257 impl->SignalWritableState.connect(this, &Transport::OnChannelWritableState);
258 impl->SignalRequestSignaling.connect(
259 this, &Transport::OnChannelRequestSignaling);
260 impl->SignalCandidateReady.connect(this, &Transport::OnChannelCandidateReady);
261 impl->SignalRouteChange.connect(this, &Transport::OnChannelRouteChange);
262 impl->SignalCandidatesAllocationDone.connect(
263 this, &Transport::OnChannelCandidatesAllocationDone);
264 impl->SignalRoleConflict.connect(this, &Transport::OnRoleConflict);
265 impl->SignalConnectionRemoved.connect(
266 this, &Transport::OnChannelConnectionRemoved);
267
268 if (connect_requested_) {
269 impl->Connect();
270 if (channels_.size() == 1) {
271 // If this is the first channel, then indicate that we have started
272 // connecting.
273 signaling_thread()->Post(this, MSG_CONNECTING, NULL);
274 }
275 }
276 return impl;
277 }
278
GetChannel(int component)279 TransportChannelImpl* Transport::GetChannel(int component) {
280 rtc::CritScope cs(&crit_);
281 ChannelMap::iterator iter = channels_.find(component);
282 return (iter != channels_.end()) ? iter->second.get() : NULL;
283 }
284
HasChannels()285 bool Transport::HasChannels() {
286 rtc::CritScope cs(&crit_);
287 return !channels_.empty();
288 }
289
DestroyChannel(int component)290 void Transport::DestroyChannel(int component) {
291 worker_thread_->Invoke<void>(Bind(
292 &Transport::DestroyChannel_w, this, component));
293 }
294
DestroyChannel_w(int component)295 void Transport::DestroyChannel_w(int component) {
296 ASSERT(worker_thread()->IsCurrent());
297
298 TransportChannelImpl* impl = NULL;
299 {
300 rtc::CritScope cs(&crit_);
301 ChannelMap::iterator iter = channels_.find(component);
302 if (iter == channels_.end())
303 return;
304
305 iter->second.DecRef();
306 if (!iter->second.ref()) {
307 impl = iter->second.get();
308 channels_.erase(iter);
309 }
310 }
311
312 if (connect_requested_ && channels_.empty()) {
313 // We're no longer attempting to connect.
314 signaling_thread()->Post(this, MSG_CONNECTING, NULL);
315 }
316
317 if (impl) {
318 // Check in case the deleted channel was the only non-writable channel.
319 OnChannelWritableState(impl);
320 DestroyTransportChannel(impl);
321 }
322 }
323
ConnectChannels()324 void Transport::ConnectChannels() {
325 ASSERT(signaling_thread()->IsCurrent());
326 worker_thread_->Invoke<void>(Bind(&Transport::ConnectChannels_w, this));
327 }
328
ConnectChannels_w()329 void Transport::ConnectChannels_w() {
330 ASSERT(worker_thread()->IsCurrent());
331 if (connect_requested_ || channels_.empty())
332 return;
333 connect_requested_ = true;
334 signaling_thread()->Post(
335 this, MSG_CANDIDATEREADY, NULL);
336
337 if (!local_description_) {
338 // TOOD(mallinath) : TransportDescription(TD) shouldn't be generated here.
339 // As Transport must know TD is offer or answer and cricket::Transport
340 // doesn't have the capability to decide it. This should be set by the
341 // Session.
342 // Session must generate local TD before remote candidates pushed when
343 // initiate request initiated by the remote.
344 LOG(LS_INFO) << "Transport::ConnectChannels_w: No local description has "
345 << "been set. Will generate one.";
346 TransportDescription desc(NS_GINGLE_P2P, std::vector<std::string>(),
347 rtc::CreateRandomString(ICE_UFRAG_LENGTH),
348 rtc::CreateRandomString(ICE_PWD_LENGTH),
349 ICEMODE_FULL, CONNECTIONROLE_NONE, NULL,
350 Candidates());
351 SetLocalTransportDescription_w(desc, CA_OFFER, NULL);
352 }
353
354 CallChannels_w(&TransportChannelImpl::Connect);
355 if (!channels_.empty()) {
356 signaling_thread()->Post(this, MSG_CONNECTING, NULL);
357 }
358 }
359
OnConnecting_s()360 void Transport::OnConnecting_s() {
361 ASSERT(signaling_thread()->IsCurrent());
362 SignalConnecting(this);
363 }
364
DestroyAllChannels()365 void Transport::DestroyAllChannels() {
366 ASSERT(signaling_thread()->IsCurrent());
367 worker_thread_->Invoke<void>(
368 Bind(&Transport::DestroyAllChannels_w, this));
369 worker_thread()->Clear(this);
370 signaling_thread()->Clear(this);
371 destroyed_ = true;
372 }
373
DestroyAllChannels_w()374 void Transport::DestroyAllChannels_w() {
375 ASSERT(worker_thread()->IsCurrent());
376 std::vector<TransportChannelImpl*> impls;
377 {
378 rtc::CritScope cs(&crit_);
379 for (ChannelMap::iterator iter = channels_.begin();
380 iter != channels_.end();
381 ++iter) {
382 iter->second.DecRef();
383 if (!iter->second.ref())
384 impls.push_back(iter->second.get());
385 }
386 }
387 channels_.clear();
388
389
390 for (size_t i = 0; i < impls.size(); ++i)
391 DestroyTransportChannel(impls[i]);
392 }
393
ResetChannels()394 void Transport::ResetChannels() {
395 ASSERT(signaling_thread()->IsCurrent());
396 worker_thread_->Invoke<void>(Bind(&Transport::ResetChannels_w, this));
397 }
398
ResetChannels_w()399 void Transport::ResetChannels_w() {
400 ASSERT(worker_thread()->IsCurrent());
401
402 // We are no longer attempting to connect
403 connect_requested_ = false;
404
405 // Clear out the old messages, they aren't relevant
406 rtc::CritScope cs(&crit_);
407 ready_candidates_.clear();
408
409 // Reset all of the channels
410 CallChannels_w(&TransportChannelImpl::Reset);
411 }
412
OnSignalingReady()413 void Transport::OnSignalingReady() {
414 ASSERT(signaling_thread()->IsCurrent());
415 if (destroyed_) return;
416
417 worker_thread()->Post(this, MSG_ONSIGNALINGREADY, NULL);
418
419 // Notify the subclass.
420 OnTransportSignalingReady();
421 }
422
CallChannels_w(TransportChannelFunc func)423 void Transport::CallChannels_w(TransportChannelFunc func) {
424 ASSERT(worker_thread()->IsCurrent());
425 rtc::CritScope cs(&crit_);
426 for (ChannelMap::iterator iter = channels_.begin();
427 iter != channels_.end();
428 ++iter) {
429 ((iter->second.get())->*func)();
430 }
431 }
432
VerifyCandidate(const Candidate & cand,std::string * error)433 bool Transport::VerifyCandidate(const Candidate& cand, std::string* error) {
434 // No address zero.
435 if (cand.address().IsNil() || cand.address().IsAny()) {
436 *error = "candidate has address of zero";
437 return false;
438 }
439
440 // Disallow all ports below 1024, except for 80 and 443 on public addresses.
441 int port = cand.address().port();
442 if (cand.protocol() == TCP_PROTOCOL_NAME &&
443 (cand.tcptype() == TCPTYPE_ACTIVE_STR || port == 0)) {
444 // Expected for active-only candidates per
445 // http://tools.ietf.org/html/rfc6544#section-4.5 so no error.
446 // Libjingle clients emit port 0, in "active" mode.
447 return true;
448 }
449 if (port < 1024) {
450 if ((port != 80) && (port != 443)) {
451 *error = "candidate has port below 1024, but not 80 or 443";
452 return false;
453 }
454
455 if (cand.address().IsPrivateIP()) {
456 *error = "candidate has port of 80 or 443 with private IP address";
457 return false;
458 }
459 }
460
461 return true;
462 }
463
464
GetStats(TransportStats * stats)465 bool Transport::GetStats(TransportStats* stats) {
466 ASSERT(signaling_thread()->IsCurrent());
467 return worker_thread_->Invoke<bool>(Bind(
468 &Transport::GetStats_w, this, stats));
469 }
470
GetStats_w(TransportStats * stats)471 bool Transport::GetStats_w(TransportStats* stats) {
472 ASSERT(worker_thread()->IsCurrent());
473 stats->content_name = content_name();
474 stats->channel_stats.clear();
475 for (ChannelMap::iterator iter = channels_.begin();
476 iter != channels_.end();
477 ++iter) {
478 TransportChannelStats substats;
479 substats.component = iter->second->component();
480 if (!iter->second->GetStats(&substats.connection_infos)) {
481 return false;
482 }
483 stats->channel_stats.push_back(substats);
484 }
485 return true;
486 }
487
GetSslRole(rtc::SSLRole * ssl_role) const488 bool Transport::GetSslRole(rtc::SSLRole* ssl_role) const {
489 return worker_thread_->Invoke<bool>(Bind(
490 &Transport::GetSslRole_w, this, ssl_role));
491 }
492
OnRemoteCandidates(const std::vector<Candidate> & candidates)493 void Transport::OnRemoteCandidates(const std::vector<Candidate>& candidates) {
494 for (std::vector<Candidate>::const_iterator iter = candidates.begin();
495 iter != candidates.end();
496 ++iter) {
497 OnRemoteCandidate(*iter);
498 }
499 }
500
OnRemoteCandidate(const Candidate & candidate)501 void Transport::OnRemoteCandidate(const Candidate& candidate) {
502 ASSERT(signaling_thread()->IsCurrent());
503 if (destroyed_) return;
504
505 if (!HasChannel(candidate.component())) {
506 LOG(LS_WARNING) << "Ignoring candidate for unknown component "
507 << candidate.component();
508 return;
509 }
510
511 ChannelParams* params = new ChannelParams(new Candidate(candidate));
512 worker_thread()->Post(this, MSG_ONREMOTECANDIDATE, params);
513 }
514
OnRemoteCandidate_w(const Candidate & candidate)515 void Transport::OnRemoteCandidate_w(const Candidate& candidate) {
516 ASSERT(worker_thread()->IsCurrent());
517 ChannelMap::iterator iter = channels_.find(candidate.component());
518 // It's ok for a channel to go away while this message is in transit.
519 if (iter != channels_.end()) {
520 iter->second->OnCandidate(candidate);
521 }
522 }
523
OnChannelReadableState(TransportChannel * channel)524 void Transport::OnChannelReadableState(TransportChannel* channel) {
525 ASSERT(worker_thread()->IsCurrent());
526 signaling_thread()->Post(this, MSG_READSTATE, NULL);
527 }
528
OnChannelReadableState_s()529 void Transport::OnChannelReadableState_s() {
530 ASSERT(signaling_thread()->IsCurrent());
531 TransportState readable = GetTransportState_s(true);
532 if (readable_ != readable) {
533 readable_ = readable;
534 SignalReadableState(this);
535 }
536 }
537
OnChannelWritableState(TransportChannel * channel)538 void Transport::OnChannelWritableState(TransportChannel* channel) {
539 ASSERT(worker_thread()->IsCurrent());
540 signaling_thread()->Post(this, MSG_WRITESTATE, NULL);
541
542 MaybeCompleted_w();
543 }
544
OnChannelWritableState_s()545 void Transport::OnChannelWritableState_s() {
546 ASSERT(signaling_thread()->IsCurrent());
547 TransportState writable = GetTransportState_s(false);
548 if (writable_ != writable) {
549 was_writable_ = (writable_ == TRANSPORT_STATE_ALL);
550 writable_ = writable;
551 SignalWritableState(this);
552 }
553 }
554
GetTransportState_s(bool read)555 TransportState Transport::GetTransportState_s(bool read) {
556 ASSERT(signaling_thread()->IsCurrent());
557 rtc::CritScope cs(&crit_);
558 bool any = false;
559 bool all = !channels_.empty();
560 for (ChannelMap::iterator iter = channels_.begin();
561 iter != channels_.end();
562 ++iter) {
563 bool b = (read ? iter->second->readable() :
564 iter->second->writable());
565 any = any || b;
566 all = all && b;
567 }
568 if (all) {
569 return TRANSPORT_STATE_ALL;
570 } else if (any) {
571 return TRANSPORT_STATE_SOME;
572 } else {
573 return TRANSPORT_STATE_NONE;
574 }
575 }
576
OnChannelRequestSignaling(TransportChannelImpl * channel)577 void Transport::OnChannelRequestSignaling(TransportChannelImpl* channel) {
578 ASSERT(worker_thread()->IsCurrent());
579 ChannelParams* params = new ChannelParams(channel->component());
580 signaling_thread()->Post(this, MSG_REQUESTSIGNALING, params);
581 }
582
OnChannelRequestSignaling_s(int component)583 void Transport::OnChannelRequestSignaling_s(int component) {
584 ASSERT(signaling_thread()->IsCurrent());
585 LOG(LS_INFO) << "Transport: " << content_name_ << ", allocating candidates";
586 // Resetting ICE state for the channel.
587 {
588 rtc::CritScope cs(&crit_);
589 ChannelMap::iterator iter = channels_.find(component);
590 if (iter != channels_.end())
591 iter->second.set_candidates_allocated(false);
592 }
593 SignalRequestSignaling(this);
594 }
595
OnChannelCandidateReady(TransportChannelImpl * channel,const Candidate & candidate)596 void Transport::OnChannelCandidateReady(TransportChannelImpl* channel,
597 const Candidate& candidate) {
598 ASSERT(worker_thread()->IsCurrent());
599 rtc::CritScope cs(&crit_);
600 ready_candidates_.push_back(candidate);
601
602 // We hold any messages until the client lets us connect.
603 if (connect_requested_) {
604 signaling_thread()->Post(
605 this, MSG_CANDIDATEREADY, NULL);
606 }
607 }
608
OnChannelCandidateReady_s()609 void Transport::OnChannelCandidateReady_s() {
610 ASSERT(signaling_thread()->IsCurrent());
611 ASSERT(connect_requested_);
612
613 std::vector<Candidate> candidates;
614 {
615 rtc::CritScope cs(&crit_);
616 candidates.swap(ready_candidates_);
617 }
618
619 // we do the deleting of Candidate* here to keep the new above and
620 // delete below close to each other
621 if (!candidates.empty()) {
622 SignalCandidatesReady(this, candidates);
623 }
624 }
625
OnChannelRouteChange(TransportChannel * channel,const Candidate & remote_candidate)626 void Transport::OnChannelRouteChange(TransportChannel* channel,
627 const Candidate& remote_candidate) {
628 ASSERT(worker_thread()->IsCurrent());
629 ChannelParams* params = new ChannelParams(new Candidate(remote_candidate));
630 params->channel = static_cast<cricket::TransportChannelImpl*>(channel);
631 signaling_thread()->Post(this, MSG_ROUTECHANGE, params);
632 }
633
OnChannelRouteChange_s(const TransportChannel * channel,const Candidate & remote_candidate)634 void Transport::OnChannelRouteChange_s(const TransportChannel* channel,
635 const Candidate& remote_candidate) {
636 ASSERT(signaling_thread()->IsCurrent());
637 SignalRouteChange(this, remote_candidate.component(), remote_candidate);
638 }
639
OnChannelCandidatesAllocationDone(TransportChannelImpl * channel)640 void Transport::OnChannelCandidatesAllocationDone(
641 TransportChannelImpl* channel) {
642 ASSERT(worker_thread()->IsCurrent());
643 rtc::CritScope cs(&crit_);
644 ChannelMap::iterator iter = channels_.find(channel->component());
645 ASSERT(iter != channels_.end());
646 LOG(LS_INFO) << "Transport: " << content_name_ << ", component "
647 << channel->component() << " allocation complete";
648 iter->second.set_candidates_allocated(true);
649
650 // If all channels belonging to this Transport got signal, then
651 // forward this signal to upper layer.
652 // Can this signal arrive before all transport channels are created?
653 for (iter = channels_.begin(); iter != channels_.end(); ++iter) {
654 if (!iter->second.candidates_allocated())
655 return;
656 }
657 signaling_thread_->Post(this, MSG_CANDIDATEALLOCATIONCOMPLETE);
658
659 MaybeCompleted_w();
660 }
661
OnChannelCandidatesAllocationDone_s()662 void Transport::OnChannelCandidatesAllocationDone_s() {
663 ASSERT(signaling_thread()->IsCurrent());
664 LOG(LS_INFO) << "Transport: " << content_name_ << " allocation complete";
665 SignalCandidatesAllocationDone(this);
666 }
667
OnRoleConflict(TransportChannelImpl * channel)668 void Transport::OnRoleConflict(TransportChannelImpl* channel) {
669 signaling_thread_->Post(this, MSG_ROLECONFLICT);
670 }
671
OnChannelConnectionRemoved(TransportChannelImpl * channel)672 void Transport::OnChannelConnectionRemoved(TransportChannelImpl* channel) {
673 ASSERT(worker_thread()->IsCurrent());
674 MaybeCompleted_w();
675
676 // Check if the state is now Failed.
677 // Failed is only available in the Controlling ICE role.
678 if (channel->GetIceRole() != ICEROLE_CONTROLLING) {
679 return;
680 }
681
682 ChannelMap::iterator iter = channels_.find(channel->component());
683 ASSERT(iter != channels_.end());
684 // Failed can only occur after candidate allocation has stopped.
685 if (!iter->second.candidates_allocated()) {
686 return;
687 }
688
689 size_t connections = channel->GetConnectionCount();
690 if (connections == 0) {
691 // A Transport has failed if any of its channels have no remaining
692 // connections.
693 signaling_thread_->Post(this, MSG_FAILED);
694 }
695 }
696
MaybeCompleted_w()697 void Transport::MaybeCompleted_w() {
698 ASSERT(worker_thread()->IsCurrent());
699
700 // A Transport's ICE process is completed if all of its channels are writable,
701 // have finished allocating candidates, and have pruned all but one of their
702 // connections.
703 ChannelMap::const_iterator iter;
704 for (iter = channels_.begin(); iter != channels_.end(); ++iter) {
705 const TransportChannelImpl* channel = iter->second.get();
706 if (!(channel->writable() &&
707 channel->GetConnectionCount() == 1 &&
708 channel->GetIceRole() == ICEROLE_CONTROLLING &&
709 iter->second.candidates_allocated())) {
710 return;
711 }
712 }
713
714 signaling_thread_->Post(this, MSG_COMPLETED);
715 }
716
SetIceRole_w(IceRole role)717 void Transport::SetIceRole_w(IceRole role) {
718 rtc::CritScope cs(&crit_);
719 ice_role_ = role;
720 for (ChannelMap::iterator iter = channels_.begin();
721 iter != channels_.end(); ++iter) {
722 iter->second->SetIceRole(ice_role_);
723 }
724 }
725
SetRemoteIceMode_w(IceMode mode)726 void Transport::SetRemoteIceMode_w(IceMode mode) {
727 rtc::CritScope cs(&crit_);
728 remote_ice_mode_ = mode;
729 // Shouldn't channels be created after this method executed?
730 for (ChannelMap::iterator iter = channels_.begin();
731 iter != channels_.end(); ++iter) {
732 iter->second->SetRemoteIceMode(remote_ice_mode_);
733 }
734 }
735
SetLocalTransportDescription_w(const TransportDescription & desc,ContentAction action,std::string * error_desc)736 bool Transport::SetLocalTransportDescription_w(
737 const TransportDescription& desc,
738 ContentAction action,
739 std::string* error_desc) {
740 bool ret = true;
741 rtc::CritScope cs(&crit_);
742
743 if (!VerifyIceParams(desc)) {
744 return BadTransportDescription("Invalid ice-ufrag or ice-pwd length",
745 error_desc);
746 }
747
748 if (local_description_ && IceCredentialsChanged(*local_description_, desc)) {
749 IceRole new_ice_role = (action == CA_OFFER) ? ICEROLE_CONTROLLING
750 : ICEROLE_CONTROLLED;
751
752 // It must be called before ApplyLocalTransportDescription_w, which may
753 // trigger an ICE restart and depends on the new ICE role.
754 SetIceRole_w(new_ice_role);
755 }
756
757 local_description_.reset(new TransportDescription(desc));
758
759 for (ChannelMap::iterator iter = channels_.begin();
760 iter != channels_.end(); ++iter) {
761 ret &= ApplyLocalTransportDescription_w(iter->second.get(), error_desc);
762 }
763 if (!ret)
764 return false;
765
766 // If PRANSWER/ANSWER is set, we should decide transport protocol type.
767 if (action == CA_PRANSWER || action == CA_ANSWER) {
768 ret &= NegotiateTransportDescription_w(action, error_desc);
769 }
770 return ret;
771 }
772
SetRemoteTransportDescription_w(const TransportDescription & desc,ContentAction action,std::string * error_desc)773 bool Transport::SetRemoteTransportDescription_w(
774 const TransportDescription& desc,
775 ContentAction action,
776 std::string* error_desc) {
777 bool ret = true;
778 rtc::CritScope cs(&crit_);
779
780 if (!VerifyIceParams(desc)) {
781 return BadTransportDescription("Invalid ice-ufrag or ice-pwd length",
782 error_desc);
783 }
784
785 remote_description_.reset(new TransportDescription(desc));
786 for (ChannelMap::iterator iter = channels_.begin();
787 iter != channels_.end(); ++iter) {
788 ret &= ApplyRemoteTransportDescription_w(iter->second.get(), error_desc);
789 }
790
791 // If PRANSWER/ANSWER is set, we should decide transport protocol type.
792 if (action == CA_PRANSWER || action == CA_ANSWER) {
793 ret = NegotiateTransportDescription_w(CA_OFFER, error_desc);
794 }
795 return ret;
796 }
797
ApplyLocalTransportDescription_w(TransportChannelImpl * ch,std::string * error_desc)798 bool Transport::ApplyLocalTransportDescription_w(TransportChannelImpl* ch,
799 std::string* error_desc) {
800 // If existing protocol_type is HYBRID, we may have not chosen the final
801 // protocol type, so update the channel protocol type from the
802 // local description. Otherwise, skip updating the protocol type.
803 // We check for HYBRID to avoid accidental changes; in the case of a
804 // session renegotiation, the new offer will have the google-ice ICE option,
805 // so we need to make sure we don't switch back from ICE mode to HYBRID
806 // when this happens.
807 // There are some other ways we could have solved this, but this is the
808 // simplest. The ultimate solution will be to get rid of GICE altogether.
809 IceProtocolType protocol_type;
810 if (ch->GetIceProtocolType(&protocol_type) &&
811 protocol_type == ICEPROTO_HYBRID) {
812 ch->SetIceProtocolType(
813 TransportProtocolFromDescription(local_description()));
814 }
815 ch->SetIceCredentials(local_description_->ice_ufrag,
816 local_description_->ice_pwd);
817 return true;
818 }
819
ApplyRemoteTransportDescription_w(TransportChannelImpl * ch,std::string * error_desc)820 bool Transport::ApplyRemoteTransportDescription_w(TransportChannelImpl* ch,
821 std::string* error_desc) {
822 ch->SetRemoteIceCredentials(remote_description_->ice_ufrag,
823 remote_description_->ice_pwd);
824 return true;
825 }
826
ApplyNegotiatedTransportDescription_w(TransportChannelImpl * channel,std::string * error_desc)827 bool Transport::ApplyNegotiatedTransportDescription_w(
828 TransportChannelImpl* channel, std::string* error_desc) {
829 channel->SetIceProtocolType(protocol_);
830 channel->SetRemoteIceMode(remote_ice_mode_);
831 return true;
832 }
833
NegotiateTransportDescription_w(ContentAction local_role,std::string * error_desc)834 bool Transport::NegotiateTransportDescription_w(ContentAction local_role,
835 std::string* error_desc) {
836 // TODO(ekr@rtfm.com): This is ICE-specific stuff. Refactor into
837 // P2PTransport.
838 const TransportDescription* offer;
839 const TransportDescription* answer;
840
841 if (local_role == CA_OFFER) {
842 offer = local_description_.get();
843 answer = remote_description_.get();
844 } else {
845 offer = remote_description_.get();
846 answer = local_description_.get();
847 }
848
849 TransportProtocol offer_proto = TransportProtocolFromDescription(offer);
850 TransportProtocol answer_proto = TransportProtocolFromDescription(answer);
851
852 // If offered protocol is gice/ice, then we expect to receive matching
853 // protocol in answer, anything else is treated as an error.
854 // HYBRID is not an option when offered specific protocol.
855 // If offered protocol is HYBRID and answered protocol is HYBRID then
856 // gice is preferred protocol.
857 // TODO(mallinath) - Answer from local or remote should't have both ice
858 // and gice support. It should always pick which protocol it wants to use.
859 // Once WebRTC stops supporting gice (for backward compatibility), HYBRID in
860 // answer must be treated as error.
861 if ((offer_proto == ICEPROTO_GOOGLE || offer_proto == ICEPROTO_RFC5245) &&
862 (offer_proto != answer_proto)) {
863 std::ostringstream desc;
864 desc << "Offer and answer protocol mismatch: "
865 << IceProtoToString(offer_proto)
866 << " vs "
867 << IceProtoToString(answer_proto);
868 return BadTransportDescription(desc.str(), error_desc);
869 }
870 protocol_ = answer_proto == ICEPROTO_HYBRID ? ICEPROTO_GOOGLE : answer_proto;
871
872 // If transport is in ICEROLE_CONTROLLED and remote end point supports only
873 // ice_lite, this local end point should take CONTROLLING role.
874 if (ice_role_ == ICEROLE_CONTROLLED &&
875 remote_description_->ice_mode == ICEMODE_LITE) {
876 SetIceRole_w(ICEROLE_CONTROLLING);
877 }
878
879 // Update remote ice_mode to all existing channels.
880 remote_ice_mode_ = remote_description_->ice_mode;
881
882 // Now that we have negotiated everything, push it downward.
883 // Note that we cache the result so that if we have race conditions
884 // between future SetRemote/SetLocal invocations and new channel
885 // creation, we have the negotiation state saved until a new
886 // negotiation happens.
887 for (ChannelMap::iterator iter = channels_.begin();
888 iter != channels_.end();
889 ++iter) {
890 if (!ApplyNegotiatedTransportDescription_w(iter->second.get(), error_desc))
891 return false;
892 }
893 return true;
894 }
895
OnMessage(rtc::Message * msg)896 void Transport::OnMessage(rtc::Message* msg) {
897 switch (msg->message_id) {
898 case MSG_ONSIGNALINGREADY:
899 CallChannels_w(&TransportChannelImpl::OnSignalingReady);
900 break;
901 case MSG_ONREMOTECANDIDATE: {
902 ChannelParams* params = static_cast<ChannelParams*>(msg->pdata);
903 OnRemoteCandidate_w(*params->candidate);
904 delete params;
905 }
906 break;
907 case MSG_CONNECTING:
908 OnConnecting_s();
909 break;
910 case MSG_READSTATE:
911 OnChannelReadableState_s();
912 break;
913 case MSG_WRITESTATE:
914 OnChannelWritableState_s();
915 break;
916 case MSG_REQUESTSIGNALING: {
917 ChannelParams* params = static_cast<ChannelParams*>(msg->pdata);
918 OnChannelRequestSignaling_s(params->component);
919 delete params;
920 }
921 break;
922 case MSG_CANDIDATEREADY:
923 OnChannelCandidateReady_s();
924 break;
925 case MSG_ROUTECHANGE: {
926 ChannelParams* params = static_cast<ChannelParams*>(msg->pdata);
927 OnChannelRouteChange_s(params->channel, *params->candidate);
928 delete params;
929 }
930 break;
931 case MSG_CANDIDATEALLOCATIONCOMPLETE:
932 OnChannelCandidatesAllocationDone_s();
933 break;
934 case MSG_ROLECONFLICT:
935 SignalRoleConflict();
936 break;
937 case MSG_COMPLETED:
938 SignalCompleted(this);
939 break;
940 case MSG_FAILED:
941 SignalFailed(this);
942 break;
943 }
944 }
945
ParseAddress(const buzz::XmlElement * elem,const buzz::QName & address_name,const buzz::QName & port_name,rtc::SocketAddress * address,ParseError * error)946 bool TransportParser::ParseAddress(const buzz::XmlElement* elem,
947 const buzz::QName& address_name,
948 const buzz::QName& port_name,
949 rtc::SocketAddress* address,
950 ParseError* error) {
951 if (!elem->HasAttr(address_name))
952 return BadParse("address does not have " + address_name.LocalPart(), error);
953 if (!elem->HasAttr(port_name))
954 return BadParse("address does not have " + port_name.LocalPart(), error);
955
956 address->SetIP(elem->Attr(address_name));
957 std::istringstream ist(elem->Attr(port_name));
958 int port = 0;
959 ist >> port;
960 address->SetPort(port);
961
962 return true;
963 }
964
965 // We're GICE if the namespace is NS_GOOGLE_P2P, or if NS_JINGLE_ICE_UDP is
966 // used and the GICE ice-option is set.
TransportProtocolFromDescription(const TransportDescription * desc)967 TransportProtocol TransportProtocolFromDescription(
968 const TransportDescription* desc) {
969 ASSERT(desc != NULL);
970 if (desc->transport_type == NS_JINGLE_ICE_UDP) {
971 return (desc->HasOption(ICE_OPTION_GICE)) ?
972 ICEPROTO_HYBRID : ICEPROTO_RFC5245;
973 }
974 return ICEPROTO_GOOGLE;
975 }
976
977 } // namespace cricket
978