Guo-wei Shieh | 37931c4 | 2015-05-15 10:26:52 -0700 | [diff] [blame] | 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 | |
Edward Lemur | c20978e | 2017-07-06 19:44:34 +0200 | [diff] [blame] | 18 | #include "webrtc/rtc_base/asyncinvoker.h" |
| 19 | #include "webrtc/rtc_base/basictypes.h" |
| 20 | #include "webrtc/rtc_base/bytebuffer.h" |
| 21 | #include "webrtc/rtc_base/callback.h" |
| 22 | #include "webrtc/rtc_base/constructormagic.h" |
| 23 | #include "webrtc/rtc_base/ipaddress.h" |
| 24 | #include "webrtc/rtc_base/network.h" |
| 25 | #include "webrtc/rtc_base/socketaddress.h" |
| 26 | #include "webrtc/rtc_base/thread.h" |
| 27 | #include "webrtc/rtc_base/thread_checker.h" |
Guo-wei Shieh | 37931c4 | 2015-05-15 10:26:52 -0700 | [diff] [blame] | 28 | #include "webrtc/typedefs.h" |
| 29 | |
Guo-wei Shieh | dc13abc | 2015-06-18 14:44:41 -0700 | [diff] [blame] | 30 | namespace rtc { |
| 31 | class AsyncPacketSocket; |
| 32 | class PacketSocketFactory; |
| 33 | class Thread; |
| 34 | class NetworkManager; |
guoweis | 00507f8 | 2015-10-22 19:15:53 -0700 | [diff] [blame] | 35 | class AsyncResolverInterface; |
Guo-wei Shieh | dc13abc | 2015-06-18 14:44:41 -0700 | [diff] [blame] | 36 | } // namespace rtc |
| 37 | |
Guo-wei Shieh | 37931c4 | 2015-05-15 10:26:52 -0700 | [diff] [blame] | 38 | namespace stunprober { |
| 39 | |
Guo-wei Shieh | dc13abc | 2015-06-18 14:44:41 -0700 | [diff] [blame] | 40 | class StunProber; |
| 41 | |
Guo-wei Shieh | 37931c4 | 2015-05-15 10:26:52 -0700 | [diff] [blame] | 42 | static const int kMaxUdpBufferSize = 1200; |
| 43 | |
Guo-wei Shieh | dc13abc | 2015-06-18 14:44:41 -0700 | [diff] [blame] | 44 | typedef rtc::Callback2<void, StunProber*, int> AsyncCallback; |
Guo-wei Shieh | 37931c4 | 2015-05-15 10:26:52 -0700 | [diff] [blame] | 45 | |
Guo-wei Shieh | 72e9f04 | 2015-06-08 21:03:48 -0700 | [diff] [blame] | 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 | |
Guo-wei Shieh | dc13abc | 2015-06-18 14:44:41 -0700 | [diff] [blame] | 54 | class StunProber : public sigslot::has_slots<> { |
Guo-wei Shieh | 37931c4 | 2015-05-15 10:26:52 -0700 | [diff] [blame] | 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 | |
guoweis | 00507f8 | 2015-10-22 19:15:53 -0700 | [diff] [blame] | 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 | |
Guo-wei Shieh | 37931c4 | 2015-05-15 10:26:52 -0700 | [diff] [blame] | 71 | struct Stats { |
| 72 | Stats() {} |
Guo-wei Shieh | 72e9f04 | 2015-06-08 21:03:48 -0700 | [diff] [blame] | 73 | |
guoweis | 066ded9 | 2015-11-11 15:04:06 -0800 | [diff] [blame] | 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; |
Guo-wei Shieh | 37931c4 | 2015-05-15 10:26:52 -0700 | [diff] [blame] | 80 | int num_request_sent = 0; |
guoweis | 066ded9 | 2015-11-11 15:04:06 -0800 | [diff] [blame] | 81 | |
Guo-wei Shieh | 37931c4 | 2015-05-15 10:26:52 -0700 | [diff] [blame] | 82 | int num_response_received = 0; |
Guo-wei Shieh | 72e9f04 | 2015-06-08 21:03:48 -0700 | [diff] [blame] | 83 | NatType nat_type = NATTYPE_INVALID; |
Guo-wei Shieh | 37931c4 | 2015-05-15 10:26:52 -0700 | [diff] [blame] | 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; |
Guo-wei Shieh | 1ab67ae | 2015-05-18 21:36:20 -0700 | [diff] [blame] | 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 | |
Guo-wei Shieh | 37931c4 | 2015-05-15 10:26:52 -0700 | [diff] [blame] | 94 | std::string host_ip; |
| 95 | |
Guo-wei Shieh | 1ab67ae | 2015-05-18 21:36:20 -0700 | [diff] [blame] | 96 | // If the srflx_addrs has more than 1 element, the NAT is symmetric. |
| 97 | std::set<std::string> srflx_addrs; |
Guo-wei Shieh | 37931c4 | 2015-05-15 10:26:52 -0700 | [diff] [blame] | 98 | }; |
| 99 | |
Guo-wei Shieh | dc13abc | 2015-06-18 14:44:41 -0700 | [diff] [blame] | 100 | StunProber(rtc::PacketSocketFactory* socket_factory, |
| 101 | rtc::Thread* thread, |
| 102 | const rtc::NetworkManager::NetworkList& networks); |
Guo-wei Shieh | 37931c4 | 2015-05-15 10:26:52 -0700 | [diff] [blame] | 103 | virtual ~StunProber(); |
| 104 | |
Guo-wei Shieh | 1ab67ae | 2015-05-18 21:36:20 -0700 | [diff] [blame] | 105 | // Begin performing the probe test against the |servers|. If |
Guo-wei Shieh | 37931c4 | 2015-05-15 10:26:52 -0700 | [diff] [blame] | 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 |
guoweis | 00507f8 | 2015-10-22 19:15:53 -0700 | [diff] [blame] | 116 | // number of resolved IP addresses). TODO(guoweis): Remove this once |
| 117 | // everything moved to Prepare() and Run(). |
Guo-wei Shieh | 1ab67ae | 2015-05-18 21:36:20 -0700 | [diff] [blame] | 118 | bool Start(const std::vector<rtc::SocketAddress>& servers, |
Guo-wei Shieh | 37931c4 | 2015-05-15 10:26:52 -0700 | [diff] [blame] | 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 | |
guoweis | 00507f8 | 2015-10-22 19:15:53 -0700 | [diff] [blame] | 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 | |
Guo-wei Shieh | 37931c4 | 2015-05-15 10:26:52 -0700 | [diff] [blame] | 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. |
Guo-wei Shieh | 72e9f04 | 2015-06-08 21:03:48 -0700 | [diff] [blame] | 140 | bool GetStats(Stats* stats) const; |
Guo-wei Shieh | 37931c4 | 2015-05-15 10:26:52 -0700 | [diff] [blame] | 141 | |
guoweis | 00507f8 | 2015-10-22 19:15:53 -0700 | [diff] [blame] | 142 | int estimated_execution_time() { |
| 143 | return static_cast<int>(requests_per_ip_ * all_servers_addrs_.size() * |
| 144 | interval_ms_); |
| 145 | } |
| 146 | |
Guo-wei Shieh | 37931c4 | 2015-05-15 10:26:52 -0700 | [diff] [blame] | 147 | private: |
| 148 | // A requester tracks the requests and responses from a single socket to many |
Guo-wei Shieh | fc622cc | 2015-06-04 16:05:57 -0700 | [diff] [blame] | 149 | // STUN servers. |
| 150 | class Requester; |
Guo-wei Shieh | 37931c4 | 2015-05-15 10:26:52 -0700 | [diff] [blame] | 151 | |
guoweis | 00507f8 | 2015-10-22 19:15:53 -0700 | [diff] [blame] | 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 | |
Guo-wei Shieh | dc13abc | 2015-06-18 14:44:41 -0700 | [diff] [blame] | 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); |
Guo-wei Shieh | 37931c4 | 2015-05-15 10:26:52 -0700 | [diff] [blame] | 177 | |
deadbeef | 9a6f4d4 | 2017-05-15 19:43:33 -0700 | [diff] [blame] | 178 | void CreateSockets(); |
| 179 | |
Guo-wei Shieh | 37931c4 | 2015-05-15 10:26:52 -0700 | [diff] [blame] | 180 | bool Done() { |
Guo-wei Shieh | dc13abc | 2015-06-18 14:44:41 -0700 | [diff] [blame] | 181 | return num_request_sent_ >= requests_per_ip_ * all_servers_addrs_.size(); |
Guo-wei Shieh | 37931c4 | 2015-05-15 10:26:52 -0700 | [diff] [blame] | 182 | } |
| 183 | |
Guo-wei Shieh | dc13abc | 2015-06-18 14:44:41 -0700 | [diff] [blame] | 184 | size_t total_socket_required() { |
| 185 | return (shared_socket_mode_ ? 1 : all_servers_addrs_.size()) * |
| 186 | requests_per_ip_; |
Guo-wei Shieh | d04d3d7 | 2015-06-04 15:20:02 -0700 | [diff] [blame] | 187 | } |
| 188 | |
honghaiz | 34b11eb | 2016-03-16 08:55:44 -0700 | [diff] [blame] | 189 | bool should_send_next_request(int64_t now); |
guoweis | 00507f8 | 2015-10-22 19:15:53 -0700 | [diff] [blame] | 190 | int get_wake_up_interval_ms(); |
| 191 | |
Guo-wei Shieh | 37931c4 | 2015-05-15 10:26:52 -0700 | [diff] [blame] | 192 | bool SendNextRequest(); |
| 193 | |
| 194 | // Will be invoked in 1ms intervals and schedule the next request from the |
| 195 | // |current_requester_| if the time has passed for another request. |
| 196 | void MaybeScheduleStunRequests(); |
| 197 | |
guoweis | 00507f8 | 2015-10-22 19:15:53 -0700 | [diff] [blame] | 198 | void ReportOnPrepared(StunProber::Status status); |
| 199 | void ReportOnFinished(StunProber::Status status); |
Guo-wei Shieh | 37931c4 | 2015-05-15 10:26:52 -0700 | [diff] [blame] | 200 | |
| 201 | Requester* CreateRequester(); |
| 202 | |
| 203 | Requester* current_requester_ = nullptr; |
| 204 | |
| 205 | // The time when the next request should go out. |
honghaiz | 34b11eb | 2016-03-16 08:55:44 -0700 | [diff] [blame] | 206 | int64_t next_request_time_ms_ = 0; |
Guo-wei Shieh | 37931c4 | 2015-05-15 10:26:52 -0700 | [diff] [blame] | 207 | |
| 208 | // Total requests sent so far. |
Peter Boström | 0c4e06b | 2015-10-07 12:23:21 +0200 | [diff] [blame] | 209 | uint32_t num_request_sent_ = 0; |
Guo-wei Shieh | 37931c4 | 2015-05-15 10:26:52 -0700 | [diff] [blame] | 210 | |
| 211 | bool shared_socket_mode_ = false; |
| 212 | |
| 213 | // How many requests should be done against each resolved IP. |
Peter Boström | 0c4e06b | 2015-10-07 12:23:21 +0200 | [diff] [blame] | 214 | uint32_t requests_per_ip_ = 0; |
Guo-wei Shieh | 37931c4 | 2015-05-15 10:26:52 -0700 | [diff] [blame] | 215 | |
| 216 | // Milliseconds to pause between each STUN request. |
| 217 | int interval_ms_; |
| 218 | |
| 219 | // Timeout period after the last request is sent. |
| 220 | int timeout_ms_; |
| 221 | |
| 222 | // STUN server name to be resolved. |
Guo-wei Shieh | 1ab67ae | 2015-05-18 21:36:20 -0700 | [diff] [blame] | 223 | std::vector<rtc::SocketAddress> servers_; |
Guo-wei Shieh | 37931c4 | 2015-05-15 10:26:52 -0700 | [diff] [blame] | 224 | |
Guo-wei Shieh | dc13abc | 2015-06-18 14:44:41 -0700 | [diff] [blame] | 225 | // Weak references. |
| 226 | rtc::PacketSocketFactory* socket_factory_; |
| 227 | rtc::Thread* thread_; |
Guo-wei Shieh | 37931c4 | 2015-05-15 10:26:52 -0700 | [diff] [blame] | 228 | |
Guo-wei Shieh | dc13abc | 2015-06-18 14:44:41 -0700 | [diff] [blame] | 229 | // Accumulate all resolved addresses. |
| 230 | std::vector<rtc::SocketAddress> all_servers_addrs_; |
Guo-wei Shieh | 37931c4 | 2015-05-15 10:26:52 -0700 | [diff] [blame] | 231 | |
Guo-wei Shieh | 37931c4 | 2015-05-15 10:26:52 -0700 | [diff] [blame] | 232 | // The set of STUN probe sockets and their state. |
| 233 | std::vector<Requester*> requesters_; |
| 234 | |
| 235 | rtc::ThreadChecker thread_checker_; |
| 236 | |
Guo-wei Shieh | dc13abc | 2015-06-18 14:44:41 -0700 | [diff] [blame] | 237 | // Temporary storage for created sockets. |
| 238 | std::vector<rtc::AsyncPacketSocket*> sockets_; |
| 239 | // This tracks how many of the sockets are ready. |
| 240 | size_t total_ready_sockets_ = 0; |
| 241 | |
| 242 | rtc::AsyncInvoker invoker_; |
| 243 | |
guoweis | 00507f8 | 2015-10-22 19:15:53 -0700 | [diff] [blame] | 244 | Observer* observer_ = nullptr; |
| 245 | // TODO(guoweis): Remove this once all dependencies move away from |
| 246 | // AsyncCallback. |
| 247 | ObserverAdapter observer_adapter_; |
| 248 | |
Guo-wei Shieh | dc13abc | 2015-06-18 14:44:41 -0700 | [diff] [blame] | 249 | rtc::NetworkManager::NetworkList networks_; |
| 250 | |
henrikg | 3c089d7 | 2015-09-16 05:37:44 -0700 | [diff] [blame] | 251 | RTC_DISALLOW_COPY_AND_ASSIGN(StunProber); |
Guo-wei Shieh | 37931c4 | 2015-05-15 10:26:52 -0700 | [diff] [blame] | 252 | }; |
| 253 | |
| 254 | } // namespace stunprober |
| 255 | |
| 256 | #endif // WEBRTC_P2P_STUNPROBER_STUNPROBER_H_ |