• 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/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