Chromium Code Reviews| 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 |