Home | History | Annotate | Download | only in stunprober
      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 #ifndef WEBRTC_P2P_STUNPROBER_STUNPROBER_H_
     12 #define WEBRTC_P2P_STUNPROBER_STUNPROBER_H_
     13 
     14 #include <set>
     15 #include <string>
     16 #include <vector>
     17 
     18 #include "webrtc/base/asyncinvoker.h"
     19 #include "webrtc/base/basictypes.h"
     20 #include "webrtc/base/bytebuffer.h"
     21 #include "webrtc/base/callback.h"
     22 #include "webrtc/base/ipaddress.h"
     23 #include "webrtc/base/network.h"
     24 #include "webrtc/base/scoped_ptr.h"
     25 #include "webrtc/base/socketaddress.h"
     26 #include "webrtc/base/thread.h"
     27 #include "webrtc/base/thread_checker.h"
     28 #include "webrtc/typedefs.h"
     29 
     30 namespace rtc {
     31 class AsyncPacketSocket;
     32 class PacketSocketFactory;
     33 class Thread;
     34 class NetworkManager;
     35 class AsyncResolverInterface;
     36 }  // namespace rtc
     37 
     38 namespace stunprober {
     39 
     40 class StunProber;
     41 
     42 static const int kMaxUdpBufferSize = 1200;
     43 
     44 typedef rtc::Callback2<void, StunProber*, int> AsyncCallback;
     45 
     46 enum NatType {
     47   NATTYPE_INVALID,
     48   NATTYPE_NONE,          // Not behind a NAT.
     49   NATTYPE_UNKNOWN,       // Behind a NAT but type can't be determine.
     50   NATTYPE_SYMMETRIC,     // Behind a symmetric NAT.
     51   NATTYPE_NON_SYMMETRIC  // Behind a non-symmetric NAT.
     52 };
     53 
     54 class StunProber : public sigslot::has_slots<> {
     55  public:
     56   enum Status {       // Used in UMA_HISTOGRAM_ENUMERATION.
     57     SUCCESS,          // Successfully received bytes from the server.
     58     GENERIC_FAILURE,  // Generic failure.
     59     RESOLVE_FAILED,   // Host resolution failed.
     60     WRITE_FAILED,     // Sending a message to the server failed.
     61     READ_FAILED,      // Reading the reply from the server failed.
     62   };
     63 
     64   class Observer {
     65    public:
     66     virtual ~Observer() = default;
     67     virtual void OnPrepared(StunProber* prober, StunProber::Status status) = 0;
     68     virtual void OnFinished(StunProber* prober, StunProber::Status status) = 0;
     69   };
     70 
     71   struct Stats {
     72     Stats() {}
     73 
     74     // |raw_num_request_sent| is the total number of requests
     75     // sent. |num_request_sent| is the count of requests against a server where
     76     // we see at least one response. |num_request_sent| is designed to protect
     77     // against DNS resolution failure or the STUN server is not responsive
     78     // which could skew the result.
     79     int raw_num_request_sent = 0;
     80     int num_request_sent = 0;
     81 
     82     int num_response_received = 0;
     83     NatType nat_type = NATTYPE_INVALID;
     84     int average_rtt_ms = -1;
     85     int success_percent = 0;
     86     int target_request_interval_ns = 0;
     87     int actual_request_interval_ns = 0;
     88 
     89     // Also report whether this trial can't be considered truly as shared
     90     // mode. Share mode only makes sense when we have multiple IP resolved and
     91     // successfully probed.
     92     bool shared_socket_mode = false;
     93 
     94     std::string host_ip;
     95 
     96     // If the srflx_addrs has more than 1 element, the NAT is symmetric.
     97     std::set<std::string> srflx_addrs;
     98   };
     99 
    100   StunProber(rtc::PacketSocketFactory* socket_factory,
    101              rtc::Thread* thread,
    102              const rtc::NetworkManager::NetworkList& networks);
    103   virtual ~StunProber();
    104 
    105   // Begin performing the probe test against the |servers|. If
    106   // |shared_socket_mode| is false, each request will be done with a new socket.
    107   // Otherwise, a unique socket will be used for a single round of requests
    108   // against all resolved IPs. No single socket will be used against a given IP
    109   // more than once.  The interval of requests will be as close to the requested
    110   // inter-probe interval |stun_ta_interval_ms| as possible. After sending out
    111   // the last scheduled request, the probe will wait |timeout_ms| for request
    112   // responses and then call |finish_callback|.  |requests_per_ip| indicates how
    113   // many requests should be tried for each resolved IP address. In shared mode,
    114   // (the number of sockets to be created) equals to |requests_per_ip|. In
    115   // non-shared mode, (the number of sockets) equals to requests_per_ip * (the
    116   // number of resolved IP addresses). TODO(guoweis): Remove this once
    117   // everything moved to Prepare() and Run().
    118   bool Start(const std::vector<rtc::SocketAddress>& servers,
    119              bool shared_socket_mode,
    120              int stun_ta_interval_ms,
    121              int requests_per_ip,
    122              int timeout_ms,
    123              const AsyncCallback finish_callback);
    124 
    125   // TODO(guoweis): The combination of Prepare() and Run() are equivalent to the
    126   // Start() above. Remove Start() once everything is migrated.
    127   bool Prepare(const std::vector<rtc::SocketAddress>& servers,
    128                bool shared_socket_mode,
    129                int stun_ta_interval_ms,
    130                int requests_per_ip,
    131                int timeout_ms,
    132                StunProber::Observer* observer);
    133 
    134   // Start to send out the STUN probes.
    135   bool Start(StunProber::Observer* observer);
    136 
    137   // Method to retrieve the Stats once |finish_callback| is invoked. Returning
    138   // false when the result is inconclusive, for example, whether it's behind a
    139   // NAT or not.
    140   bool GetStats(Stats* stats) const;
    141 
    142   int estimated_execution_time() {
    143     return static_cast<int>(requests_per_ip_ * all_servers_addrs_.size() *
    144                             interval_ms_);
    145   }
    146 
    147  private:
    148   // A requester tracks the requests and responses from a single socket to many
    149   // STUN servers.
    150   class Requester;
    151 
    152   // TODO(guoweis): Remove this once all dependencies move away from
    153   // AsyncCallback.
    154   class ObserverAdapter : public Observer {
    155    public:
    156     void set_callback(AsyncCallback callback) { callback_ = callback; }
    157     void OnPrepared(StunProber* stunprober, Status status) {
    158       if (status == SUCCESS) {
    159         stunprober->Start(this);
    160       } else {
    161         callback_(stunprober, status);
    162       }
    163     }
    164     void OnFinished(StunProber* stunprober, Status status) {
    165       callback_(stunprober, status);
    166     }
    167 
    168    private:
    169     AsyncCallback callback_;
    170   };
    171 
    172   bool ResolveServerName(const rtc::SocketAddress& addr);
    173   void OnServerResolved(rtc::AsyncResolverInterface* resolver);
    174 
    175   void OnSocketReady(rtc::AsyncPacketSocket* socket,
    176                      const rtc::SocketAddress& addr);
    177 
    178   bool Done() {
    179     return num_request_sent_ >= requests_per_ip_ * all_servers_addrs_.size();
    180   }
    181 
    182   size_t total_socket_required() {
    183     return (shared_socket_mode_ ? 1 : all_servers_addrs_.size()) *
    184            requests_per_ip_;
    185   }
    186 
    187   bool should_send_next_request(uint32_t now);
    188   int get_wake_up_interval_ms();
    189 
    190   bool SendNextRequest();
    191 
    192   // Will be invoked in 1ms intervals and schedule the next request from the
    193   // |current_requester_| if the time has passed for another request.
    194   void MaybeScheduleStunRequests();
    195 
    196   void ReportOnPrepared(StunProber::Status status);
    197   void ReportOnFinished(StunProber::Status status);
    198 
    199   Requester* CreateRequester();
    200 
    201   Requester* current_requester_ = nullptr;
    202 
    203   // The time when the next request should go out.
    204   uint64_t next_request_time_ms_ = 0;
    205 
    206   // Total requests sent so far.
    207   uint32_t num_request_sent_ = 0;
    208 
    209   bool shared_socket_mode_ = false;
    210 
    211   // How many requests should be done against each resolved IP.
    212   uint32_t requests_per_ip_ = 0;
    213 
    214   // Milliseconds to pause between each STUN request.
    215   int interval_ms_;
    216 
    217   // Timeout period after the last request is sent.
    218   int timeout_ms_;
    219 
    220   // STUN server name to be resolved.
    221   std::vector<rtc::SocketAddress> servers_;
    222 
    223   // Weak references.
    224   rtc::PacketSocketFactory* socket_factory_;
    225   rtc::Thread* thread_;
    226 
    227   // Accumulate all resolved addresses.
    228   std::vector<rtc::SocketAddress> all_servers_addrs_;
    229 
    230   // The set of STUN probe sockets and their state.
    231   std::vector<Requester*> requesters_;
    232 
    233   rtc::ThreadChecker thread_checker_;
    234 
    235   // Temporary storage for created sockets.
    236   std::vector<rtc::AsyncPacketSocket*> sockets_;
    237   // This tracks how many of the sockets are ready.
    238   size_t total_ready_sockets_ = 0;
    239 
    240   rtc::AsyncInvoker invoker_;
    241 
    242   Observer* observer_ = nullptr;
    243   // TODO(guoweis): Remove this once all dependencies move away from
    244   // AsyncCallback.
    245   ObserverAdapter observer_adapter_;
    246 
    247   rtc::NetworkManager::NetworkList networks_;
    248 
    249   RTC_DISALLOW_COPY_AND_ASSIGN(StunProber);
    250 };
    251 
    252 }  // namespace stunprober
    253 
    254 #endif  // WEBRTC_P2P_STUNPROBER_STUNPROBER_H_
    255