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