• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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