OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2015 The WebRTC Project Authors. All rights reserved. | 2 * Copyright 2015 The WebRTC Project Authors. All rights reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 #include <iostream> | 11 #include <iostream> |
12 #include <map> | 12 #include <map> |
13 #include <set> | 13 #include <set> |
14 #include <string> | 14 #include <string> |
15 | 15 |
| 16 #include "webrtc/base/asyncpacketsocket.h" |
| 17 #include "webrtc/base/asyncresolverinterface.h" |
16 #include "webrtc/base/bind.h" | 18 #include "webrtc/base/bind.h" |
17 #include "webrtc/base/checks.h" | 19 #include "webrtc/base/checks.h" |
18 #include "webrtc/base/helpers.h" | 20 #include "webrtc/base/helpers.h" |
| 21 #include "webrtc/base/logging.h" |
19 #include "webrtc/base/timeutils.h" | 22 #include "webrtc/base/timeutils.h" |
| 23 #include "webrtc/base/thread.h" |
| 24 #include "webrtc/p2p/base/packetsocketfactory.h" |
20 #include "webrtc/p2p/base/stun.h" | 25 #include "webrtc/p2p/base/stun.h" |
21 #include "webrtc/p2p/stunprober/stunprober.h" | 26 #include "webrtc/p2p/stunprober/stunprober.h" |
22 | 27 |
23 namespace stunprober { | 28 namespace stunprober { |
24 | 29 |
25 namespace { | 30 namespace { |
26 | 31 |
| 32 const int thread_wake_up_interval_ms = 5; |
| 33 |
27 template <typename T> | 34 template <typename T> |
28 void IncrementCounterByAddress(std::map<T, int>* counter_per_ip, const T& ip) { | 35 void IncrementCounterByAddress(std::map<T, int>* counter_per_ip, const T& ip) { |
29 counter_per_ip->insert(std::make_pair(ip, 0)).first->second++; | 36 counter_per_ip->insert(std::make_pair(ip, 0)).first->second++; |
30 } | 37 } |
31 | 38 |
32 bool behind_nat(NatType nat_type) { | |
33 return nat_type > stunprober::NATTYPE_NONE; | |
34 } | |
35 | |
36 } // namespace | 39 } // namespace |
37 | 40 |
38 // A requester tracks the requests and responses from a single socket to many | 41 // A requester tracks the requests and responses from a single socket to many |
39 // STUN servers | 42 // STUN servers |
40 class StunProber::Requester { | 43 class StunProber::Requester : public sigslot::has_slots<> { |
41 public: | 44 public: |
42 // Each Request maps to a request and response. | 45 // Each Request maps to a request and response. |
43 struct Request { | 46 struct Request { |
44 // Actual time the STUN bind request was sent. | 47 // Actual time the STUN bind request was sent. |
45 int64 sent_time_ms = 0; | 48 int64 sent_time_ms = 0; |
46 // Time the response was received. | 49 // Time the response was received. |
47 int64 received_time_ms = 0; | 50 int64 received_time_ms = 0; |
48 | 51 |
49 // See whether the observed address returned matches the | |
50 // local address as in StunProber.local_addr_. | |
51 bool behind_nat = false; | |
52 | |
53 // Server reflexive address from STUN response for this given request. | 52 // Server reflexive address from STUN response for this given request. |
54 rtc::SocketAddress srflx_addr; | 53 rtc::SocketAddress srflx_addr; |
55 | 54 |
56 rtc::IPAddress server_addr; | 55 rtc::IPAddress server_addr; |
57 | 56 |
58 int64 rtt() { return received_time_ms - sent_time_ms; } | 57 int64 rtt() { return received_time_ms - sent_time_ms; } |
59 void ProcessResponse(rtc::ByteBuffer* message, | 58 void ProcessResponse(const char* buf, size_t buf_len); |
60 int buf_len, | |
61 const rtc::IPAddress& local_addr); | |
62 }; | 59 }; |
63 | 60 |
64 // StunProber provides |server_ips| for Requester to probe. For shared | 61 // StunProber provides |server_ips| for Requester to probe. For shared |
65 // socket mode, it'll be all the resolved IP addresses. For non-shared mode, | 62 // socket mode, it'll be all the resolved IP addresses. For non-shared mode, |
66 // it'll just be a single address. | 63 // it'll just be a single address. |
67 Requester(StunProber* prober, | 64 Requester(StunProber* prober, |
68 ServerSocketInterface* socket, | 65 rtc::AsyncPacketSocket* socket, |
69 const std::vector<rtc::SocketAddress>& server_ips); | 66 const std::vector<rtc::SocketAddress>& server_ips); |
70 virtual ~Requester(); | 67 virtual ~Requester(); |
71 | 68 |
72 // There is no callback for SendStunRequest as the underneath socket send is | 69 // There is no callback for SendStunRequest as the underneath socket send is |
73 // expected to be completed immediately. Otherwise, it'll skip this request | 70 // expected to be completed immediately. Otherwise, it'll skip this request |
74 // and move to the next one. | 71 // and move to the next one. |
75 void SendStunRequest(); | 72 void SendStunRequest(); |
76 | 73 |
77 void ReadStunResponse(); | 74 void OnStunResponseReceived(rtc::AsyncPacketSocket* socket, |
78 | 75 const char* buf, |
79 // |result| is the positive return value from RecvFrom when data is | 76 size_t size, |
80 // available. | 77 const rtc::SocketAddress& addr, |
81 void OnStunResponseReceived(int result); | 78 const rtc::PacketTime& time); |
82 | 79 |
83 const std::vector<Request*>& requests() { return requests_; } | 80 const std::vector<Request*>& requests() { return requests_; } |
84 | 81 |
85 // Whether this Requester has completed all requests. | 82 // Whether this Requester has completed all requests. |
86 bool Done() { | 83 bool Done() { |
87 return static_cast<size_t>(num_request_sent_) == server_ips_.size(); | 84 return static_cast<size_t>(num_request_sent_) == server_ips_.size(); |
88 } | 85 } |
89 | 86 |
90 private: | 87 private: |
91 Request* GetRequestByAddress(const rtc::IPAddress& ip); | 88 Request* GetRequestByAddress(const rtc::IPAddress& ip); |
92 | 89 |
93 StunProber* prober_; | 90 StunProber* prober_; |
94 | 91 |
95 // The socket for this session. | 92 // The socket for this session. |
96 rtc::scoped_ptr<ServerSocketInterface> socket_; | 93 rtc::scoped_ptr<rtc::AsyncPacketSocket> socket_; |
97 | 94 |
98 // Temporary SocketAddress and buffer for RecvFrom. | 95 // Temporary SocketAddress and buffer for RecvFrom. |
99 rtc::SocketAddress addr_; | 96 rtc::SocketAddress addr_; |
100 rtc::scoped_ptr<rtc::ByteBuffer> response_packet_; | 97 rtc::scoped_ptr<rtc::ByteBuffer> response_packet_; |
101 | 98 |
102 std::vector<Request*> requests_; | 99 std::vector<Request*> requests_; |
103 std::vector<rtc::SocketAddress> server_ips_; | 100 std::vector<rtc::SocketAddress> server_ips_; |
104 int16 num_request_sent_ = 0; | 101 int16 num_request_sent_ = 0; |
105 int16 num_response_received_ = 0; | 102 int16 num_response_received_ = 0; |
106 | 103 |
107 rtc::ThreadChecker& thread_checker_; | 104 rtc::ThreadChecker& thread_checker_; |
108 | 105 |
109 DISALLOW_COPY_AND_ASSIGN(Requester); | 106 DISALLOW_COPY_AND_ASSIGN(Requester); |
110 }; | 107 }; |
111 | 108 |
112 StunProber::Requester::Requester( | 109 StunProber::Requester::Requester( |
113 StunProber* prober, | 110 StunProber* prober, |
114 ServerSocketInterface* socket, | 111 rtc::AsyncPacketSocket* socket, |
115 const std::vector<rtc::SocketAddress>& server_ips) | 112 const std::vector<rtc::SocketAddress>& server_ips) |
116 : prober_(prober), | 113 : prober_(prober), |
117 socket_(socket), | 114 socket_(socket), |
118 response_packet_(new rtc::ByteBuffer(nullptr, kMaxUdpBufferSize)), | 115 response_packet_(new rtc::ByteBuffer(nullptr, kMaxUdpBufferSize)), |
119 server_ips_(server_ips), | 116 server_ips_(server_ips), |
120 thread_checker_(prober->thread_checker_) { | 117 thread_checker_(prober->thread_checker_) { |
| 118 socket_->SignalReadPacket.connect( |
| 119 this, &StunProber::Requester::OnStunResponseReceived); |
121 } | 120 } |
122 | 121 |
123 StunProber::Requester::~Requester() { | 122 StunProber::Requester::~Requester() { |
124 if (socket_) { | 123 if (socket_) { |
125 socket_->Close(); | 124 socket_->Close(); |
126 } | 125 } |
127 for (auto req : requests_) { | 126 for (auto req : requests_) { |
128 if (req) { | 127 if (req) { |
129 delete req; | 128 delete req; |
130 } | 129 } |
131 } | 130 } |
132 } | 131 } |
133 | 132 |
134 void StunProber::Requester::SendStunRequest() { | 133 void StunProber::Requester::SendStunRequest() { |
135 DCHECK(thread_checker_.CalledOnValidThread()); | 134 DCHECK(thread_checker_.CalledOnValidThread()); |
136 requests_.push_back(new Request()); | 135 requests_.push_back(new Request()); |
137 Request& request = *(requests_.back()); | 136 Request& request = *(requests_.back()); |
138 cricket::StunMessage message; | 137 cricket::StunMessage message; |
139 | 138 |
140 // Random transaction ID, STUN_BINDING_REQUEST | 139 // Random transaction ID, STUN_BINDING_REQUEST |
141 message.SetTransactionID( | 140 message.SetTransactionID( |
142 rtc::CreateRandomString(cricket::kStunTransactionIdLength)); | 141 rtc::CreateRandomString(cricket::kStunTransactionIdLength)); |
143 message.SetType(cricket::STUN_BINDING_REQUEST); | 142 message.SetType(cricket::STUN_BINDING_REQUEST); |
144 | 143 |
145 rtc::scoped_ptr<rtc::ByteBuffer> request_packet( | 144 rtc::scoped_ptr<rtc::ByteBuffer> request_packet( |
146 new rtc::ByteBuffer(nullptr, kMaxUdpBufferSize)); | 145 new rtc::ByteBuffer(nullptr, kMaxUdpBufferSize)); |
147 if (!message.Write(request_packet.get())) { | 146 if (!message.Write(request_packet.get())) { |
148 prober_->End(WRITE_FAILED, 0); | 147 prober_->End(WRITE_FAILED); |
149 return; | 148 return; |
150 } | 149 } |
151 | 150 |
152 auto addr = server_ips_[num_request_sent_]; | 151 auto addr = server_ips_[num_request_sent_]; |
153 request.server_addr = addr.ipaddr(); | 152 request.server_addr = addr.ipaddr(); |
154 | 153 |
155 // The write must succeed immediately. Otherwise, the calculating of the STUN | 154 // The write must succeed immediately. Otherwise, the calculating of the STUN |
156 // request timing could become too complicated. Callback is ignored by passing | 155 // request timing could become too complicated. Callback is ignored by passing |
157 // empty AsyncCallback. | 156 // empty AsyncCallback. |
158 int rv = socket_->SendTo(addr, const_cast<char*>(request_packet->Data()), | 157 rtc::PacketOptions options; |
159 request_packet->Length(), AsyncCallback()); | 158 int rv = socket_->SendTo(const_cast<char*>(request_packet->Data()), |
| 159 request_packet->Length(), addr, options); |
160 if (rv < 0) { | 160 if (rv < 0) { |
161 prober_->End(WRITE_FAILED, rv); | 161 prober_->End(WRITE_FAILED); |
162 return; | 162 return; |
163 } | 163 } |
164 | 164 |
165 request.sent_time_ms = rtc::Time(); | 165 request.sent_time_ms = rtc::Time(); |
166 | 166 |
167 // Post a read waiting for response. For share mode, the subsequent read will | |
168 // be posted inside OnStunResponseReceived. | |
169 if (num_request_sent_ == 0) { | |
170 ReadStunResponse(); | |
171 } | |
172 | |
173 num_request_sent_++; | 167 num_request_sent_++; |
174 DCHECK(static_cast<size_t>(num_request_sent_) <= server_ips_.size()); | 168 DCHECK(static_cast<size_t>(num_request_sent_) <= server_ips_.size()); |
175 } | 169 } |
176 | 170 |
177 void StunProber::Requester::ReadStunResponse() { | 171 void StunProber::Requester::Request::ProcessResponse(const char* buf, |
178 DCHECK(thread_checker_.CalledOnValidThread()); | 172 size_t buf_len) { |
179 if (!socket_) { | |
180 return; | |
181 } | |
182 | |
183 int rv = socket_->RecvFrom( | |
184 response_packet_->ReserveWriteBuffer(kMaxUdpBufferSize), | |
185 kMaxUdpBufferSize, &addr_, | |
186 [this](int result) { this->OnStunResponseReceived(result); }); | |
187 if (rv != SocketInterface::IO_PENDING) { | |
188 OnStunResponseReceived(rv); | |
189 } | |
190 } | |
191 | |
192 void StunProber::Requester::Request::ProcessResponse( | |
193 rtc::ByteBuffer* message, | |
194 int buf_len, | |
195 const rtc::IPAddress& local_addr) { | |
196 int64 now = rtc::Time(); | 173 int64 now = rtc::Time(); |
197 | 174 rtc::ByteBuffer message(buf, buf_len); |
198 cricket::StunMessage stun_response; | 175 cricket::StunMessage stun_response; |
199 if (!stun_response.Read(message)) { | 176 if (!stun_response.Read(&message)) { |
200 // Invalid or incomplete STUN packet. | 177 // Invalid or incomplete STUN packet. |
201 received_time_ms = 0; | 178 received_time_ms = 0; |
202 return; | 179 return; |
203 } | 180 } |
204 | 181 |
205 // Get external address of the socket. | 182 // Get external address of the socket. |
206 const cricket::StunAddressAttribute* addr_attr = | 183 const cricket::StunAddressAttribute* addr_attr = |
207 stun_response.GetAddress(cricket::STUN_ATTR_MAPPED_ADDRESS); | 184 stun_response.GetAddress(cricket::STUN_ATTR_MAPPED_ADDRESS); |
208 if (addr_attr == nullptr) { | 185 if (addr_attr == nullptr) { |
209 // Addresses not available to detect whether or not behind a NAT. | 186 // Addresses not available to detect whether or not behind a NAT. |
210 return; | 187 return; |
211 } | 188 } |
212 | 189 |
213 if (addr_attr->family() != cricket::STUN_ADDRESS_IPV4 && | 190 if (addr_attr->family() != cricket::STUN_ADDRESS_IPV4 && |
214 addr_attr->family() != cricket::STUN_ADDRESS_IPV6) { | 191 addr_attr->family() != cricket::STUN_ADDRESS_IPV6) { |
215 return; | 192 return; |
216 } | 193 } |
217 | 194 |
218 received_time_ms = now; | 195 received_time_ms = now; |
219 | 196 |
220 srflx_addr = addr_attr->GetAddress(); | 197 srflx_addr = addr_attr->GetAddress(); |
221 | |
222 // Calculate behind_nat. | |
223 behind_nat = (srflx_addr.ipaddr() != local_addr); | |
224 } | 198 } |
225 | 199 |
226 void StunProber::Requester::OnStunResponseReceived(int result) { | 200 void StunProber::Requester::OnStunResponseReceived( |
| 201 rtc::AsyncPacketSocket* socket, |
| 202 const char* buf, |
| 203 size_t size, |
| 204 const rtc::SocketAddress& addr, |
| 205 const rtc::PacketTime& time) { |
227 DCHECK(thread_checker_.CalledOnValidThread()); | 206 DCHECK(thread_checker_.CalledOnValidThread()); |
228 DCHECK(socket_); | 207 DCHECK(socket_); |
229 | 208 Request* request = GetRequestByAddress(addr.ipaddr()); |
230 if (result < 0) { | |
231 // Something is wrong, finish the test. | |
232 prober_->End(READ_FAILED, result); | |
233 return; | |
234 } | |
235 | |
236 Request* request = GetRequestByAddress(addr_.ipaddr()); | |
237 if (!request) { | 209 if (!request) { |
238 // Something is wrong, finish the test. | 210 // Something is wrong, finish the test. |
239 prober_->End(GENERIC_FAILURE, result); | 211 prober_->End(GENERIC_FAILURE); |
240 return; | 212 return; |
241 } | 213 } |
242 | 214 |
243 num_response_received_++; | 215 num_response_received_++; |
244 | 216 request->ProcessResponse(buf, size); |
245 // Resize will set the end_ to indicate that there are data available in this | |
246 // ByteBuffer. | |
247 response_packet_->Resize(result); | |
248 request->ProcessResponse(response_packet_.get(), result, | |
249 prober_->local_addr_); | |
250 | |
251 if (static_cast<size_t>(num_response_received_) < server_ips_.size()) { | |
252 // Post another read response. | |
253 ReadStunResponse(); | |
254 } | |
255 } | 217 } |
256 | 218 |
257 StunProber::Requester::Request* StunProber::Requester::GetRequestByAddress( | 219 StunProber::Requester::Request* StunProber::Requester::GetRequestByAddress( |
258 const rtc::IPAddress& ipaddr) { | 220 const rtc::IPAddress& ipaddr) { |
259 DCHECK(thread_checker_.CalledOnValidThread()); | 221 DCHECK(thread_checker_.CalledOnValidThread()); |
260 for (auto request : requests_) { | 222 for (auto request : requests_) { |
261 if (request->server_addr == ipaddr) { | 223 if (request->server_addr == ipaddr) { |
262 return request; | 224 return request; |
263 } | 225 } |
264 } | 226 } |
265 | 227 |
266 return nullptr; | 228 return nullptr; |
267 } | 229 } |
268 | 230 |
269 StunProber::StunProber(HostNameResolverInterface* host_name_resolver, | 231 StunProber::StunProber(rtc::PacketSocketFactory* socket_factory, |
270 SocketFactoryInterface* socket_factory, | 232 rtc::Thread* thread, |
271 TaskRunnerInterface* task_runner) | 233 const rtc::NetworkManager::NetworkList& networks) |
272 : interval_ms_(0), | 234 : interval_ms_(0), |
273 socket_factory_(socket_factory), | 235 socket_factory_(socket_factory), |
274 resolver_(host_name_resolver), | 236 thread_(thread), |
275 task_runner_(task_runner) { | 237 networks_(networks) { |
276 } | 238 } |
277 | 239 |
278 StunProber::~StunProber() { | 240 StunProber::~StunProber() { |
279 for (auto req : requesters_) { | 241 for (auto req : requesters_) { |
280 if (req) { | 242 if (req) { |
281 delete req; | 243 delete req; |
282 } | 244 } |
283 } | 245 } |
| 246 for (auto s : sockets_) { |
| 247 if (s) { |
| 248 delete s; |
| 249 } |
| 250 } |
284 } | 251 } |
285 | 252 |
286 bool StunProber::Start(const std::vector<rtc::SocketAddress>& servers, | 253 bool StunProber::Start(const std::vector<rtc::SocketAddress>& servers, |
287 bool shared_socket_mode, | 254 bool shared_socket_mode, |
288 int interval_ms, | 255 int interval_ms, |
289 int num_request_per_ip, | 256 int num_request_per_ip, |
290 int timeout_ms, | 257 int timeout_ms, |
291 const AsyncCallback callback) { | 258 const AsyncCallback callback) { |
292 DCHECK(thread_checker_.CalledOnValidThread()); | 259 DCHECK(thread_checker_.CalledOnValidThread()); |
293 interval_ms_ = interval_ms; | 260 interval_ms_ = interval_ms; |
294 shared_socket_mode_ = shared_socket_mode; | 261 shared_socket_mode_ = shared_socket_mode; |
295 | 262 |
296 requests_per_ip_ = num_request_per_ip; | 263 requests_per_ip_ = num_request_per_ip; |
297 if (requests_per_ip_ == 0 || servers.size() == 0) { | 264 if (requests_per_ip_ == 0 || servers.size() == 0) { |
298 return false; | 265 return false; |
299 } | 266 } |
300 | 267 |
301 timeout_ms_ = timeout_ms; | 268 timeout_ms_ = timeout_ms; |
302 servers_ = servers; | 269 servers_ = servers; |
303 finished_callback_ = callback; | 270 finished_callback_ = callback; |
304 resolver_->Resolve(servers_[0], &resolved_ips_, | 271 return ResolveServerName(servers_.back()); |
305 [this](int result) { this->OnServerResolved(0, result); }); | 272 } |
| 273 |
| 274 bool StunProber::ResolveServerName(const rtc::SocketAddress& addr) { |
| 275 rtc::AsyncResolverInterface* resolver = |
| 276 socket_factory_->CreateAsyncResolver(); |
| 277 if (!resolver) { |
| 278 return false; |
| 279 } |
| 280 resolver->SignalDone.connect(this, &StunProber::OnServerResolved); |
| 281 resolver->Start(addr); |
306 return true; | 282 return true; |
307 } | 283 } |
308 | 284 |
309 void StunProber::OnServerResolved(int index, int result) { | 285 void StunProber::OnSocketReady(rtc::AsyncPacketSocket* socket, |
| 286 const rtc::SocketAddress& addr) { |
| 287 total_ready_sockets_++; |
| 288 if (total_ready_sockets_ == total_socket_required()) { |
| 289 MaybeScheduleStunRequests(); |
| 290 } |
| 291 } |
| 292 |
| 293 void StunProber::OnServerResolved(rtc::AsyncResolverInterface* resolver) { |
310 DCHECK(thread_checker_.CalledOnValidThread()); | 294 DCHECK(thread_checker_.CalledOnValidThread()); |
311 | 295 |
312 if (result == 0) { | 296 if (resolver->GetError() == 0) { |
313 all_servers_ips_.insert(all_servers_ips_.end(), resolved_ips_.begin(), | 297 rtc::SocketAddress addr(resolver->address().ipaddr(), |
314 resolved_ips_.end()); | 298 resolver->address().port()); |
315 resolved_ips_.clear(); | 299 all_servers_addrs_.push_back(addr); |
316 } | 300 } |
317 | 301 |
318 index++; | 302 // Deletion of AsyncResolverInterface can't be done in OnResolveResult which |
| 303 // handles SignalDone. |
| 304 invoker_.AsyncInvoke<void>( |
| 305 thread_, |
| 306 rtc::Bind(&rtc::AsyncResolverInterface::Destroy, resolver, false)); |
| 307 servers_.pop_back(); |
319 | 308 |
320 if (static_cast<size_t>(index) < servers_.size()) { | 309 if (servers_.size()) { |
321 resolver_->Resolve( | 310 if (!ResolveServerName(servers_.back())) { |
322 servers_[index], &resolved_ips_, | 311 End(RESOLVE_FAILED); |
323 [this, index](int result) { this->OnServerResolved(index, result); }); | 312 } |
324 return; | 313 return; |
325 } | 314 } |
326 | 315 |
327 if (all_servers_ips_.size() == 0) { | 316 if (all_servers_addrs_.size() == 0) { |
328 End(RESOLVE_FAILED, result); | 317 End(RESOLVE_FAILED); |
329 return; | 318 return; |
330 } | 319 } |
331 | 320 |
332 // Dedupe. | 321 // Dedupe. |
333 std::set<rtc::SocketAddress> addrs(all_servers_ips_.begin(), | 322 std::set<rtc::SocketAddress> addrs(all_servers_addrs_.begin(), |
334 all_servers_ips_.end()); | 323 all_servers_addrs_.end()); |
335 all_servers_ips_.assign(addrs.begin(), addrs.end()); | 324 all_servers_addrs_.assign(addrs.begin(), addrs.end()); |
336 | 325 |
337 rtc::IPAddress addr; | 326 // Prepare all the sockets beforehand. All of them will bind to "any" address. |
338 if (GetLocalAddress(&addr) != 0) { | 327 while (sockets_.size() < total_socket_required()) { |
339 End(GENERIC_FAILURE, result); | 328 rtc::scoped_ptr<rtc::AsyncPacketSocket> socket( |
340 return; | 329 socket_factory_->CreateUdpSocket(rtc::SocketAddress(INADDR_ANY, 0), 0, |
| 330 0)); |
| 331 if (!socket) { |
| 332 End(GENERIC_FAILURE); |
| 333 return; |
| 334 } |
| 335 // Chrome and WebRTC behave differently in terms of the state of a socket |
| 336 // once returned from PacketSocketFactory::CreateUdpSocket. |
| 337 if (socket->GetState() == rtc::AsyncPacketSocket::STATE_BINDING) { |
| 338 socket->SignalAddressReady.connect(this, &StunProber::OnSocketReady); |
| 339 } else { |
| 340 OnSocketReady(socket.get(), rtc::SocketAddress(INADDR_ANY, 0)); |
| 341 } |
| 342 sockets_.push_back(socket.release()); |
341 } | 343 } |
342 | |
343 socket_factory_->Prepare(GetTotalClientSockets(), GetTotalServerSockets(), | |
344 [this](int result) { | |
345 if (result == 0) { | |
346 this->MaybeScheduleStunRequests(); | |
347 } | |
348 }); | |
349 } | |
350 | |
351 int StunProber::GetLocalAddress(rtc::IPAddress* addr) { | |
352 DCHECK(thread_checker_.CalledOnValidThread()); | |
353 if (local_addr_.family() == AF_UNSPEC) { | |
354 rtc::SocketAddress sock_addr; | |
355 rtc::scoped_ptr<ClientSocketInterface> socket( | |
356 socket_factory_->CreateClientSocket()); | |
357 int rv = socket->Connect(all_servers_ips_[0]); | |
358 if (rv != SUCCESS) { | |
359 End(GENERIC_FAILURE, rv); | |
360 return rv; | |
361 } | |
362 rv = socket->GetLocalAddress(&sock_addr); | |
363 if (rv != SUCCESS) { | |
364 End(GENERIC_FAILURE, rv); | |
365 return rv; | |
366 } | |
367 local_addr_ = sock_addr.ipaddr(); | |
368 socket->Close(); | |
369 } | |
370 *addr = local_addr_; | |
371 return 0; | |
372 } | 344 } |
373 | 345 |
374 StunProber::Requester* StunProber::CreateRequester() { | 346 StunProber::Requester* StunProber::CreateRequester() { |
375 DCHECK(thread_checker_.CalledOnValidThread()); | 347 DCHECK(thread_checker_.CalledOnValidThread()); |
376 rtc::scoped_ptr<ServerSocketInterface> socket( | 348 if (!sockets_.size()) { |
377 socket_factory_->CreateServerSocket(kMaxUdpBufferSize, | |
378 kMaxUdpBufferSize)); | |
379 if (!socket) { | |
380 return nullptr; | 349 return nullptr; |
381 } | 350 } |
| 351 StunProber::Requester* requester; |
382 if (shared_socket_mode_) { | 352 if (shared_socket_mode_) { |
383 return new Requester(this, socket.release(), all_servers_ips_); | 353 requester = new Requester(this, sockets_.back(), all_servers_addrs_); |
384 } else { | 354 } else { |
385 std::vector<rtc::SocketAddress> server_ip; | 355 std::vector<rtc::SocketAddress> server_ip; |
386 server_ip.push_back( | 356 server_ip.push_back( |
387 all_servers_ips_[(num_request_sent_ % all_servers_ips_.size())]); | 357 all_servers_addrs_[(num_request_sent_ % all_servers_addrs_.size())]); |
388 return new Requester(this, socket.release(), server_ip); | 358 requester = new Requester(this, sockets_.back(), server_ip); |
389 } | 359 } |
| 360 |
| 361 sockets_.pop_back(); |
| 362 return requester; |
390 } | 363 } |
391 | 364 |
392 bool StunProber::SendNextRequest() { | 365 bool StunProber::SendNextRequest() { |
393 if (!current_requester_ || current_requester_->Done()) { | 366 if (!current_requester_ || current_requester_->Done()) { |
394 current_requester_ = CreateRequester(); | 367 current_requester_ = CreateRequester(); |
395 requesters_.push_back(current_requester_); | 368 requesters_.push_back(current_requester_); |
396 } | 369 } |
397 if (!current_requester_) { | 370 if (!current_requester_) { |
398 return false; | 371 return false; |
399 } | 372 } |
400 current_requester_->SendStunRequest(); | 373 current_requester_->SendStunRequest(); |
401 num_request_sent_++; | 374 num_request_sent_++; |
402 return true; | 375 return true; |
403 } | 376 } |
404 | 377 |
405 void StunProber::MaybeScheduleStunRequests() { | 378 void StunProber::MaybeScheduleStunRequests() { |
406 DCHECK(thread_checker_.CalledOnValidThread()); | 379 DCHECK(thread_checker_.CalledOnValidThread()); |
407 uint32 now = rtc::Time(); | 380 uint32 now = rtc::Time(); |
408 | 381 |
409 if (Done()) { | 382 if (Done()) { |
410 task_runner_->PostTask(rtc::Bind(&StunProber::End, this, SUCCESS, 0), | 383 invoker_.AsyncInvokeDelayed<void>( |
411 timeout_ms_); | 384 thread_, rtc::Bind(&StunProber::End, this, SUCCESS), timeout_ms_); |
412 return; | 385 return; |
413 } | 386 } |
414 if (now >= next_request_time_ms_) { | 387 if ((now + (thread_wake_up_interval_ms / 2)) >= next_request_time_ms_) { |
415 if (!SendNextRequest()) { | 388 if (!SendNextRequest()) { |
416 End(GENERIC_FAILURE, 0); | 389 End(GENERIC_FAILURE); |
417 return; | 390 return; |
418 } | 391 } |
419 next_request_time_ms_ = now + interval_ms_; | 392 next_request_time_ms_ = now + interval_ms_; |
420 } | 393 } |
421 task_runner_->PostTask( | 394 invoker_.AsyncInvokeDelayed<void>( |
422 rtc::Bind(&StunProber::MaybeScheduleStunRequests, this), 1 /* ms */); | 395 thread_, rtc::Bind(&StunProber::MaybeScheduleStunRequests, this), |
| 396 thread_wake_up_interval_ms /* ms */); |
423 } | 397 } |
424 | 398 |
425 bool StunProber::GetStats(StunProber::Stats* prob_stats) const { | 399 bool StunProber::GetStats(StunProber::Stats* prob_stats) const { |
426 // No need to be on the same thread. | 400 // No need to be on the same thread. |
427 if (!prob_stats) { | 401 if (!prob_stats) { |
428 return false; | 402 return false; |
429 } | 403 } |
430 | 404 |
431 StunProber::Stats stats; | 405 StunProber::Stats stats; |
432 | 406 |
(...skipping 24 matching lines...) Expand all Loading... |
457 } | 431 } |
458 last_sent_time = request->sent_time_ms; | 432 last_sent_time = request->sent_time_ms; |
459 | 433 |
460 if (request->received_time_ms < request->sent_time_ms) { | 434 if (request->received_time_ms < request->sent_time_ms) { |
461 continue; | 435 continue; |
462 } | 436 } |
463 | 437 |
464 IncrementCounterByAddress(&num_response_per_server, request->server_addr); | 438 IncrementCounterByAddress(&num_response_per_server, request->server_addr); |
465 IncrementCounterByAddress(&num_response_per_srflx_addr, | 439 IncrementCounterByAddress(&num_response_per_srflx_addr, |
466 request->srflx_addr); | 440 request->srflx_addr); |
467 | |
468 rtt_sum += request->rtt(); | 441 rtt_sum += request->rtt(); |
469 if (nat_type == NATTYPE_INVALID) { | |
470 nat_type = request->behind_nat ? NATTYPE_UNKNOWN : NATTYPE_NONE; | |
471 } else if (behind_nat(nat_type) != request->behind_nat) { | |
472 // Detect the inconsistency in NAT presence. | |
473 return false; | |
474 } | |
475 stats.srflx_addrs.insert(request->srflx_addr.ToString()); | 442 stats.srflx_addrs.insert(request->srflx_addr.ToString()); |
476 srflx_ips.insert(request->srflx_addr.ipaddr()); | 443 srflx_ips.insert(request->srflx_addr.ipaddr()); |
477 } | 444 } |
478 | 445 |
479 // If we're using shared mode and seeing >1 srflx addresses for a single | 446 // If we're using shared mode and seeing >1 srflx addresses for a single |
480 // requester, it's symmetric NAT. | 447 // requester, it's symmetric NAT. |
481 if (shared_socket_mode_ && num_response_per_srflx_addr.size() > 1) { | 448 if (shared_socket_mode_ && num_response_per_srflx_addr.size() > 1) { |
482 nat_type = NATTYPE_SYMMETRIC; | 449 nat_type = NATTYPE_SYMMETRIC; |
483 } | 450 } |
484 } | 451 } |
(...skipping 13 matching lines...) Expand all Loading... |
498 num_server_ip_with_response++; | 465 num_server_ip_with_response++; |
499 num_received += kv.second; | 466 num_received += kv.second; |
500 num_sent += num_request_per_server[kv.first]; | 467 num_sent += num_request_per_server[kv.first]; |
501 } | 468 } |
502 | 469 |
503 // Not receiving any response, the trial is inconclusive. | 470 // Not receiving any response, the trial is inconclusive. |
504 if (!num_received) { | 471 if (!num_received) { |
505 return false; | 472 return false; |
506 } | 473 } |
507 | 474 |
508 stats.nat_type = nat_type; | |
509 | |
510 // Shared mode is only true if we use the shared socket and there are more | 475 // Shared mode is only true if we use the shared socket and there are more |
511 // than 1 responding servers. | 476 // than 1 responding servers. |
512 stats.shared_socket_mode = | 477 stats.shared_socket_mode = |
513 shared_socket_mode_ && (num_server_ip_with_response > 1); | 478 shared_socket_mode_ && (num_server_ip_with_response > 1); |
514 | 479 |
515 if (stats.shared_socket_mode && nat_type == NATTYPE_UNKNOWN) { | 480 if (stats.shared_socket_mode && nat_type == NATTYPE_INVALID) { |
516 stats.nat_type = NATTYPE_NON_SYMMETRIC; | 481 nat_type = NATTYPE_NON_SYMMETRIC; |
517 } | 482 } |
518 | 483 |
519 stats.host_ip = local_addr_.ToString(); | 484 // If we could find a local IP matching srflx, we're not behind a NAT. |
| 485 rtc::SocketAddress srflx_addr; |
| 486 if (!srflx_addr.FromString(*(stats.srflx_addrs.begin()))) { |
| 487 return false; |
| 488 } |
| 489 for (const auto& net : networks_) { |
| 490 if (srflx_addr.ipaddr() == net->GetBestIP()) { |
| 491 nat_type = stunprober::NATTYPE_NONE; |
| 492 stats.host_ip = net->GetBestIP().ToString(); |
| 493 break; |
| 494 } |
| 495 } |
| 496 |
| 497 // Finally, we know we're behind a NAT but can't determine which type it is. |
| 498 if (nat_type == NATTYPE_INVALID) { |
| 499 nat_type = NATTYPE_UNKNOWN; |
| 500 } |
| 501 |
| 502 stats.nat_type = nat_type; |
520 stats.num_request_sent = num_sent; | 503 stats.num_request_sent = num_sent; |
521 stats.num_response_received = num_received; | 504 stats.num_response_received = num_received; |
522 stats.target_request_interval_ns = interval_ms_ * 1000; | 505 stats.target_request_interval_ns = interval_ms_ * 1000; |
523 | 506 |
524 if (num_sent) { | 507 if (num_sent) { |
525 stats.success_percent = static_cast<int>(100 * num_received / num_sent); | 508 stats.success_percent = static_cast<int>(100 * num_received / num_sent); |
526 } | 509 } |
527 | 510 |
528 if (num_sent > 1) { | 511 if (num_sent > 1) { |
529 stats.actual_request_interval_ns = | 512 stats.actual_request_interval_ns = |
530 (1000 * (last_sent_time - first_sent_time)) / (num_sent - 1); | 513 (1000 * (last_sent_time - first_sent_time)) / (num_sent - 1); |
531 } | 514 } |
532 | 515 |
533 if (num_received) { | 516 if (num_received) { |
534 stats.average_rtt_ms = static_cast<int>((rtt_sum / num_received)); | 517 stats.average_rtt_ms = static_cast<int>((rtt_sum / num_received)); |
535 } | 518 } |
536 | 519 |
537 *prob_stats = stats; | 520 *prob_stats = stats; |
538 return true; | 521 return true; |
539 } | 522 } |
540 | 523 |
541 void StunProber::End(StunProber::Status status, int result) { | 524 void StunProber::End(StunProber::Status status) { |
542 DCHECK(thread_checker_.CalledOnValidThread()); | 525 DCHECK(thread_checker_.CalledOnValidThread()); |
543 if (!finished_callback_.empty()) { | 526 if (!finished_callback_.empty()) { |
544 AsyncCallback callback = finished_callback_; | 527 AsyncCallback callback = finished_callback_; |
545 finished_callback_ = AsyncCallback(); | 528 finished_callback_ = AsyncCallback(); |
546 | 529 |
547 // Callback at the last since the prober might be deleted in the callback. | 530 // Callback at the last since the prober might be deleted in the callback. |
548 callback(status); | 531 callback(this, status); |
549 } | 532 } |
550 } | 533 } |
551 | 534 |
552 } // namespace stunprober | 535 } // namespace stunprober |
OLD | NEW |