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