• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright 2015 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 <map>
12 #include <set>
13 #include <string>
14 
15 #include "webrtc/base/asyncpacketsocket.h"
16 #include "webrtc/base/asyncresolverinterface.h"
17 #include "webrtc/base/bind.h"
18 #include "webrtc/base/checks.h"
19 #include "webrtc/base/helpers.h"
20 #include "webrtc/base/logging.h"
21 #include "webrtc/base/timeutils.h"
22 #include "webrtc/base/thread.h"
23 #include "webrtc/p2p/base/packetsocketfactory.h"
24 #include "webrtc/p2p/base/stun.h"
25 #include "webrtc/p2p/stunprober/stunprober.h"
26 
27 namespace stunprober {
28 
29 namespace {
30 
31 const int THREAD_WAKE_UP_INTERVAL_MS = 5;
32 
33 template <typename T>
IncrementCounterByAddress(std::map<T,int> * counter_per_ip,const T & ip)34 void IncrementCounterByAddress(std::map<T, int>* counter_per_ip, const T& ip) {
35   counter_per_ip->insert(std::make_pair(ip, 0)).first->second++;
36 }
37 
38 }  // namespace
39 
40 // A requester tracks the requests and responses from a single socket to many
41 // STUN servers
42 class StunProber::Requester : public sigslot::has_slots<> {
43  public:
44   // Each Request maps to a request and response.
45   struct Request {
46     // Actual time the STUN bind request was sent.
47     int64_t sent_time_ms = 0;
48     // Time the response was received.
49     int64_t received_time_ms = 0;
50 
51     // Server reflexive address from STUN response for this given request.
52     rtc::SocketAddress srflx_addr;
53 
54     rtc::IPAddress server_addr;
55 
rttstunprober::StunProber::Requester::Request56     int64_t rtt() { return received_time_ms - sent_time_ms; }
57     void ProcessResponse(const char* buf, size_t buf_len);
58   };
59 
60   // StunProber provides |server_ips| for Requester to probe. For shared
61   // socket mode, it'll be all the resolved IP addresses. For non-shared mode,
62   // it'll just be a single address.
63   Requester(StunProber* prober,
64             rtc::AsyncPacketSocket* socket,
65             const std::vector<rtc::SocketAddress>& server_ips);
66   virtual ~Requester();
67 
68   // There is no callback for SendStunRequest as the underneath socket send is
69   // expected to be completed immediately. Otherwise, it'll skip this request
70   // and move to the next one.
71   void SendStunRequest();
72 
73   void OnStunResponseReceived(rtc::AsyncPacketSocket* socket,
74                               const char* buf,
75                               size_t size,
76                               const rtc::SocketAddress& addr,
77                               const rtc::PacketTime& time);
78 
requests()79   const std::vector<Request*>& requests() { return requests_; }
80 
81   // Whether this Requester has completed all requests.
Done()82   bool Done() {
83     return static_cast<size_t>(num_request_sent_) == server_ips_.size();
84   }
85 
86  private:
87   Request* GetRequestByAddress(const rtc::IPAddress& ip);
88 
89   StunProber* prober_;
90 
91   // The socket for this session.
92   rtc::scoped_ptr<rtc::AsyncPacketSocket> socket_;
93 
94   // Temporary SocketAddress and buffer for RecvFrom.
95   rtc::SocketAddress addr_;
96   rtc::scoped_ptr<rtc::ByteBuffer> response_packet_;
97 
98   std::vector<Request*> requests_;
99   std::vector<rtc::SocketAddress> server_ips_;
100   int16_t num_request_sent_ = 0;
101   int16_t num_response_received_ = 0;
102 
103   rtc::ThreadChecker& thread_checker_;
104 
105   RTC_DISALLOW_COPY_AND_ASSIGN(Requester);
106 };
107 
Requester(StunProber * prober,rtc::AsyncPacketSocket * socket,const std::vector<rtc::SocketAddress> & server_ips)108 StunProber::Requester::Requester(
109     StunProber* prober,
110     rtc::AsyncPacketSocket* socket,
111     const std::vector<rtc::SocketAddress>& server_ips)
112     : prober_(prober),
113       socket_(socket),
114       response_packet_(new rtc::ByteBuffer(nullptr, kMaxUdpBufferSize)),
115       server_ips_(server_ips),
116       thread_checker_(prober->thread_checker_) {
117   socket_->SignalReadPacket.connect(
118       this, &StunProber::Requester::OnStunResponseReceived);
119 }
120 
~Requester()121 StunProber::Requester::~Requester() {
122   if (socket_) {
123     socket_->Close();
124   }
125   for (auto req : requests_) {
126     if (req) {
127       delete req;
128     }
129   }
130 }
131 
SendStunRequest()132 void StunProber::Requester::SendStunRequest() {
133   RTC_DCHECK(thread_checker_.CalledOnValidThread());
134   requests_.push_back(new Request());
135   Request& request = *(requests_.back());
136   cricket::StunMessage message;
137 
138   // Random transaction ID, STUN_BINDING_REQUEST
139   message.SetTransactionID(
140       rtc::CreateRandomString(cricket::kStunTransactionIdLength));
141   message.SetType(cricket::STUN_BINDING_REQUEST);
142 
143   rtc::scoped_ptr<rtc::ByteBuffer> request_packet(
144       new rtc::ByteBuffer(nullptr, kMaxUdpBufferSize));
145   if (!message.Write(request_packet.get())) {
146     prober_->ReportOnFinished(WRITE_FAILED);
147     return;
148   }
149 
150   auto addr = server_ips_[num_request_sent_];
151   request.server_addr = addr.ipaddr();
152 
153   // The write must succeed immediately. Otherwise, the calculating of the STUN
154   // request timing could become too complicated. Callback is ignored by passing
155   // empty AsyncCallback.
156   rtc::PacketOptions options;
157   int rv = socket_->SendTo(const_cast<char*>(request_packet->Data()),
158                            request_packet->Length(), addr, options);
159   if (rv < 0) {
160     prober_->ReportOnFinished(WRITE_FAILED);
161     return;
162   }
163 
164   request.sent_time_ms = rtc::Time();
165 
166   num_request_sent_++;
167   RTC_DCHECK(static_cast<size_t>(num_request_sent_) <= server_ips_.size());
168 }
169 
ProcessResponse(const char * buf,size_t buf_len)170 void StunProber::Requester::Request::ProcessResponse(const char* buf,
171                                                      size_t buf_len) {
172   int64_t now = rtc::Time();
173   rtc::ByteBuffer message(buf, buf_len);
174   cricket::StunMessage stun_response;
175   if (!stun_response.Read(&message)) {
176     // Invalid or incomplete STUN packet.
177     received_time_ms = 0;
178     return;
179   }
180 
181   // Get external address of the socket.
182   const cricket::StunAddressAttribute* addr_attr =
183       stun_response.GetAddress(cricket::STUN_ATTR_MAPPED_ADDRESS);
184   if (addr_attr == nullptr) {
185     // Addresses not available to detect whether or not behind a NAT.
186     return;
187   }
188 
189   if (addr_attr->family() != cricket::STUN_ADDRESS_IPV4 &&
190       addr_attr->family() != cricket::STUN_ADDRESS_IPV6) {
191     return;
192   }
193 
194   received_time_ms = now;
195 
196   srflx_addr = addr_attr->GetAddress();
197 }
198 
OnStunResponseReceived(rtc::AsyncPacketSocket * socket,const char * buf,size_t size,const rtc::SocketAddress & addr,const rtc::PacketTime & time)199 void StunProber::Requester::OnStunResponseReceived(
200     rtc::AsyncPacketSocket* socket,
201     const char* buf,
202     size_t size,
203     const rtc::SocketAddress& addr,
204     const rtc::PacketTime& time) {
205   RTC_DCHECK(thread_checker_.CalledOnValidThread());
206   RTC_DCHECK(socket_);
207   Request* request = GetRequestByAddress(addr.ipaddr());
208   if (!request) {
209     // Something is wrong, finish the test.
210     prober_->ReportOnFinished(GENERIC_FAILURE);
211     return;
212   }
213 
214   num_response_received_++;
215   request->ProcessResponse(buf, size);
216 }
217 
GetRequestByAddress(const rtc::IPAddress & ipaddr)218 StunProber::Requester::Request* StunProber::Requester::GetRequestByAddress(
219     const rtc::IPAddress& ipaddr) {
220   RTC_DCHECK(thread_checker_.CalledOnValidThread());
221   for (auto request : requests_) {
222     if (request->server_addr == ipaddr) {
223       return request;
224     }
225   }
226 
227   return nullptr;
228 }
229 
StunProber(rtc::PacketSocketFactory * socket_factory,rtc::Thread * thread,const rtc::NetworkManager::NetworkList & networks)230 StunProber::StunProber(rtc::PacketSocketFactory* socket_factory,
231                        rtc::Thread* thread,
232                        const rtc::NetworkManager::NetworkList& networks)
233     : interval_ms_(0),
234       socket_factory_(socket_factory),
235       thread_(thread),
236       networks_(networks) {
237 }
238 
~StunProber()239 StunProber::~StunProber() {
240   for (auto req : requesters_) {
241     if (req) {
242       delete req;
243     }
244   }
245   for (auto s : sockets_) {
246     if (s) {
247       delete s;
248     }
249   }
250 }
251 
Start(const std::vector<rtc::SocketAddress> & servers,bool shared_socket_mode,int interval_ms,int num_request_per_ip,int timeout_ms,const AsyncCallback callback)252 bool StunProber::Start(const std::vector<rtc::SocketAddress>& servers,
253                        bool shared_socket_mode,
254                        int interval_ms,
255                        int num_request_per_ip,
256                        int timeout_ms,
257                        const AsyncCallback callback) {
258   observer_adapter_.set_callback(callback);
259   return Prepare(servers, shared_socket_mode, interval_ms, num_request_per_ip,
260                  timeout_ms, &observer_adapter_);
261 }
262 
Prepare(const std::vector<rtc::SocketAddress> & servers,bool shared_socket_mode,int interval_ms,int num_request_per_ip,int timeout_ms,StunProber::Observer * observer)263 bool StunProber::Prepare(const std::vector<rtc::SocketAddress>& servers,
264                          bool shared_socket_mode,
265                          int interval_ms,
266                          int num_request_per_ip,
267                          int timeout_ms,
268                          StunProber::Observer* observer) {
269   RTC_DCHECK(thread_checker_.CalledOnValidThread());
270   interval_ms_ = interval_ms;
271   shared_socket_mode_ = shared_socket_mode;
272 
273   requests_per_ip_ = num_request_per_ip;
274   if (requests_per_ip_ == 0 || servers.size() == 0) {
275     return false;
276   }
277 
278   timeout_ms_ = timeout_ms;
279   servers_ = servers;
280   observer_ = observer;
281   return ResolveServerName(servers_.back());
282 }
283 
Start(StunProber::Observer * observer)284 bool StunProber::Start(StunProber::Observer* observer) {
285   observer_ = observer;
286   if (total_ready_sockets_ != total_socket_required()) {
287     return false;
288   }
289   MaybeScheduleStunRequests();
290   return true;
291 }
292 
ResolveServerName(const rtc::SocketAddress & addr)293 bool StunProber::ResolveServerName(const rtc::SocketAddress& addr) {
294   rtc::AsyncResolverInterface* resolver =
295       socket_factory_->CreateAsyncResolver();
296   if (!resolver) {
297     return false;
298   }
299   resolver->SignalDone.connect(this, &StunProber::OnServerResolved);
300   resolver->Start(addr);
301   return true;
302 }
303 
OnSocketReady(rtc::AsyncPacketSocket * socket,const rtc::SocketAddress & addr)304 void StunProber::OnSocketReady(rtc::AsyncPacketSocket* socket,
305                                const rtc::SocketAddress& addr) {
306   total_ready_sockets_++;
307   if (total_ready_sockets_ == total_socket_required()) {
308     ReportOnPrepared(SUCCESS);
309   }
310 }
311 
OnServerResolved(rtc::AsyncResolverInterface * resolver)312 void StunProber::OnServerResolved(rtc::AsyncResolverInterface* resolver) {
313   RTC_DCHECK(thread_checker_.CalledOnValidThread());
314 
315   if (resolver->GetError() == 0) {
316     rtc::SocketAddress addr(resolver->address().ipaddr(),
317                             resolver->address().port());
318     all_servers_addrs_.push_back(addr);
319   }
320 
321   // Deletion of AsyncResolverInterface can't be done in OnResolveResult which
322   // handles SignalDone.
323   invoker_.AsyncInvoke<void>(
324       thread_,
325       rtc::Bind(&rtc::AsyncResolverInterface::Destroy, resolver, false));
326   servers_.pop_back();
327 
328   if (servers_.size()) {
329     if (!ResolveServerName(servers_.back())) {
330       ReportOnPrepared(RESOLVE_FAILED);
331     }
332     return;
333   }
334 
335   if (all_servers_addrs_.size() == 0) {
336     ReportOnPrepared(RESOLVE_FAILED);
337     return;
338   }
339 
340   // Dedupe.
341   std::set<rtc::SocketAddress> addrs(all_servers_addrs_.begin(),
342                                      all_servers_addrs_.end());
343   all_servers_addrs_.assign(addrs.begin(), addrs.end());
344 
345   // Prepare all the sockets beforehand. All of them will bind to "any" address.
346   while (sockets_.size() < total_socket_required()) {
347     rtc::scoped_ptr<rtc::AsyncPacketSocket> socket(
348         socket_factory_->CreateUdpSocket(rtc::SocketAddress(INADDR_ANY, 0), 0,
349                                          0));
350     if (!socket) {
351       ReportOnPrepared(GENERIC_FAILURE);
352       return;
353     }
354     // Chrome and WebRTC behave differently in terms of the state of a socket
355     // once returned from PacketSocketFactory::CreateUdpSocket.
356     if (socket->GetState() == rtc::AsyncPacketSocket::STATE_BINDING) {
357       socket->SignalAddressReady.connect(this, &StunProber::OnSocketReady);
358     } else {
359       OnSocketReady(socket.get(), rtc::SocketAddress(INADDR_ANY, 0));
360     }
361     sockets_.push_back(socket.release());
362   }
363 }
364 
CreateRequester()365 StunProber::Requester* StunProber::CreateRequester() {
366   RTC_DCHECK(thread_checker_.CalledOnValidThread());
367   if (!sockets_.size()) {
368     return nullptr;
369   }
370   StunProber::Requester* requester;
371   if (shared_socket_mode_) {
372     requester = new Requester(this, sockets_.back(), all_servers_addrs_);
373   } else {
374     std::vector<rtc::SocketAddress> server_ip;
375     server_ip.push_back(
376         all_servers_addrs_[(num_request_sent_ % all_servers_addrs_.size())]);
377     requester = new Requester(this, sockets_.back(), server_ip);
378   }
379 
380   sockets_.pop_back();
381   return requester;
382 }
383 
SendNextRequest()384 bool StunProber::SendNextRequest() {
385   if (!current_requester_ || current_requester_->Done()) {
386     current_requester_ = CreateRequester();
387     requesters_.push_back(current_requester_);
388   }
389   if (!current_requester_) {
390     return false;
391   }
392   current_requester_->SendStunRequest();
393   num_request_sent_++;
394   return true;
395 }
396 
should_send_next_request(uint32_t now)397 bool StunProber::should_send_next_request(uint32_t now) {
398   if (interval_ms_ < THREAD_WAKE_UP_INTERVAL_MS) {
399     return now >= next_request_time_ms_;
400   } else {
401     return (now + (THREAD_WAKE_UP_INTERVAL_MS / 2)) >= next_request_time_ms_;
402   }
403 }
404 
get_wake_up_interval_ms()405 int StunProber::get_wake_up_interval_ms() {
406   if (interval_ms_ < THREAD_WAKE_UP_INTERVAL_MS) {
407     return 1;
408   } else {
409     return THREAD_WAKE_UP_INTERVAL_MS;
410   }
411 }
412 
MaybeScheduleStunRequests()413 void StunProber::MaybeScheduleStunRequests() {
414   RTC_DCHECK(thread_checker_.CalledOnValidThread());
415   uint32_t now = rtc::Time();
416 
417   if (Done()) {
418     invoker_.AsyncInvokeDelayed<void>(
419         thread_, rtc::Bind(&StunProber::ReportOnFinished, this, SUCCESS),
420         timeout_ms_);
421     return;
422   }
423   if (should_send_next_request(now)) {
424     if (!SendNextRequest()) {
425       ReportOnFinished(GENERIC_FAILURE);
426       return;
427     }
428     next_request_time_ms_ = now + interval_ms_;
429   }
430   invoker_.AsyncInvokeDelayed<void>(
431       thread_, rtc::Bind(&StunProber::MaybeScheduleStunRequests, this),
432       get_wake_up_interval_ms());
433 }
434 
GetStats(StunProber::Stats * prob_stats) const435 bool StunProber::GetStats(StunProber::Stats* prob_stats) const {
436   // No need to be on the same thread.
437   if (!prob_stats) {
438     return false;
439   }
440 
441   StunProber::Stats stats;
442 
443   int rtt_sum = 0;
444   int64_t first_sent_time = 0;
445   int64_t last_sent_time = 0;
446   NatType nat_type = NATTYPE_INVALID;
447 
448   // Track of how many srflx IP that we have seen.
449   std::set<rtc::IPAddress> srflx_ips;
450 
451   // If we're not receiving any response on a given IP, all requests sent to
452   // that IP should be ignored as this could just be an DNS error.
453   std::map<rtc::IPAddress, int> num_response_per_server;
454   std::map<rtc::IPAddress, int> num_request_per_server;
455 
456   for (auto* requester : requesters_) {
457     std::map<rtc::SocketAddress, int> num_response_per_srflx_addr;
458     for (auto request : requester->requests()) {
459       if (request->sent_time_ms <= 0) {
460         continue;
461       }
462 
463       ++stats.raw_num_request_sent;
464       IncrementCounterByAddress(&num_request_per_server, request->server_addr);
465 
466       if (!first_sent_time) {
467         first_sent_time = request->sent_time_ms;
468       }
469       last_sent_time = request->sent_time_ms;
470 
471       if (request->received_time_ms < request->sent_time_ms) {
472         continue;
473       }
474 
475       IncrementCounterByAddress(&num_response_per_server, request->server_addr);
476       IncrementCounterByAddress(&num_response_per_srflx_addr,
477                                 request->srflx_addr);
478       rtt_sum += request->rtt();
479       stats.srflx_addrs.insert(request->srflx_addr.ToString());
480       srflx_ips.insert(request->srflx_addr.ipaddr());
481     }
482 
483     // If we're using shared mode and seeing >1 srflx addresses for a single
484     // requester, it's symmetric NAT.
485     if (shared_socket_mode_ && num_response_per_srflx_addr.size() > 1) {
486       nat_type = NATTYPE_SYMMETRIC;
487     }
488   }
489 
490   // We're probably not behind a regular NAT. We have more than 1 distinct
491   // server reflexive IPs.
492   if (srflx_ips.size() > 1) {
493     return false;
494   }
495 
496   int num_sent = 0;
497   int num_received = 0;
498   int num_server_ip_with_response = 0;
499 
500   for (const auto& kv : num_response_per_server) {
501     RTC_DCHECK_GT(kv.second, 0);
502     num_server_ip_with_response++;
503     num_received += kv.second;
504     num_sent += num_request_per_server[kv.first];
505   }
506 
507   // Shared mode is only true if we use the shared socket and there are more
508   // than 1 responding servers.
509   stats.shared_socket_mode =
510       shared_socket_mode_ && (num_server_ip_with_response > 1);
511 
512   if (stats.shared_socket_mode && nat_type == NATTYPE_INVALID) {
513     nat_type = NATTYPE_NON_SYMMETRIC;
514   }
515 
516   // If we could find a local IP matching srflx, we're not behind a NAT.
517   rtc::SocketAddress srflx_addr;
518   if (stats.srflx_addrs.size() &&
519       !srflx_addr.FromString(*(stats.srflx_addrs.begin()))) {
520     return false;
521   }
522   for (const auto& net : networks_) {
523     if (srflx_addr.ipaddr() == net->GetBestIP()) {
524       nat_type = stunprober::NATTYPE_NONE;
525       stats.host_ip = net->GetBestIP().ToString();
526       break;
527     }
528   }
529 
530   // Finally, we know we're behind a NAT but can't determine which type it is.
531   if (nat_type == NATTYPE_INVALID) {
532     nat_type = NATTYPE_UNKNOWN;
533   }
534 
535   stats.nat_type = nat_type;
536   stats.num_request_sent = num_sent;
537   stats.num_response_received = num_received;
538   stats.target_request_interval_ns = interval_ms_ * 1000;
539 
540   if (num_sent) {
541     stats.success_percent = static_cast<int>(100 * num_received / num_sent);
542   }
543 
544   if (stats.raw_num_request_sent > 1) {
545     stats.actual_request_interval_ns =
546         (1000 * (last_sent_time - first_sent_time)) /
547         (stats.raw_num_request_sent - 1);
548   }
549 
550   if (num_received) {
551     stats.average_rtt_ms = static_cast<int>((rtt_sum / num_received));
552   }
553 
554   *prob_stats = stats;
555   return true;
556 }
557 
ReportOnPrepared(StunProber::Status status)558 void StunProber::ReportOnPrepared(StunProber::Status status) {
559   if (observer_) {
560     observer_->OnPrepared(this, status);
561   }
562 }
563 
ReportOnFinished(StunProber::Status status)564 void StunProber::ReportOnFinished(StunProber::Status status) {
565   if (observer_) {
566     observer_->OnFinished(this, status);
567   }
568 }
569 
570 }  // namespace stunprober
571