• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
VerifyIceParams(const TransportDescription & desc)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 
BadTransportDescription(const std::string & desc,std::string * err_desc)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 
IceCredentialsChanged(const std::string & old_ufrag,const std::string & old_pwd,const std::string & new_ufrag,const std::string & new_pwd)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 
IceCredentialsChanged(const TransportDescription & old_desc,const TransportDescription & new_desc)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 
Transport(const std::string & name,PortAllocator * allocator)66 Transport::Transport(const std::string& name, PortAllocator* allocator)
67     : name_(name), allocator_(allocator) {}
68 
~Transport()69 Transport::~Transport() {
70   RTC_DCHECK(channels_destroyed_);
71 }
72 
SetIceRole(IceRole role)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 
GetRemoteSSLCertificate(rtc::SSLCertificate ** cert)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 
SetIceConfig(const IceConfig & config)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 
SetLocalTransportDescription(const TransportDescription & description,ContentAction action,std::string * error_desc)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 
SetRemoteTransportDescription(const TransportDescription & description,ContentAction action,std::string * error_desc)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 
CreateChannel(int component)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 
GetChannel(int component)205 TransportChannelImpl* Transport::GetChannel(int component) {
206   auto iter = channels_.find(component);
207   return (iter != channels_.end()) ? iter->second : nullptr;
208 }
209 
HasChannels()210 bool Transport::HasChannels() {
211   return !channels_.empty();
212 }
213 
DestroyChannel(int component)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 
ConnectChannels()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 
MaybeStartGathering()249 void Transport::MaybeStartGathering() {
250   if (connect_requested_) {
251     CallChannels(&TransportChannelImpl::MaybeStartGathering);
252   }
253 }
254 
DestroyAllChannels()255 void Transport::DestroyAllChannels() {
256   for (const auto& kv : channels_) {
257     DestroyTransportChannel(kv.second);
258   }
259   channels_.clear();
260   channels_destroyed_ = true;
261 }
262 
CallChannels(TransportChannelFunc func)263 void Transport::CallChannels(TransportChannelFunc func) {
264   for (const auto& kv : channels_) {
265     (kv.second->*func)();
266   }
267 }
268 
VerifyCandidate(const Candidate & cand,std::string * error)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 
GetStats(TransportStats * stats)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 
AddRemoteCandidates(const std::vector<Candidate> & candidates,std::string * error)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 
ApplyLocalTransportDescription(TransportChannelImpl * ch,std::string * error_desc)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 
ApplyRemoteTransportDescription(TransportChannelImpl * ch,std::string * error_desc)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 
ApplyNegotiatedTransportDescription(TransportChannelImpl * channel,std::string * error_desc)356 bool Transport::ApplyNegotiatedTransportDescription(
357     TransportChannelImpl* channel,
358     std::string* error_desc) {
359   channel->SetRemoteIceMode(remote_ice_mode_);
360   return true;
361 }
362 
NegotiateTransportDescription(ContentAction local_role,std::string * error_desc)363 bool Transport::NegotiateTransportDescription(ContentAction local_role,
364                                               std::string* error_desc) {
365   // TODO(ekr@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