Home | History | Annotate | Download | only in base
      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 {
     61   ChannelParams() : channel(NULL), candidate(NULL) {}
     62   explicit ChannelParams(int component)
     63       : component(component), channel(NULL), candidate(NULL) {}
     64   explicit ChannelParams(Candidate* candidate)
     65       : channel(NULL), candidate(candidate) {
     66   }
     67 
     68   ~ChannelParams() {
     69     delete candidate;
     70   }
     71 
     72   std::string name;
     73   int component;
     74   TransportChannelImpl* channel;
     75   Candidate* candidate;
     76 };
     77 
     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 
     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 
    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 
    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 
    142 Transport::~Transport() {
    143   ASSERT(signaling_thread_->IsCurrent());
    144   ASSERT(destroyed_);
    145 }
    146 
    147 void Transport::SetIceRole(IceRole role) {
    148   worker_thread_->Invoke<void>(Bind(&Transport::SetIceRole_w, this, role));
    149 }
    150 
    151 void Transport::SetIdentity(talk_base::SSLIdentity* identity) {
    152   worker_thread_->Invoke<void>(Bind(&Transport::SetIdentity_w, this, identity));
    153 }
    154 
    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 
    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 
    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 
    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 
    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 
    196 TransportChannelImpl* Transport::CreateChannel(int component) {
    197   return worker_thread_->Invoke<TransportChannelImpl*>(Bind(
    198       &Transport::CreateChannel_w, this, component));
    199 }
    200 
    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 
    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 
    267 bool Transport::HasChannels() {
    268   talk_base::CritScope cs(&crit_);
    269   return !channels_.empty();
    270 }
    271 
    272 void Transport::DestroyChannel(int component) {
    273   worker_thread_->Invoke<void>(Bind(
    274       &Transport::DestroyChannel_w, this, component));
    275 }
    276 
    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 
    306 void Transport::ConnectChannels() {
    307   ASSERT(signaling_thread()->IsCurrent());
    308   worker_thread_->Invoke<void>(Bind(&Transport::ConnectChannels_w, this));
    309 }
    310 
    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 
    342 void Transport::OnConnecting_s() {
    343   ASSERT(signaling_thread()->IsCurrent());
    344   SignalConnecting(this);
    345 }
    346 
    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 
    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 
    376 void Transport::ResetChannels() {
    377   ASSERT(signaling_thread()->IsCurrent());
    378   worker_thread_->Invoke<void>(Bind(&Transport::ResetChannels_w, this));
    379 }
    380 
    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 
    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 
    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 
    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 
    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 
    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 
    469 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 
    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 
    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 
    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 
    505 void Transport::OnChannelReadableState(TransportChannel* channel) {
    506   ASSERT(worker_thread()->IsCurrent());
    507   signaling_thread()->Post(this, MSG_READSTATE, NULL);
    508 }
    509 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    643 void Transport::OnChannelCandidatesAllocationDone_s() {
    644   ASSERT(signaling_thread()->IsCurrent());
    645   LOG(LS_INFO) << "Transport: " << content_name_ << " allocation complete";
    646   SignalCandidatesAllocationDone(this);
    647 }
    648 
    649 void Transport::OnRoleConflict(TransportChannelImpl* channel) {
    650   signaling_thread_->Post(this, MSG_ROLECONFLICT);
    651 }
    652 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    805 bool Transport::NegotiateTransportDescription_w(ContentAction local_role,
    806                                                 std::string* error_desc) {
    807   // TODO(ekr (at) 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 
    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 
    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.
    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