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