blob: 54c8b1ccda9c623f6055fdd5bd59481dddaa6869 [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
Guo-wei Shieh1ab67ae2015-05-18 21:36:20 -070011#include <map>
kwiberg3ec46792016-04-27 07:22:53 -070012#include <memory>
Guo-wei Shieh37931c42015-05-15 10:26:52 -070013#include <set>
14#include <string>
15
Guo-wei Shiehdc13abc2015-06-18 14:44:41 -070016#include "webrtc/p2p/base/packetsocketfactory.h"
Guo-wei Shieh37931c42015-05-15 10:26:52 -070017#include "webrtc/p2p/base/stun.h"
18#include "webrtc/p2p/stunprober/stunprober.h"
Edward Lemurc20978e2017-07-06 19:44:34 +020019#include "webrtc/rtc_base/asyncpacketsocket.h"
20#include "webrtc/rtc_base/asyncresolverinterface.h"
21#include "webrtc/rtc_base/bind.h"
22#include "webrtc/rtc_base/checks.h"
23#include "webrtc/rtc_base/constructormagic.h"
24#include "webrtc/rtc_base/helpers.h"
25#include "webrtc/rtc_base/logging.h"
26#include "webrtc/rtc_base/thread.h"
27#include "webrtc/rtc_base/timeutils.h"
Guo-wei Shieh37931c42015-05-15 10:26:52 -070028
29namespace stunprober {
30
Guo-wei Shieh1ab67ae2015-05-18 21:36:20 -070031namespace {
32
guoweis00507f82015-10-22 19:15:53 -070033const int THREAD_WAKE_UP_INTERVAL_MS = 5;
Guo-wei Shiehdc13abc2015-06-18 14:44:41 -070034
Guo-wei Shieh72e9f042015-06-08 21:03:48 -070035template <typename T>
36void IncrementCounterByAddress(std::map<T, int>* counter_per_ip, const T& ip) {
Guo-wei Shieh1ab67ae2015-05-18 21:36:20 -070037 counter_per_ip->insert(std::make_pair(ip, 0)).first->second++;
38}
39
40} // namespace
41
Guo-wei Shiehfc622cc2015-06-04 16:05:57 -070042// A requester tracks the requests and responses from a single socket to many
43// STUN servers
Guo-wei Shiehdc13abc2015-06-18 14:44:41 -070044class StunProber::Requester : public sigslot::has_slots<> {
Guo-wei Shiehfc622cc2015-06-04 16:05:57 -070045 public:
46 // Each Request maps to a request and response.
47 struct Request {
48 // Actual time the STUN bind request was sent.
Peter Boström0c4e06b2015-10-07 12:23:21 +020049 int64_t sent_time_ms = 0;
Guo-wei Shiehfc622cc2015-06-04 16:05:57 -070050 // Time the response was received.
Peter Boström0c4e06b2015-10-07 12:23:21 +020051 int64_t received_time_ms = 0;
Guo-wei Shiehfc622cc2015-06-04 16:05:57 -070052
Guo-wei Shiehfc622cc2015-06-04 16:05:57 -070053 // Server reflexive address from STUN response for this given request.
54 rtc::SocketAddress srflx_addr;
55
56 rtc::IPAddress server_addr;
57
Peter Boström0c4e06b2015-10-07 12:23:21 +020058 int64_t rtt() { return received_time_ms - sent_time_ms; }
Guo-wei Shiehdc13abc2015-06-18 14:44:41 -070059 void ProcessResponse(const char* buf, size_t buf_len);
Guo-wei Shiehfc622cc2015-06-04 16:05:57 -070060 };
61
62 // StunProber provides |server_ips| for Requester to probe. For shared
63 // socket mode, it'll be all the resolved IP addresses. For non-shared mode,
64 // it'll just be a single address.
65 Requester(StunProber* prober,
Guo-wei Shiehdc13abc2015-06-18 14:44:41 -070066 rtc::AsyncPacketSocket* socket,
Guo-wei Shiehfc622cc2015-06-04 16:05:57 -070067 const std::vector<rtc::SocketAddress>& server_ips);
68 virtual ~Requester();
69
70 // There is no callback for SendStunRequest as the underneath socket send is
71 // expected to be completed immediately. Otherwise, it'll skip this request
72 // and move to the next one.
73 void SendStunRequest();
74
Guo-wei Shiehdc13abc2015-06-18 14:44:41 -070075 void OnStunResponseReceived(rtc::AsyncPacketSocket* socket,
76 const char* buf,
77 size_t size,
78 const rtc::SocketAddress& addr,
79 const rtc::PacketTime& time);
Guo-wei Shiehfc622cc2015-06-04 16:05:57 -070080
81 const std::vector<Request*>& requests() { return requests_; }
82
83 // Whether this Requester has completed all requests.
84 bool Done() {
85 return static_cast<size_t>(num_request_sent_) == server_ips_.size();
86 }
87
88 private:
89 Request* GetRequestByAddress(const rtc::IPAddress& ip);
90
91 StunProber* prober_;
92
93 // The socket for this session.
kwiberg3ec46792016-04-27 07:22:53 -070094 std::unique_ptr<rtc::AsyncPacketSocket> socket_;
Guo-wei Shiehfc622cc2015-06-04 16:05:57 -070095
96 // Temporary SocketAddress and buffer for RecvFrom.
97 rtc::SocketAddress addr_;
kwiberg3ec46792016-04-27 07:22:53 -070098 std::unique_ptr<rtc::ByteBufferWriter> response_packet_;
Guo-wei Shiehfc622cc2015-06-04 16:05:57 -070099
100 std::vector<Request*> requests_;
101 std::vector<rtc::SocketAddress> server_ips_;
Peter Boström0c4e06b2015-10-07 12:23:21 +0200102 int16_t num_request_sent_ = 0;
103 int16_t num_response_received_ = 0;
Guo-wei Shiehfc622cc2015-06-04 16:05:57 -0700104
105 rtc::ThreadChecker& thread_checker_;
106
henrikg3c089d72015-09-16 05:37:44 -0700107 RTC_DISALLOW_COPY_AND_ASSIGN(Requester);
Guo-wei Shiehfc622cc2015-06-04 16:05:57 -0700108};
109
Guo-wei Shieh1ab67ae2015-05-18 21:36:20 -0700110StunProber::Requester::Requester(
111 StunProber* prober,
Guo-wei Shiehdc13abc2015-06-18 14:44:41 -0700112 rtc::AsyncPacketSocket* socket,
Guo-wei Shieh1ab67ae2015-05-18 21:36:20 -0700113 const std::vector<rtc::SocketAddress>& server_ips)
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700114 : prober_(prober),
115 socket_(socket),
jbauchf1f87202016-03-30 06:43:37 -0700116 response_packet_(new rtc::ByteBufferWriter(nullptr, kMaxUdpBufferSize)),
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700117 server_ips_(server_ips),
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700118 thread_checker_(prober->thread_checker_) {
Guo-wei Shiehdc13abc2015-06-18 14:44:41 -0700119 socket_->SignalReadPacket.connect(
120 this, &StunProber::Requester::OnStunResponseReceived);
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700121}
122
123StunProber::Requester::~Requester() {
124 if (socket_) {
125 socket_->Close();
126 }
127 for (auto req : requests_) {
128 if (req) {
129 delete req;
130 }
131 }
132}
133
134void StunProber::Requester::SendStunRequest() {
henrikg91d6ede2015-09-17 00:24:34 -0700135 RTC_DCHECK(thread_checker_.CalledOnValidThread());
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700136 requests_.push_back(new Request());
137 Request& request = *(requests_.back());
138 cricket::StunMessage message;
139
140 // Random transaction ID, STUN_BINDING_REQUEST
141 message.SetTransactionID(
142 rtc::CreateRandomString(cricket::kStunTransactionIdLength));
143 message.SetType(cricket::STUN_BINDING_REQUEST);
144
kwiberg3ec46792016-04-27 07:22:53 -0700145 std::unique_ptr<rtc::ByteBufferWriter> request_packet(
jbauchf1f87202016-03-30 06:43:37 -0700146 new rtc::ByteBufferWriter(nullptr, kMaxUdpBufferSize));
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700147 if (!message.Write(request_packet.get())) {
guoweis00507f82015-10-22 19:15:53 -0700148 prober_->ReportOnFinished(WRITE_FAILED);
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700149 return;
150 }
151
Guo-wei Shieh1ab67ae2015-05-18 21:36:20 -0700152 auto addr = server_ips_[num_request_sent_];
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700153 request.server_addr = addr.ipaddr();
154
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700155 // The write must succeed immediately. Otherwise, the calculating of the STUN
156 // request timing could become too complicated. Callback is ignored by passing
157 // empty AsyncCallback.
Guo-wei Shiehdc13abc2015-06-18 14:44:41 -0700158 rtc::PacketOptions options;
159 int rv = socket_->SendTo(const_cast<char*>(request_packet->Data()),
160 request_packet->Length(), addr, options);
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700161 if (rv < 0) {
guoweis00507f82015-10-22 19:15:53 -0700162 prober_->ReportOnFinished(WRITE_FAILED);
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700163 return;
164 }
165
nisse1bffc1d2016-05-02 08:18:55 -0700166 request.sent_time_ms = rtc::TimeMillis();
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700167
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700168 num_request_sent_++;
henrikg91d6ede2015-09-17 00:24:34 -0700169 RTC_DCHECK(static_cast<size_t>(num_request_sent_) <= server_ips_.size());
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700170}
171
Guo-wei Shiehdc13abc2015-06-18 14:44:41 -0700172void StunProber::Requester::Request::ProcessResponse(const char* buf,
173 size_t buf_len) {
nisse1bffc1d2016-05-02 08:18:55 -0700174 int64_t now = rtc::TimeMillis();
jbauchf1f87202016-03-30 06:43:37 -0700175 rtc::ByteBufferReader message(buf, buf_len);
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700176 cricket::StunMessage stun_response;
Guo-wei Shiehdc13abc2015-06-18 14:44:41 -0700177 if (!stun_response.Read(&message)) {
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700178 // Invalid or incomplete STUN packet.
Guo-wei Shieh1ab67ae2015-05-18 21:36:20 -0700179 received_time_ms = 0;
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700180 return;
181 }
182
183 // Get external address of the socket.
184 const cricket::StunAddressAttribute* addr_attr =
185 stun_response.GetAddress(cricket::STUN_ATTR_MAPPED_ADDRESS);
186 if (addr_attr == nullptr) {
187 // Addresses not available to detect whether or not behind a NAT.
188 return;
189 }
190
191 if (addr_attr->family() != cricket::STUN_ADDRESS_IPV4 &&
192 addr_attr->family() != cricket::STUN_ADDRESS_IPV6) {
193 return;
194 }
195
Guo-wei Shieh1ab67ae2015-05-18 21:36:20 -0700196 received_time_ms = now;
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700197
Guo-wei Shieh1ab67ae2015-05-18 21:36:20 -0700198 srflx_addr = addr_attr->GetAddress();
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700199}
200
Guo-wei Shiehdc13abc2015-06-18 14:44:41 -0700201void StunProber::Requester::OnStunResponseReceived(
202 rtc::AsyncPacketSocket* socket,
203 const char* buf,
204 size_t size,
205 const rtc::SocketAddress& addr,
206 const rtc::PacketTime& time) {
henrikg91d6ede2015-09-17 00:24:34 -0700207 RTC_DCHECK(thread_checker_.CalledOnValidThread());
208 RTC_DCHECK(socket_);
Guo-wei Shiehdc13abc2015-06-18 14:44:41 -0700209 Request* request = GetRequestByAddress(addr.ipaddr());
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700210 if (!request) {
211 // Something is wrong, finish the test.
guoweis00507f82015-10-22 19:15:53 -0700212 prober_->ReportOnFinished(GENERIC_FAILURE);
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700213 return;
214 }
215
216 num_response_received_++;
Guo-wei Shiehdc13abc2015-06-18 14:44:41 -0700217 request->ProcessResponse(buf, size);
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700218}
219
220StunProber::Requester::Request* StunProber::Requester::GetRequestByAddress(
221 const rtc::IPAddress& ipaddr) {
henrikg91d6ede2015-09-17 00:24:34 -0700222 RTC_DCHECK(thread_checker_.CalledOnValidThread());
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700223 for (auto request : requests_) {
224 if (request->server_addr == ipaddr) {
225 return request;
226 }
227 }
228
229 return nullptr;
230}
231
Guo-wei Shiehdc13abc2015-06-18 14:44:41 -0700232StunProber::StunProber(rtc::PacketSocketFactory* socket_factory,
233 rtc::Thread* thread,
234 const rtc::NetworkManager::NetworkList& networks)
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700235 : interval_ms_(0),
236 socket_factory_(socket_factory),
Guo-wei Shiehdc13abc2015-06-18 14:44:41 -0700237 thread_(thread),
238 networks_(networks) {
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700239}
240
241StunProber::~StunProber() {
242 for (auto req : requesters_) {
243 if (req) {
244 delete req;
245 }
246 }
Guo-wei Shiehdc13abc2015-06-18 14:44:41 -0700247 for (auto s : sockets_) {
248 if (s) {
249 delete s;
250 }
251 }
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700252}
253
Guo-wei Shieh1ab67ae2015-05-18 21:36:20 -0700254bool StunProber::Start(const std::vector<rtc::SocketAddress>& servers,
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700255 bool shared_socket_mode,
256 int interval_ms,
257 int num_request_per_ip,
258 int timeout_ms,
259 const AsyncCallback callback) {
guoweis00507f82015-10-22 19:15:53 -0700260 observer_adapter_.set_callback(callback);
261 return Prepare(servers, shared_socket_mode, interval_ms, num_request_per_ip,
262 timeout_ms, &observer_adapter_);
263}
264
265bool StunProber::Prepare(const std::vector<rtc::SocketAddress>& servers,
266 bool shared_socket_mode,
267 int interval_ms,
268 int num_request_per_ip,
269 int timeout_ms,
270 StunProber::Observer* observer) {
henrikg91d6ede2015-09-17 00:24:34 -0700271 RTC_DCHECK(thread_checker_.CalledOnValidThread());
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700272 interval_ms_ = interval_ms;
273 shared_socket_mode_ = shared_socket_mode;
274
275 requests_per_ip_ = num_request_per_ip;
Guo-wei Shieh1ab67ae2015-05-18 21:36:20 -0700276 if (requests_per_ip_ == 0 || servers.size() == 0) {
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700277 return false;
278 }
279
280 timeout_ms_ = timeout_ms;
Guo-wei Shieh1ab67ae2015-05-18 21:36:20 -0700281 servers_ = servers;
guoweis00507f82015-10-22 19:15:53 -0700282 observer_ = observer;
deadbeef9a6f4d42017-05-15 19:43:33 -0700283 // Remove addresses that are already resolved.
284 for (auto it = servers_.begin(); it != servers_.end();) {
285 if (it->ipaddr().family() != AF_UNSPEC) {
286 all_servers_addrs_.push_back(*it);
287 it = servers_.erase(it);
288 } else {
289 ++it;
290 }
291 }
292 if (servers_.empty()) {
293 CreateSockets();
294 return true;
295 }
Guo-wei Shiehdc13abc2015-06-18 14:44:41 -0700296 return ResolveServerName(servers_.back());
297}
298
guoweis00507f82015-10-22 19:15:53 -0700299bool StunProber::Start(StunProber::Observer* observer) {
300 observer_ = observer;
301 if (total_ready_sockets_ != total_socket_required()) {
302 return false;
303 }
304 MaybeScheduleStunRequests();
305 return true;
306}
307
Guo-wei Shiehdc13abc2015-06-18 14:44:41 -0700308bool StunProber::ResolveServerName(const rtc::SocketAddress& addr) {
309 rtc::AsyncResolverInterface* resolver =
310 socket_factory_->CreateAsyncResolver();
311 if (!resolver) {
312 return false;
313 }
314 resolver->SignalDone.connect(this, &StunProber::OnServerResolved);
315 resolver->Start(addr);
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700316 return true;
317}
318
Guo-wei Shiehdc13abc2015-06-18 14:44:41 -0700319void StunProber::OnSocketReady(rtc::AsyncPacketSocket* socket,
320 const rtc::SocketAddress& addr) {
321 total_ready_sockets_++;
322 if (total_ready_sockets_ == total_socket_required()) {
guoweis00507f82015-10-22 19:15:53 -0700323 ReportOnPrepared(SUCCESS);
Guo-wei Shiehdc13abc2015-06-18 14:44:41 -0700324 }
325}
326
327void StunProber::OnServerResolved(rtc::AsyncResolverInterface* resolver) {
henrikg91d6ede2015-09-17 00:24:34 -0700328 RTC_DCHECK(thread_checker_.CalledOnValidThread());
Guo-wei Shieh1ab67ae2015-05-18 21:36:20 -0700329
Guo-wei Shiehdc13abc2015-06-18 14:44:41 -0700330 if (resolver->GetError() == 0) {
331 rtc::SocketAddress addr(resolver->address().ipaddr(),
332 resolver->address().port());
333 all_servers_addrs_.push_back(addr);
Guo-wei Shieh1ab67ae2015-05-18 21:36:20 -0700334 }
335
Guo-wei Shiehdc13abc2015-06-18 14:44:41 -0700336 // Deletion of AsyncResolverInterface can't be done in OnResolveResult which
337 // handles SignalDone.
338 invoker_.AsyncInvoke<void>(
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700339 RTC_FROM_HERE, thread_,
Guo-wei Shiehdc13abc2015-06-18 14:44:41 -0700340 rtc::Bind(&rtc::AsyncResolverInterface::Destroy, resolver, false));
341 servers_.pop_back();
Guo-wei Shieh1ab67ae2015-05-18 21:36:20 -0700342
Guo-wei Shiehdc13abc2015-06-18 14:44:41 -0700343 if (servers_.size()) {
344 if (!ResolveServerName(servers_.back())) {
guoweis00507f82015-10-22 19:15:53 -0700345 ReportOnPrepared(RESOLVE_FAILED);
Guo-wei Shiehdc13abc2015-06-18 14:44:41 -0700346 }
Guo-wei Shieh1ab67ae2015-05-18 21:36:20 -0700347 return;
348 }
349
Guo-wei Shiehdc13abc2015-06-18 14:44:41 -0700350 if (all_servers_addrs_.size() == 0) {
guoweis00507f82015-10-22 19:15:53 -0700351 ReportOnPrepared(RESOLVE_FAILED);
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700352 return;
353 }
354
deadbeef9a6f4d42017-05-15 19:43:33 -0700355 CreateSockets();
356}
357
358void StunProber::CreateSockets() {
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700359 // Dedupe.
Guo-wei Shiehdc13abc2015-06-18 14:44:41 -0700360 std::set<rtc::SocketAddress> addrs(all_servers_addrs_.begin(),
361 all_servers_addrs_.end());
362 all_servers_addrs_.assign(addrs.begin(), addrs.end());
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700363
Guo-wei Shiehdc13abc2015-06-18 14:44:41 -0700364 // Prepare all the sockets beforehand. All of them will bind to "any" address.
365 while (sockets_.size() < total_socket_required()) {
kwiberg3ec46792016-04-27 07:22:53 -0700366 std::unique_ptr<rtc::AsyncPacketSocket> socket(
Guo-wei Shiehdc13abc2015-06-18 14:44:41 -0700367 socket_factory_->CreateUdpSocket(rtc::SocketAddress(INADDR_ANY, 0), 0,
368 0));
369 if (!socket) {
guoweis00507f82015-10-22 19:15:53 -0700370 ReportOnPrepared(GENERIC_FAILURE);
Guo-wei Shiehdc13abc2015-06-18 14:44:41 -0700371 return;
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700372 }
Guo-wei Shiehdc13abc2015-06-18 14:44:41 -0700373 // Chrome and WebRTC behave differently in terms of the state of a socket
374 // once returned from PacketSocketFactory::CreateUdpSocket.
375 if (socket->GetState() == rtc::AsyncPacketSocket::STATE_BINDING) {
376 socket->SignalAddressReady.connect(this, &StunProber::OnSocketReady);
377 } else {
378 OnSocketReady(socket.get(), rtc::SocketAddress(INADDR_ANY, 0));
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700379 }
Guo-wei Shiehdc13abc2015-06-18 14:44:41 -0700380 sockets_.push_back(socket.release());
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700381 }
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700382}
383
384StunProber::Requester* StunProber::CreateRequester() {
henrikg91d6ede2015-09-17 00:24:34 -0700385 RTC_DCHECK(thread_checker_.CalledOnValidThread());
Guo-wei Shiehdc13abc2015-06-18 14:44:41 -0700386 if (!sockets_.size()) {
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700387 return nullptr;
388 }
Guo-wei Shiehdc13abc2015-06-18 14:44:41 -0700389 StunProber::Requester* requester;
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700390 if (shared_socket_mode_) {
Guo-wei Shiehdc13abc2015-06-18 14:44:41 -0700391 requester = new Requester(this, sockets_.back(), all_servers_addrs_);
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700392 } else {
Guo-wei Shieh1ab67ae2015-05-18 21:36:20 -0700393 std::vector<rtc::SocketAddress> server_ip;
394 server_ip.push_back(
Guo-wei Shiehdc13abc2015-06-18 14:44:41 -0700395 all_servers_addrs_[(num_request_sent_ % all_servers_addrs_.size())]);
396 requester = new Requester(this, sockets_.back(), server_ip);
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700397 }
Guo-wei Shiehdc13abc2015-06-18 14:44:41 -0700398
399 sockets_.pop_back();
400 return requester;
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700401}
402
403bool StunProber::SendNextRequest() {
404 if (!current_requester_ || current_requester_->Done()) {
405 current_requester_ = CreateRequester();
406 requesters_.push_back(current_requester_);
407 }
408 if (!current_requester_) {
409 return false;
410 }
411 current_requester_->SendStunRequest();
412 num_request_sent_++;
413 return true;
414}
415
honghaiz34b11eb2016-03-16 08:55:44 -0700416bool StunProber::should_send_next_request(int64_t now) {
guoweis00507f82015-10-22 19:15:53 -0700417 if (interval_ms_ < THREAD_WAKE_UP_INTERVAL_MS) {
418 return now >= next_request_time_ms_;
419 } else {
420 return (now + (THREAD_WAKE_UP_INTERVAL_MS / 2)) >= next_request_time_ms_;
421 }
422}
423
424int StunProber::get_wake_up_interval_ms() {
425 if (interval_ms_ < THREAD_WAKE_UP_INTERVAL_MS) {
426 return 1;
427 } else {
428 return THREAD_WAKE_UP_INTERVAL_MS;
429 }
430}
431
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700432void StunProber::MaybeScheduleStunRequests() {
henrikg91d6ede2015-09-17 00:24:34 -0700433 RTC_DCHECK(thread_checker_.CalledOnValidThread());
nisse1bffc1d2016-05-02 08:18:55 -0700434 int64_t now = rtc::TimeMillis();
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700435
436 if (Done()) {
Guo-wei Shiehdc13abc2015-06-18 14:44:41 -0700437 invoker_.AsyncInvokeDelayed<void>(
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700438 RTC_FROM_HERE, thread_,
439 rtc::Bind(&StunProber::ReportOnFinished, this, SUCCESS), timeout_ms_);
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700440 return;
441 }
guoweis00507f82015-10-22 19:15:53 -0700442 if (should_send_next_request(now)) {
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700443 if (!SendNextRequest()) {
guoweis00507f82015-10-22 19:15:53 -0700444 ReportOnFinished(GENERIC_FAILURE);
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700445 return;
446 }
447 next_request_time_ms_ = now + interval_ms_;
448 }
Guo-wei Shiehdc13abc2015-06-18 14:44:41 -0700449 invoker_.AsyncInvokeDelayed<void>(
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700450 RTC_FROM_HERE, thread_,
451 rtc::Bind(&StunProber::MaybeScheduleStunRequests, this),
guoweis00507f82015-10-22 19:15:53 -0700452 get_wake_up_interval_ms());
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700453}
454
Guo-wei Shieh72e9f042015-06-08 21:03:48 -0700455bool StunProber::GetStats(StunProber::Stats* prob_stats) const {
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700456 // No need to be on the same thread.
457 if (!prob_stats) {
458 return false;
459 }
460
461 StunProber::Stats stats;
462
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700463 int rtt_sum = 0;
Peter Boström0c4e06b2015-10-07 12:23:21 +0200464 int64_t first_sent_time = 0;
465 int64_t last_sent_time = 0;
Guo-wei Shieh72e9f042015-06-08 21:03:48 -0700466 NatType nat_type = NATTYPE_INVALID;
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700467
Guo-wei Shieh1ab67ae2015-05-18 21:36:20 -0700468 // Track of how many srflx IP that we have seen.
469 std::set<rtc::IPAddress> srflx_ips;
470
471 // If we're not receiving any response on a given IP, all requests sent to
472 // that IP should be ignored as this could just be an DNS error.
Guo-wei Shieh72e9f042015-06-08 21:03:48 -0700473 std::map<rtc::IPAddress, int> num_response_per_server;
474 std::map<rtc::IPAddress, int> num_request_per_server;
Guo-wei Shieh1ab67ae2015-05-18 21:36:20 -0700475
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700476 for (auto* requester : requesters_) {
Guo-wei Shieh72e9f042015-06-08 21:03:48 -0700477 std::map<rtc::SocketAddress, int> num_response_per_srflx_addr;
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700478 for (auto request : requester->requests()) {
Guo-wei Shieh1ab67ae2015-05-18 21:36:20 -0700479 if (request->sent_time_ms <= 0) {
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700480 continue;
481 }
Guo-wei Shieh1ab67ae2015-05-18 21:36:20 -0700482
guoweis066ded92015-11-11 15:04:06 -0800483 ++stats.raw_num_request_sent;
Guo-wei Shieh72e9f042015-06-08 21:03:48 -0700484 IncrementCounterByAddress(&num_request_per_server, request->server_addr);
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700485
486 if (!first_sent_time) {
Guo-wei Shieh1ab67ae2015-05-18 21:36:20 -0700487 first_sent_time = request->sent_time_ms;
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700488 }
Guo-wei Shieh1ab67ae2015-05-18 21:36:20 -0700489 last_sent_time = request->sent_time_ms;
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700490
Guo-wei Shieh1ab67ae2015-05-18 21:36:20 -0700491 if (request->received_time_ms < request->sent_time_ms) {
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700492 continue;
493 }
Guo-wei Shieh1ab67ae2015-05-18 21:36:20 -0700494
Guo-wei Shieh72e9f042015-06-08 21:03:48 -0700495 IncrementCounterByAddress(&num_response_per_server, request->server_addr);
496 IncrementCounterByAddress(&num_response_per_srflx_addr,
497 request->srflx_addr);
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700498 rtt_sum += request->rtt();
Guo-wei Shieh1ab67ae2015-05-18 21:36:20 -0700499 stats.srflx_addrs.insert(request->srflx_addr.ToString());
500 srflx_ips.insert(request->srflx_addr.ipaddr());
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700501 }
Guo-wei Shieh72e9f042015-06-08 21:03:48 -0700502
503 // If we're using shared mode and seeing >1 srflx addresses for a single
504 // requester, it's symmetric NAT.
505 if (shared_socket_mode_ && num_response_per_srflx_addr.size() > 1) {
506 nat_type = NATTYPE_SYMMETRIC;
507 }
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700508 }
509
Guo-wei Shieh1ab67ae2015-05-18 21:36:20 -0700510 // We're probably not behind a regular NAT. We have more than 1 distinct
511 // server reflexive IPs.
512 if (srflx_ips.size() > 1) {
513 return false;
514 }
515
516 int num_sent = 0;
517 int num_received = 0;
518 int num_server_ip_with_response = 0;
519
Guo-wei Shieh72e9f042015-06-08 21:03:48 -0700520 for (const auto& kv : num_response_per_server) {
henrikg91d6ede2015-09-17 00:24:34 -0700521 RTC_DCHECK_GT(kv.second, 0);
Guo-wei Shieh1ab67ae2015-05-18 21:36:20 -0700522 num_server_ip_with_response++;
523 num_received += kv.second;
Guo-wei Shieh72e9f042015-06-08 21:03:48 -0700524 num_sent += num_request_per_server[kv.first];
Guo-wei Shieh1ab67ae2015-05-18 21:36:20 -0700525 }
526
Guo-wei Shieh1ab67ae2015-05-18 21:36:20 -0700527 // Shared mode is only true if we use the shared socket and there are more
528 // than 1 responding servers.
529 stats.shared_socket_mode =
530 shared_socket_mode_ && (num_server_ip_with_response > 1);
531
Guo-wei Shiehdc13abc2015-06-18 14:44:41 -0700532 if (stats.shared_socket_mode && nat_type == NATTYPE_INVALID) {
533 nat_type = NATTYPE_NON_SYMMETRIC;
Guo-wei Shieh72e9f042015-06-08 21:03:48 -0700534 }
535
Guo-wei Shiehdc13abc2015-06-18 14:44:41 -0700536 // If we could find a local IP matching srflx, we're not behind a NAT.
537 rtc::SocketAddress srflx_addr;
guoweis066ded92015-11-11 15:04:06 -0800538 if (stats.srflx_addrs.size() &&
539 !srflx_addr.FromString(*(stats.srflx_addrs.begin()))) {
Guo-wei Shiehdc13abc2015-06-18 14:44:41 -0700540 return false;
541 }
542 for (const auto& net : networks_) {
543 if (srflx_addr.ipaddr() == net->GetBestIP()) {
544 nat_type = stunprober::NATTYPE_NONE;
545 stats.host_ip = net->GetBestIP().ToString();
546 break;
547 }
548 }
549
550 // Finally, we know we're behind a NAT but can't determine which type it is.
551 if (nat_type == NATTYPE_INVALID) {
552 nat_type = NATTYPE_UNKNOWN;
553 }
554
555 stats.nat_type = nat_type;
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700556 stats.num_request_sent = num_sent;
557 stats.num_response_received = num_received;
558 stats.target_request_interval_ns = interval_ms_ * 1000;
559
560 if (num_sent) {
561 stats.success_percent = static_cast<int>(100 * num_received / num_sent);
562 }
563
guoweis066ded92015-11-11 15:04:06 -0800564 if (stats.raw_num_request_sent > 1) {
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700565 stats.actual_request_interval_ns =
guoweis066ded92015-11-11 15:04:06 -0800566 (1000 * (last_sent_time - first_sent_time)) /
567 (stats.raw_num_request_sent - 1);
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700568 }
569
570 if (num_received) {
571 stats.average_rtt_ms = static_cast<int>((rtt_sum / num_received));
572 }
573
574 *prob_stats = stats;
575 return true;
576}
577
guoweis00507f82015-10-22 19:15:53 -0700578void StunProber::ReportOnPrepared(StunProber::Status status) {
579 if (observer_) {
580 observer_->OnPrepared(this, status);
581 }
582}
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700583
guoweis00507f82015-10-22 19:15:53 -0700584void StunProber::ReportOnFinished(StunProber::Status status) {
585 if (observer_) {
586 observer_->OnFinished(this, status);
Guo-wei Shieh37931c42015-05-15 10:26:52 -0700587 }
588}
589
590} // namespace stunprober