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/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 {
     62   ChannelParams() : channel(NULL), candidate(NULL) {}
     63   explicit ChannelParams(int component)
     64       : component(component), channel(NULL), candidate(NULL) {}
     65   explicit ChannelParams(Candidate* candidate)
     66       : channel(NULL), candidate(candidate) {
     67   }
     68 
     69   ~ChannelParams() {
     70     delete candidate;
     71   }
     72 
     73   std::string name;
     74   int component;
     75   TransportChannelImpl* channel;
     76   Candidate* candidate;
     77 };
     78 
     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 
     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 
    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 
    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 
    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 
    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 
    160 Transport::~Transport() {
    161   ASSERT(signaling_thread_->IsCurrent());
    162   ASSERT(destroyed_);
    163 }
    164 
    165 void Transport::SetIceRole(IceRole role) {
    166   worker_thread_->Invoke<void>(Bind(&Transport::SetIceRole_w, this, role));
    167 }
    168 
    169 void Transport::SetIdentity(rtc::SSLIdentity* identity) {
    170   worker_thread_->Invoke<void>(Bind(&Transport::SetIdentity_w, this, identity));
    171 }
    172 
    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 
    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 
    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 
    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 
    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 
    214 TransportChannelImpl* Transport::CreateChannel(int component) {
    215   return worker_thread_->Invoke<TransportChannelImpl*>(Bind(
    216       &Transport::CreateChannel_w, this, component));
    217 }
    218 
    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 
    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 
    285 bool Transport::HasChannels() {
    286   rtc::CritScope cs(&crit_);
    287   return !channels_.empty();
    288 }
    289 
    290 void Transport::DestroyChannel(int component) {
    291   worker_thread_->Invoke<void>(Bind(
    292       &Transport::DestroyChannel_w, this, component));
    293 }
    294 
    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 
    324 void Transport::ConnectChannels() {
    325   ASSERT(signaling_thread()->IsCurrent());
    326   worker_thread_->Invoke<void>(Bind(&Transport::ConnectChannels_w, this));
    327 }
    328 
    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 
    360 void Transport::OnConnecting_s() {
    361   ASSERT(signaling_thread()->IsCurrent());
    362   SignalConnecting(this);
    363 }
    364 
    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 
    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 
    394 void Transport::ResetChannels() {
    395   ASSERT(signaling_thread()->IsCurrent());
    396   worker_thread_->Invoke<void>(Bind(&Transport::ResetChannels_w, this));
    397 }
    398 
    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 
    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 
    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 
    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 
    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 
    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 
    488 bool Transport::GetSslRole(rtc::SSLRole* ssl_role) const {
    489   return worker_thread_->Invoke<bool>(Bind(
    490       &Transport::GetSslRole_w, this, ssl_role));
    491 }
    492 
    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 
    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 
    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 
    524 void Transport::OnChannelReadableState(TransportChannel* channel) {
    525   ASSERT(worker_thread()->IsCurrent());
    526   signaling_thread()->Post(this, MSG_READSTATE, NULL);
    527 }
    528 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    662 void Transport::OnChannelCandidatesAllocationDone_s() {
    663   ASSERT(signaling_thread()->IsCurrent());
    664   LOG(LS_INFO) << "Transport: " << content_name_ << " allocation complete";
    665   SignalCandidatesAllocationDone(this);
    666 }
    667 
    668 void Transport::OnRoleConflict(TransportChannelImpl* channel) {
    669   signaling_thread_->Post(this, MSG_ROLECONFLICT);
    670 }
    671 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    834 bool Transport::NegotiateTransportDescription_w(ContentAction local_role,
    835                                                 std::string* error_desc) {
    836   // TODO(ekr (at) 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 
    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 
    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.
    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