Home | History | Annotate | Download | only in base
      1 /*
      2  *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
      3  *
      4  *  Use of this source code is governed by a BSD-style license
      5  *  that can be found in the LICENSE file in the root of the source
      6  *  tree. An additional intellectual property rights grant can be found
      7  *  in the file PATENTS.  All contributing project authors may
      8  *  be found in the AUTHORS file in the root of the source tree.
      9  */
     10 
     11 #include <utility>  // for std::pair
     12 
     13 #include "webrtc/p2p/base/transport.h"
     14 
     15 #include "webrtc/p2p/base/candidate.h"
     16 #include "webrtc/p2p/base/constants.h"
     17 #include "webrtc/p2p/base/port.h"
     18 #include "webrtc/p2p/base/transportchannelimpl.h"
     19 #include "webrtc/base/bind.h"
     20 #include "webrtc/base/checks.h"
     21 #include "webrtc/base/logging.h"
     22 
     23 namespace cricket {
     24 
     25 static bool VerifyIceParams(const TransportDescription& desc) {
     26   // For legacy protocols.
     27   if (desc.ice_ufrag.empty() && desc.ice_pwd.empty())
     28     return true;
     29 
     30   if (desc.ice_ufrag.length() < ICE_UFRAG_MIN_LENGTH ||
     31       desc.ice_ufrag.length() > ICE_UFRAG_MAX_LENGTH) {
     32     return false;
     33   }
     34   if (desc.ice_pwd.length() < ICE_PWD_MIN_LENGTH ||
     35       desc.ice_pwd.length() > ICE_PWD_MAX_LENGTH) {
     36     return false;
     37   }
     38   return true;
     39 }
     40 
     41 bool BadTransportDescription(const std::string& desc, std::string* err_desc) {
     42   if (err_desc) {
     43     *err_desc = desc;
     44   }
     45   LOG(LS_ERROR) << desc;
     46   return false;
     47 }
     48 
     49 bool IceCredentialsChanged(const std::string& old_ufrag,
     50                            const std::string& old_pwd,
     51                            const std::string& new_ufrag,
     52                            const std::string& new_pwd) {
     53   // TODO(jiayl): The standard (RFC 5245 Section 9.1.1.1) says that ICE should
     54   // restart when both the ufrag and password are changed, but we do restart
     55   // when either ufrag or passwrod is changed to keep compatible with GICE. We
     56   // should clean this up when GICE is no longer used.
     57   return (old_ufrag != new_ufrag) || (old_pwd != new_pwd);
     58 }
     59 
     60 static bool IceCredentialsChanged(const TransportDescription& old_desc,
     61                                   const TransportDescription& new_desc) {
     62   return IceCredentialsChanged(old_desc.ice_ufrag, old_desc.ice_pwd,
     63                                new_desc.ice_ufrag, new_desc.ice_pwd);
     64 }
     65 
     66 Transport::Transport(const std::string& name, PortAllocator* allocator)
     67     : name_(name), allocator_(allocator) {}
     68 
     69 Transport::~Transport() {
     70   RTC_DCHECK(channels_destroyed_);
     71 }
     72 
     73 void Transport::SetIceRole(IceRole role) {
     74   ice_role_ = role;
     75   for (const auto& kv : channels_) {
     76     kv.second->SetIceRole(ice_role_);
     77   }
     78 }
     79 
     80 bool Transport::GetRemoteSSLCertificate(rtc::SSLCertificate** cert) {
     81   if (channels_.empty()) {
     82     return false;
     83   }
     84 
     85   auto iter = channels_.begin();
     86   return iter->second->GetRemoteSSLCertificate(cert);
     87 }
     88 
     89 void Transport::SetIceConfig(const IceConfig& config) {
     90   ice_config_ = config;
     91   for (const auto& kv : channels_) {
     92     kv.second->SetIceConfig(ice_config_);
     93   }
     94 }
     95 
     96 bool Transport::SetLocalTransportDescription(
     97     const TransportDescription& description,
     98     ContentAction action,
     99     std::string* error_desc) {
    100   bool ret = true;
    101 
    102   if (!VerifyIceParams(description)) {
    103     return BadTransportDescription("Invalid ice-ufrag or ice-pwd length",
    104                                    error_desc);
    105   }
    106 
    107   if (local_description_ &&
    108       IceCredentialsChanged(*local_description_, description)) {
    109     IceRole new_ice_role =
    110         (action == CA_OFFER) ? ICEROLE_CONTROLLING : ICEROLE_CONTROLLED;
    111 
    112     // It must be called before ApplyLocalTransportDescription, which may
    113     // trigger an ICE restart and depends on the new ICE role.
    114     SetIceRole(new_ice_role);
    115   }
    116 
    117   local_description_.reset(new TransportDescription(description));
    118 
    119   for (const auto& kv : channels_) {
    120     ret &= ApplyLocalTransportDescription(kv.second, error_desc);
    121   }
    122   if (!ret) {
    123     return false;
    124   }
    125 
    126   // If PRANSWER/ANSWER is set, we should decide transport protocol type.
    127   if (action == CA_PRANSWER || action == CA_ANSWER) {
    128     ret &= NegotiateTransportDescription(action, error_desc);
    129   }
    130   if (ret) {
    131     local_description_set_ = true;
    132     ConnectChannels();
    133   }
    134 
    135   return ret;
    136 }
    137 
    138 bool Transport::SetRemoteTransportDescription(
    139     const TransportDescription& description,
    140     ContentAction action,
    141     std::string* error_desc) {
    142   bool ret = true;
    143 
    144   if (!VerifyIceParams(description)) {
    145     return BadTransportDescription("Invalid ice-ufrag or ice-pwd length",
    146                                    error_desc);
    147   }
    148 
    149   remote_description_.reset(new TransportDescription(description));
    150   for (const auto& kv : channels_) {
    151     ret &= ApplyRemoteTransportDescription(kv.second, error_desc);
    152   }
    153 
    154   // If PRANSWER/ANSWER is set, we should decide transport protocol type.
    155   if (action == CA_PRANSWER || action == CA_ANSWER) {
    156     ret = NegotiateTransportDescription(CA_OFFER, error_desc);
    157   }
    158   if (ret) {
    159     remote_description_set_ = true;
    160   }
    161 
    162   return ret;
    163 }
    164 
    165 TransportChannelImpl* Transport::CreateChannel(int component) {
    166   TransportChannelImpl* channel;
    167 
    168   // Create the entry if it does not exist.
    169   bool channel_exists = false;
    170   auto iter = channels_.find(component);
    171   if (iter == channels_.end()) {
    172     channel = CreateTransportChannel(component);
    173     channels_.insert(std::pair<int, TransportChannelImpl*>(component, channel));
    174   } else {
    175     channel = iter->second;
    176     channel_exists = true;
    177   }
    178 
    179   channels_destroyed_ = false;
    180 
    181   if (channel_exists) {
    182     // If this is an existing channel, we should just return it.
    183     return channel;
    184   }
    185 
    186   // Push down our transport state to the new channel.
    187   channel->SetIceRole(ice_role_);
    188   channel->SetIceTiebreaker(tiebreaker_);
    189   channel->SetIceConfig(ice_config_);
    190   // TODO(ronghuawu): Change CreateChannel to be able to return error since
    191   // below Apply**Description calls can fail.
    192   if (local_description_)
    193     ApplyLocalTransportDescription(channel, nullptr);
    194   if (remote_description_)
    195     ApplyRemoteTransportDescription(channel, nullptr);
    196   if (local_description_ && remote_description_)
    197     ApplyNegotiatedTransportDescription(channel, nullptr);
    198 
    199   if (connect_requested_) {
    200     channel->Connect();
    201   }
    202   return channel;
    203 }
    204 
    205 TransportChannelImpl* Transport::GetChannel(int component) {
    206   auto iter = channels_.find(component);
    207   return (iter != channels_.end()) ? iter->second : nullptr;
    208 }
    209 
    210 bool Transport::HasChannels() {
    211   return !channels_.empty();
    212 }
    213 
    214 void Transport::DestroyChannel(int component) {
    215   auto iter = channels_.find(component);
    216   if (iter == channels_.end())
    217     return;
    218 
    219   TransportChannelImpl* channel = iter->second;
    220   channels_.erase(iter);
    221   DestroyTransportChannel(channel);
    222 }
    223 
    224 void Transport::ConnectChannels() {
    225   if (connect_requested_ || channels_.empty())
    226     return;
    227 
    228   connect_requested_ = true;
    229 
    230   if (!local_description_) {
    231     // TOOD(mallinath) : TransportDescription(TD) shouldn't be generated here.
    232     // As Transport must know TD is offer or answer and cricket::Transport
    233     // doesn't have the capability to decide it. This should be set by the
    234     // Session.
    235     // Session must generate local TD before remote candidates pushed when
    236     // initiate request initiated by the remote.
    237     LOG(LS_INFO) << "Transport::ConnectChannels: No local description has "
    238                  << "been set. Will generate one.";
    239     TransportDescription desc(
    240         std::vector<std::string>(), rtc::CreateRandomString(ICE_UFRAG_LENGTH),
    241         rtc::CreateRandomString(ICE_PWD_LENGTH), ICEMODE_FULL,
    242         CONNECTIONROLE_NONE, nullptr, Candidates());
    243     SetLocalTransportDescription(desc, CA_OFFER, nullptr);
    244   }
    245 
    246   CallChannels(&TransportChannelImpl::Connect);
    247 }
    248 
    249 void Transport::MaybeStartGathering() {
    250   if (connect_requested_) {
    251     CallChannels(&TransportChannelImpl::MaybeStartGathering);
    252   }
    253 }
    254 
    255 void Transport::DestroyAllChannels() {
    256   for (const auto& kv : channels_) {
    257     DestroyTransportChannel(kv.second);
    258   }
    259   channels_.clear();
    260   channels_destroyed_ = true;
    261 }
    262 
    263 void Transport::CallChannels(TransportChannelFunc func) {
    264   for (const auto& kv : channels_) {
    265     (kv.second->*func)();
    266   }
    267 }
    268 
    269 bool Transport::VerifyCandidate(const Candidate& cand, std::string* error) {
    270   // No address zero.
    271   if (cand.address().IsNil() || cand.address().IsAnyIP()) {
    272     *error = "candidate has address of zero";
    273     return false;
    274   }
    275 
    276   // Disallow all ports below 1024, except for 80 and 443 on public addresses.
    277   int port = cand.address().port();
    278   if (cand.protocol() == TCP_PROTOCOL_NAME &&
    279       (cand.tcptype() == TCPTYPE_ACTIVE_STR || port == 0)) {
    280     // Expected for active-only candidates per
    281     // http://tools.ietf.org/html/rfc6544#section-4.5 so no error.
    282     // Libjingle clients emit port 0, in "active" mode.
    283     return true;
    284   }
    285   if (port < 1024) {
    286     if ((port != 80) && (port != 443)) {
    287       *error = "candidate has port below 1024, but not 80 or 443";
    288       return false;
    289     }
    290 
    291     if (cand.address().IsPrivateIP()) {
    292       *error = "candidate has port of 80 or 443 with private IP address";
    293       return false;
    294     }
    295   }
    296 
    297   return true;
    298 }
    299 
    300 
    301 bool Transport::GetStats(TransportStats* stats) {
    302   stats->transport_name = name();
    303   stats->channel_stats.clear();
    304   for (auto kv : channels_) {
    305     TransportChannelImpl* channel = kv.second;
    306     TransportChannelStats substats;
    307     substats.component = channel->component();
    308     channel->GetSrtpCryptoSuite(&substats.srtp_crypto_suite);
    309     channel->GetSslCipherSuite(&substats.ssl_cipher_suite);
    310     if (!channel->GetStats(&substats.connection_infos)) {
    311       return false;
    312     }
    313     stats->channel_stats.push_back(substats);
    314   }
    315   return true;
    316 }
    317 
    318 bool Transport::AddRemoteCandidates(const std::vector<Candidate>& candidates,
    319                                     std::string* error) {
    320   ASSERT(!channels_destroyed_);
    321   // Verify each candidate before passing down to transport layer.
    322   for (const Candidate& cand : candidates) {
    323     if (!VerifyCandidate(cand, error)) {
    324       return false;
    325     }
    326     if (!HasChannel(cand.component())) {
    327       *error = "Candidate has unknown component: " + cand.ToString() +
    328                " for content: " + name();
    329       return false;
    330     }
    331   }
    332 
    333   for (const Candidate& candidate : candidates) {
    334     TransportChannelImpl* channel = GetChannel(candidate.component());
    335     if (channel != nullptr) {
    336       channel->AddRemoteCandidate(candidate);
    337     }
    338   }
    339   return true;
    340 }
    341 
    342 bool Transport::ApplyLocalTransportDescription(TransportChannelImpl* ch,
    343                                                std::string* error_desc) {
    344   ch->SetIceCredentials(local_description_->ice_ufrag,
    345                         local_description_->ice_pwd);
    346   return true;
    347 }
    348 
    349 bool Transport::ApplyRemoteTransportDescription(TransportChannelImpl* ch,
    350                                                 std::string* error_desc) {
    351   ch->SetRemoteIceCredentials(remote_description_->ice_ufrag,
    352                               remote_description_->ice_pwd);
    353   return true;
    354 }
    355 
    356 bool Transport::ApplyNegotiatedTransportDescription(
    357     TransportChannelImpl* channel,
    358     std::string* error_desc) {
    359   channel->SetRemoteIceMode(remote_ice_mode_);
    360   return true;
    361 }
    362 
    363 bool Transport::NegotiateTransportDescription(ContentAction local_role,
    364                                               std::string* error_desc) {
    365   // TODO(ekr (at) rtfm.com): This is ICE-specific stuff. Refactor into
    366   // P2PTransport.
    367 
    368   // If transport is in ICEROLE_CONTROLLED and remote end point supports only
    369   // ice_lite, this local end point should take CONTROLLING role.
    370   if (ice_role_ == ICEROLE_CONTROLLED &&
    371       remote_description_->ice_mode == ICEMODE_LITE) {
    372     SetIceRole(ICEROLE_CONTROLLING);
    373   }
    374 
    375   // Update remote ice_mode to all existing channels.
    376   remote_ice_mode_ = remote_description_->ice_mode;
    377 
    378   // Now that we have negotiated everything, push it downward.
    379   // Note that we cache the result so that if we have race conditions
    380   // between future SetRemote/SetLocal invocations and new channel
    381   // creation, we have the negotiation state saved until a new
    382   // negotiation happens.
    383   for (const auto& kv : channels_) {
    384     if (!ApplyNegotiatedTransportDescription(kv.second, error_desc)) {
    385       return false;
    386     }
    387   }
    388   return true;
    389 }
    390 
    391 }  // namespace cricket
    392