blob: b32c8b2dcd3b6a1dae4bad4fb827ae64b48d9a1d [file] [log] [blame]
Guo-wei Shieh37931c42015-05-15 10:26:52 -07001/*
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 Lemurc20978e2017-07-06 19:44:34 +020018#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 Shieh37931c42015-05-15 10:26:52 -070028#include "webrtc/typedefs.h"
29
Guo-wei Shiehdc13abc2015-06-18 14:44:41 -070030namespace rtc {
31class AsyncPacketSocket;
32class PacketSocketFactory;
33class Thread;
34class NetworkManager;
guoweis00507f82015-10-22 19:15:53 -070035class AsyncResolverInterface;
Guo-wei Shiehdc13abc2015-06-18 14:44:41 -070036} // namespace rtc
37
Guo-wei Shieh37931c42015-05-15 10:26:52 -070038namespace stunprober {
39
Guo-wei Shiehdc13abc2015-06-18 14:44:41 -070040class StunProber;
41
Guo-wei Shieh37931c42015-05-15 10:26:52 -070042static const int kMaxUdpBufferSize = 1200;
43
Guo-wei Shiehdc13abc2015-06-18 14:44:41 -070044typedef rtc::Callback2<void, StunProber*, int> AsyncCallback;
Guo-wei Shieh37931c42015-05-15 10:26:52 -070045
Guo-wei Shieh72e9f042015-06-08 21:03:48 -070046enum 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 Shiehdc13abc2015-06-18 14:44:41 -070054class StunProber : public sigslot::has_slots<> {
Guo-wei Shieh37931c42015-05-15 10:26:52 -070055 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
guoweis00507f82015-10-22 19:15:53 -070064 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 Shieh37931c42015-05-15 10:26:52 -070071 struct Stats {
72 Stats() {}
Guo-wei Shieh72e9f042015-06-08 21:03:48 -070073
guoweis066ded92015-11-11 15:04:06 -080074 // |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 Shieh37931c42015-05-15 10:26:52 -070080 int num_request_sent = 0;
guoweis066ded92015-11-11 15:04:06 -080081
Guo-wei Shieh37931c42015-05-15 10:26:52 -070082 int num_response_received = 0;
Guo-wei Shieh72e9f042015-06-08 21:03:48 -070083 NatType nat_type = NATTYPE_INVALID;
Guo-wei Shieh37931c42015-05-15 10:26:52 -070084 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 Shieh1ab67ae2015-05-18 21:36:20 -070088
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 Shieh37931c42015-05-15 10:26:52 -070094 std::string host_ip;
95
Guo-wei Shieh1ab67ae2015-05-18 21:36:20 -070096 // If the srflx_addrs has more than 1 element, the NAT is symmetric.
97 std::set<std::string> srflx_addrs;
Guo-wei Shieh37931c42015-05-15 10:26:52 -070098 };
99
Guo-wei Shiehdc13abc2015-06-18 14:44:41 -0700100 StunProber(rtc::PacketSocketFactory* socket_factory,
101 rtc::Thread* thread,
102 const rtc::NetworkManager::NetworkList& networks);
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700103 virtual ~StunProber();
104
Guo-wei Shieh1ab67ae2015-05-18 21:36:20 -0700105 // Begin performing the probe test against the |servers|. If
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700106 // |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
guoweis00507f82015-10-22 19:15:53 -0700116 // number of resolved IP addresses). TODO(guoweis): Remove this once
117 // everything moved to Prepare() and Run().
Guo-wei Shieh1ab67ae2015-05-18 21:36:20 -0700118 bool Start(const std::vector<rtc::SocketAddress>& servers,
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700119 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
guoweis00507f82015-10-22 19:15:53 -0700125 // 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 Shieh37931c42015-05-15 10:26:52 -0700137 // 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 Shieh72e9f042015-06-08 21:03:48 -0700140 bool GetStats(Stats* stats) const;
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700141
guoweis00507f82015-10-22 19:15:53 -0700142 int estimated_execution_time() {
143 return static_cast<int>(requests_per_ip_ * all_servers_addrs_.size() *
144 interval_ms_);
145 }
146
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700147 private:
148 // A requester tracks the requests and responses from a single socket to many
Guo-wei Shiehfc622cc2015-06-04 16:05:57 -0700149 // STUN servers.
150 class Requester;
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700151
guoweis00507f82015-10-22 19:15:53 -0700152 // 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 Shiehdc13abc2015-06-18 14:44:41 -0700172 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 Shieh37931c42015-05-15 10:26:52 -0700177
deadbeef9a6f4d42017-05-15 19:43:33 -0700178 void CreateSockets();
179
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700180 bool Done() {
Guo-wei Shiehdc13abc2015-06-18 14:44:41 -0700181 return num_request_sent_ >= requests_per_ip_ * all_servers_addrs_.size();
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700182 }
183
Guo-wei Shiehdc13abc2015-06-18 14:44:41 -0700184 size_t total_socket_required() {
185 return (shared_socket_mode_ ? 1 : all_servers_addrs_.size()) *
186 requests_per_ip_;
Guo-wei Shiehd04d3d72015-06-04 15:20:02 -0700187 }
188
honghaiz34b11eb2016-03-16 08:55:44 -0700189 bool should_send_next_request(int64_t now);
guoweis00507f82015-10-22 19:15:53 -0700190 int get_wake_up_interval_ms();
191
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700192 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
guoweis00507f82015-10-22 19:15:53 -0700198 void ReportOnPrepared(StunProber::Status status);
199 void ReportOnFinished(StunProber::Status status);
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700200
201 Requester* CreateRequester();
202
203 Requester* current_requester_ = nullptr;
204
205 // The time when the next request should go out.
honghaiz34b11eb2016-03-16 08:55:44 -0700206 int64_t next_request_time_ms_ = 0;
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700207
208 // Total requests sent so far.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200209 uint32_t num_request_sent_ = 0;
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700210
211 bool shared_socket_mode_ = false;
212
213 // How many requests should be done against each resolved IP.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200214 uint32_t requests_per_ip_ = 0;
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700215
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 Shieh1ab67ae2015-05-18 21:36:20 -0700223 std::vector<rtc::SocketAddress> servers_;
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700224
Guo-wei Shiehdc13abc2015-06-18 14:44:41 -0700225 // Weak references.
226 rtc::PacketSocketFactory* socket_factory_;
227 rtc::Thread* thread_;
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700228
Guo-wei Shiehdc13abc2015-06-18 14:44:41 -0700229 // Accumulate all resolved addresses.
230 std::vector<rtc::SocketAddress> all_servers_addrs_;
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700231
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700232 // The set of STUN probe sockets and their state.
233 std::vector<Requester*> requesters_;
234
235 rtc::ThreadChecker thread_checker_;
236
Guo-wei Shiehdc13abc2015-06-18 14:44:41 -0700237 // 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
guoweis00507f82015-10-22 19:15:53 -0700244 Observer* observer_ = nullptr;
245 // TODO(guoweis): Remove this once all dependencies move away from
246 // AsyncCallback.
247 ObserverAdapter observer_adapter_;
248
Guo-wei Shiehdc13abc2015-06-18 14:44:41 -0700249 rtc::NetworkManager::NetworkList networks_;
250
henrikg3c089d72015-09-16 05:37:44 -0700251 RTC_DISALLOW_COPY_AND_ASSIGN(StunProber);
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700252};
253
254} // namespace stunprober
255
256#endif // WEBRTC_P2P_STUNPROBER_STUNPROBER_H_