| OLD | NEW |
| 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/base/host_resolver.h" | 5 #include "net/base/host_resolver_impl.h" |
| 6 | 6 |
| 7 #if defined(OS_WIN) | 7 #if defined(OS_WIN) |
| 8 #include <ws2tcpip.h> | 8 #include <ws2tcpip.h> |
| 9 #include <wspiapi.h> // Needed for Win2k compat. | 9 #include <wspiapi.h> // Needed for Win2k compat. |
| 10 #elif defined(OS_POSIX) | 10 #elif defined(OS_POSIX) |
| 11 #include <netdb.h> | 11 #include <netdb.h> |
| 12 #include <sys/socket.h> | 12 #include <sys/socket.h> |
| 13 #endif | 13 #endif |
| 14 #if defined(OS_LINUX) | 14 #if defined(OS_LINUX) |
| 15 #include <resolv.h> | 15 #include <resolv.h> |
| 16 #endif | 16 #endif |
| 17 | 17 |
| 18 #include "base/compiler_specific.h" | 18 #include "base/compiler_specific.h" |
| 19 #include "base/message_loop.h" | 19 #include "base/message_loop.h" |
| 20 #include "base/stl_util-inl.h" | 20 #include "base/stl_util-inl.h" |
| 21 #include "base/string_util.h" | 21 #include "base/string_util.h" |
| 22 #include "base/time.h" | 22 #include "base/time.h" |
| 23 #include "base/worker_pool.h" | 23 #include "base/worker_pool.h" |
| 24 #include "net/base/address_list.h" | 24 #include "net/base/address_list.h" |
| 25 #include "net/base/host_resolver_proc.h" |
| 25 #include "net/base/net_errors.h" | 26 #include "net/base/net_errors.h" |
| 26 | 27 |
| 27 #if defined(OS_LINUX) | |
| 28 #include "base/singleton.h" | |
| 29 #include "base/thread_local_storage.h" | |
| 30 #endif | |
| 31 | |
| 32 #if defined(OS_WIN) | 28 #if defined(OS_WIN) |
| 33 #include "net/base/winsock_init.h" | 29 #include "net/base/winsock_init.h" |
| 34 #endif | 30 #endif |
| 35 | 31 |
| 36 namespace net { | 32 namespace net { |
| 37 | 33 |
| 38 //----------------------------------------------------------------------------- | 34 HostResolver* CreateSystemHostResolver() { |
| 39 | 35 static const size_t kMaxHostCacheEntries = 100; |
| 40 static HostMapper* host_mapper; | 36 static const size_t kHostCacheExpirationMs = 60000; // 1 minute. |
| 41 | 37 return new HostResolverImpl( |
| 42 std::string HostMapper::MapUsingPrevious(const std::string& host) { | 38 NULL, kMaxHostCacheEntries, kHostCacheExpirationMs); |
| 43 return previous_mapper_.get() ? previous_mapper_->Map(host) : host; | |
| 44 } | 39 } |
| 45 | 40 |
| 46 HostMapper* SetHostMapper(HostMapper* value) { | 41 static int ResolveAddrInfo(HostResolverProc* resolver_proc, |
| 47 std::swap(host_mapper, value); | 42 const std::string& host, AddressList* out) { |
| 48 return value; | 43 if (resolver_proc) { |
| 49 } | 44 // Use the custom procedure. |
| 50 | 45 return resolver_proc->Resolve(host, out); |
| 51 #if defined(OS_LINUX) | |
| 52 // On Linux changes to /etc/resolv.conf can go unnoticed thus resulting in | |
| 53 // DNS queries failing either because nameservers are unknown on startup | |
| 54 // or because nameserver info has changed as a result of e.g. connecting to | |
| 55 // a new network. Some distributions patch glibc to stat /etc/resolv.conf | |
| 56 // to try to automatically detect such changes but these patches are not | |
| 57 // universal and even patched systems such as Jaunty appear to need calls | |
| 58 // to res_ninit to reload the nameserver information in different threads. | |
| 59 // | |
| 60 // We adopt the Mozilla solution here which is to call res_ninit when | |
| 61 // lookups fail and to rate limit the reloading to once per second per | |
| 62 // thread. | |
| 63 | |
| 64 // Keep a timer per calling thread to rate limit the calling of res_ninit. | |
| 65 class DnsReloadTimer { | |
| 66 public: | |
| 67 DnsReloadTimer() { | |
| 68 tls_index_.Initialize(SlotReturnFunction); | |
| 69 } | |
| 70 | |
| 71 ~DnsReloadTimer() { } | |
| 72 | |
| 73 // Check if the timer for the calling thread has expired. When no | |
| 74 // timer exists for the calling thread, create one. | |
| 75 bool Expired() { | |
| 76 const base::TimeDelta kRetryTime = base::TimeDelta::FromSeconds(1); | |
| 77 base::TimeTicks now = base::TimeTicks::Now(); | |
| 78 base::TimeTicks* timer_ptr = | |
| 79 static_cast<base::TimeTicks*>(tls_index_.Get()); | |
| 80 | |
| 81 if (!timer_ptr) { | |
| 82 timer_ptr = new base::TimeTicks(); | |
| 83 *timer_ptr = base::TimeTicks::Now(); | |
| 84 tls_index_.Set(timer_ptr); | |
| 85 // Return true to reload dns info on the first call for each thread. | |
| 86 return true; | |
| 87 } else if (now - *timer_ptr > kRetryTime) { | |
| 88 *timer_ptr = now; | |
| 89 return true; | |
| 90 } else { | |
| 91 return false; | |
| 92 } | |
| 93 } | |
| 94 | |
| 95 // Free the allocated timer. | |
| 96 static void SlotReturnFunction(void* data) { | |
| 97 base::TimeTicks* tls_data = static_cast<base::TimeTicks*>(data); | |
| 98 delete tls_data; | |
| 99 } | |
| 100 | |
| 101 private: | |
| 102 // We use thread local storage to identify which base::TimeTicks to | |
| 103 // interact with. | |
| 104 static ThreadLocalStorage::Slot tls_index_ ; | |
| 105 | |
| 106 DISALLOW_COPY_AND_ASSIGN(DnsReloadTimer); | |
| 107 }; | |
| 108 | |
| 109 // A TLS slot to the TimeTicks for the current thread. | |
| 110 // static | |
| 111 ThreadLocalStorage::Slot DnsReloadTimer::tls_index_(base::LINKER_INITIALIZED); | |
| 112 | |
| 113 #endif // defined(OS_LINUX) | |
| 114 | |
| 115 static int HostResolverProc(const std::string& host, struct addrinfo** out) { | |
| 116 struct addrinfo hints = {0}; | |
| 117 hints.ai_family = AF_UNSPEC; | |
| 118 | |
| 119 #if defined(OS_WIN) | |
| 120 // DO NOT USE AI_ADDRCONFIG ON WINDOWS. | |
| 121 // | |
| 122 // The following comment in <winsock2.h> is the best documentation I found | |
| 123 // on AI_ADDRCONFIG for Windows: | |
| 124 // Flags used in "hints" argument to getaddrinfo() | |
| 125 // - AI_ADDRCONFIG is supported starting with Vista | |
| 126 // - default is AI_ADDRCONFIG ON whether the flag is set or not | |
| 127 // because the performance penalty in not having ADDRCONFIG in | |
| 128 // the multi-protocol stack environment is severe; | |
| 129 // this defaulting may be disabled by specifying the AI_ALL flag, | |
| 130 // in that case AI_ADDRCONFIG must be EXPLICITLY specified to | |
| 131 // enable ADDRCONFIG behavior | |
| 132 // | |
| 133 // Not only is AI_ADDRCONFIG unnecessary, but it can be harmful. If the | |
| 134 // computer is not connected to a network, AI_ADDRCONFIG causes getaddrinfo | |
| 135 // to fail with WSANO_DATA (11004) for "localhost", probably because of the | |
| 136 // following note on AI_ADDRCONFIG in the MSDN getaddrinfo page: | |
| 137 // The IPv4 or IPv6 loopback address is not considered a valid global | |
| 138 // address. | |
| 139 // See http://crbug.com/5234. | |
| 140 hints.ai_flags = 0; | |
| 141 #else | |
| 142 hints.ai_flags = AI_ADDRCONFIG; | |
| 143 #endif | |
| 144 | |
| 145 // Restrict result set to only this socket type to avoid duplicates. | |
| 146 hints.ai_socktype = SOCK_STREAM; | |
| 147 | |
| 148 int err = getaddrinfo(host.c_str(), NULL, &hints, out); | |
| 149 #if defined(OS_LINUX) | |
| 150 net::DnsReloadTimer* dns_timer = Singleton<net::DnsReloadTimer>::get(); | |
| 151 // If we fail, re-initialise the resolver just in case there have been any | |
| 152 // changes to /etc/resolv.conf and retry. See http://crbug.com/11380 for info. | |
| 153 if (err && dns_timer->Expired()) { | |
| 154 res_nclose(&_res); | |
| 155 if (!res_ninit(&_res)) | |
| 156 err = getaddrinfo(host.c_str(), NULL, &hints, out); | |
| 157 } | |
| 158 #endif | |
| 159 | |
| 160 return err ? ERR_NAME_NOT_RESOLVED : OK; | |
| 161 } | |
| 162 | |
| 163 static int ResolveAddrInfo(HostMapper* mapper, const std::string& host, | |
| 164 struct addrinfo** out) { | |
| 165 if (mapper) { | |
| 166 std::string mapped_host = mapper->Map(host); | |
| 167 | |
| 168 if (mapped_host.empty()) | |
| 169 return ERR_NAME_NOT_RESOLVED; | |
| 170 | |
| 171 return HostResolverProc(mapped_host, out); | |
| 172 } else { | 46 } else { |
| 173 return HostResolverProc(host, out); | 47 // Use the system procedure (getaddrinfo). |
| 48 return SystemHostResolverProc(host, out); |
| 174 } | 49 } |
| 175 } | 50 } |
| 176 | 51 |
| 177 //----------------------------------------------------------------------------- | 52 //----------------------------------------------------------------------------- |
| 178 | 53 |
| 179 class HostResolver::Request { | 54 class HostResolverImpl::Request { |
| 180 public: | 55 public: |
| 181 Request(int id, const RequestInfo& info, CompletionCallback* callback, | 56 Request(int id, const RequestInfo& info, CompletionCallback* callback, |
| 182 AddressList* addresses) | 57 AddressList* addresses) |
| 183 : id_(id), info_(info), job_(NULL), callback_(callback), | 58 : id_(id), info_(info), job_(NULL), callback_(callback), |
| 184 addresses_(addresses) {} | 59 addresses_(addresses) {} |
| 185 | 60 |
| 186 // Mark the request as cancelled. | 61 // Mark the request as cancelled. |
| 187 void MarkAsCancelled() { | 62 void MarkAsCancelled() { |
| 188 job_ = NULL; | 63 job_ = NULL; |
| 189 callback_ = NULL; | 64 callback_ = NULL; |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 238 // The address list to save result into. | 113 // The address list to save result into. |
| 239 AddressList* addresses_; | 114 AddressList* addresses_; |
| 240 | 115 |
| 241 DISALLOW_COPY_AND_ASSIGN(Request); | 116 DISALLOW_COPY_AND_ASSIGN(Request); |
| 242 }; | 117 }; |
| 243 | 118 |
| 244 //----------------------------------------------------------------------------- | 119 //----------------------------------------------------------------------------- |
| 245 | 120 |
| 246 // This class represents a request to the worker pool for a "getaddrinfo()" | 121 // This class represents a request to the worker pool for a "getaddrinfo()" |
| 247 // call. | 122 // call. |
| 248 class HostResolver::Job : public base::RefCountedThreadSafe<HostResolver::Job> { | 123 class HostResolverImpl::Job |
| 124 : public base::RefCountedThreadSafe<HostResolverImpl::Job> { |
| 249 public: | 125 public: |
| 250 Job(HostResolver* resolver, const std::string& host) | 126 Job(HostResolverImpl* resolver, const std::string& host) |
| 251 : host_(host), | 127 : host_(host), |
| 252 resolver_(resolver), | 128 resolver_(resolver), |
| 253 origin_loop_(MessageLoop::current()), | 129 origin_loop_(MessageLoop::current()), |
| 254 host_mapper_(host_mapper), | 130 resolver_proc_(resolver->effective_resolver_proc()), |
| 255 error_(OK), | 131 error_(OK) { |
| 256 results_(NULL) { | |
| 257 } | 132 } |
| 258 | 133 |
| 259 ~Job() { | 134 ~Job() { |
| 260 if (results_) | |
| 261 freeaddrinfo(results_); | |
| 262 | |
| 263 // Free the requests attached to this job. | 135 // Free the requests attached to this job. |
| 264 STLDeleteElements(&requests_); | 136 STLDeleteElements(&requests_); |
| 265 } | 137 } |
| 266 | 138 |
| 267 // Attaches a request to this job. The job takes ownership of |req| and will | 139 // Attaches a request to this job. The job takes ownership of |req| and will |
| 268 // take care to delete it. | 140 // take care to delete it. |
| 269 void AddRequest(HostResolver::Request* req) { | 141 void AddRequest(Request* req) { |
| 270 req->set_job(this); | 142 req->set_job(this); |
| 271 requests_.push_back(req); | 143 requests_.push_back(req); |
| 272 } | 144 } |
| 273 | 145 |
| 274 // Called from origin loop. | 146 // Called from origin loop. |
| 275 void Start() { | 147 void Start() { |
| 276 // Dispatch the job to a worker thread. | 148 // Dispatch the job to a worker thread. |
| 277 if (!WorkerPool::PostTask(FROM_HERE, | 149 if (!WorkerPool::PostTask(FROM_HERE, |
| 278 NewRunnableMethod(this, &Job::DoLookup), true)) { | 150 NewRunnableMethod(this, &Job::DoLookup), true)) { |
| 279 NOTREACHED(); | 151 NOTREACHED(); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 294 | 166 |
| 295 // Mark the job as cancelled, so when worker thread completes it will | 167 // Mark the job as cancelled, so when worker thread completes it will |
| 296 // not try to post completion to origin loop. | 168 // not try to post completion to origin loop. |
| 297 { | 169 { |
| 298 AutoLock locked(origin_loop_lock_); | 170 AutoLock locked(origin_loop_lock_); |
| 299 origin_loop_ = NULL; | 171 origin_loop_ = NULL; |
| 300 } | 172 } |
| 301 | 173 |
| 302 // We don't have to do anything further to actually cancel the requests | 174 // We don't have to do anything further to actually cancel the requests |
| 303 // that were attached to this job (since they are unreachable now). | 175 // that were attached to this job (since they are unreachable now). |
| 304 // But we will call HostResolver::CancelRequest(Request*) on each one | 176 // But we will call HostResolverImpl::CancelRequest(Request*) on each one |
| 305 // in order to notify any observers. | 177 // in order to notify any observers. |
| 306 for (RequestsList::const_iterator it = requests_.begin(); | 178 for (RequestsList::const_iterator it = requests_.begin(); |
| 307 it != requests_.end(); ++it) { | 179 it != requests_.end(); ++it) { |
| 308 HostResolver::Request* req = *it; | 180 HostResolverImpl::Request* req = *it; |
| 309 if (!req->was_cancelled()) | 181 if (!req->was_cancelled()) |
| 310 resolver->CancelRequest(req); | 182 resolver->CancelRequest(req); |
| 311 } | 183 } |
| 312 } | 184 } |
| 313 | 185 |
| 314 // Called from origin thread. | 186 // Called from origin thread. |
| 315 bool was_cancelled() const { | 187 bool was_cancelled() const { |
| 316 return resolver_ == NULL; | 188 return resolver_ == NULL; |
| 317 } | 189 } |
| 318 | 190 |
| 319 // Called from origin thread. | 191 // Called from origin thread. |
| 320 const std::string& host() const { | 192 const std::string& host() const { |
| 321 return host_; | 193 return host_; |
| 322 } | 194 } |
| 323 | 195 |
| 324 // Called from origin thread. | 196 // Called from origin thread. |
| 325 const RequestsList& requests() const { | 197 const RequestsList& requests() const { |
| 326 return requests_; | 198 return requests_; |
| 327 } | 199 } |
| 328 | 200 |
| 329 private: | 201 private: |
| 330 void DoLookup() { | 202 void DoLookup() { |
| 331 // Running on the worker thread | 203 // Running on the worker thread |
| 332 error_ = ResolveAddrInfo(host_mapper_, host_, &results_); | 204 error_ = ResolveAddrInfo(resolver_proc_, host_, &results_); |
| 333 | 205 |
| 334 Task* reply = NewRunnableMethod(this, &Job::OnLookupComplete); | 206 Task* reply = NewRunnableMethod(this, &Job::OnLookupComplete); |
| 335 | 207 |
| 336 // The origin loop could go away while we are trying to post to it, so we | 208 // The origin loop could go away while we are trying to post to it, so we |
| 337 // need to call its PostTask method inside a lock. See ~HostResolver. | 209 // need to call its PostTask method inside a lock. See ~HostResolver. |
| 338 { | 210 { |
| 339 AutoLock locked(origin_loop_lock_); | 211 AutoLock locked(origin_loop_lock_); |
| 340 if (origin_loop_) { | 212 if (origin_loop_) { |
| 341 origin_loop_->PostTask(FROM_HERE, reply); | 213 origin_loop_->PostTask(FROM_HERE, reply); |
| 342 reply = NULL; | 214 reply = NULL; |
| 343 } | 215 } |
| 344 } | 216 } |
| 345 | 217 |
| 346 // Does nothing if it got posted. | 218 // Does nothing if it got posted. |
| 347 delete reply; | 219 delete reply; |
| 348 } | 220 } |
| 349 | 221 |
| 350 // Callback for when DoLookup() completes (runs on origin thread). | 222 // Callback for when DoLookup() completes (runs on origin thread). |
| 351 void OnLookupComplete() { | 223 void OnLookupComplete() { |
| 352 // Should be running on origin loop. | 224 // Should be running on origin loop. |
| 353 // TODO(eroman): this is being hit by URLRequestTest.CancelTest*, | 225 // TODO(eroman): this is being hit by URLRequestTest.CancelTest*, |
| 354 // because MessageLoop::current() == NULL. | 226 // because MessageLoop::current() == NULL. |
| 355 //DCHECK_EQ(origin_loop_, MessageLoop::current()); | 227 //DCHECK_EQ(origin_loop_, MessageLoop::current()); |
| 356 DCHECK(error_ || results_); | 228 DCHECK(error_ || results_.head()); |
| 357 | 229 |
| 358 if (was_cancelled()) | 230 if (was_cancelled()) |
| 359 return; | 231 return; |
| 360 | 232 |
| 361 DCHECK(!requests_.empty()); | 233 DCHECK(!requests_.empty()); |
| 362 | 234 |
| 363 // Adopt the address list using the port number of the first request. | 235 // Use the port number of the first request. |
| 364 AddressList addrlist; | 236 if (error_ == OK) |
| 365 if (error_ == OK) { | 237 results_.SetPort(requests_[0]->port()); |
| 366 addrlist.Adopt(results_); | |
| 367 addrlist.SetPort(requests_[0]->port()); | |
| 368 results_ = NULL; | |
| 369 } | |
| 370 | 238 |
| 371 resolver_->OnJobComplete(this, error_, addrlist); | 239 resolver_->OnJobComplete(this, error_, results_); |
| 372 } | 240 } |
| 373 | 241 |
| 374 // Set on the origin thread, read on the worker thread. | 242 // Set on the origin thread, read on the worker thread. |
| 375 std::string host_; | 243 std::string host_; |
| 376 | 244 |
| 377 // Only used on the origin thread (where Resolve was called). | 245 // Only used on the origin thread (where Resolve was called). |
| 378 HostResolver* resolver_; | 246 HostResolverImpl* resolver_; |
| 379 RequestsList requests_; // The requests waiting on this job. | 247 RequestsList requests_; // The requests waiting on this job. |
| 380 | 248 |
| 381 // Used to post ourselves onto the origin thread. | 249 // Used to post ourselves onto the origin thread. |
| 382 Lock origin_loop_lock_; | 250 Lock origin_loop_lock_; |
| 383 MessageLoop* origin_loop_; | 251 MessageLoop* origin_loop_; |
| 384 | 252 |
| 385 // Hold an owning reference to the host mapper that we are going to use. | 253 // Hold an owning reference to the HostResolverProc that we are going to use. |
| 386 // This may not be the current host mapper by the time we call | 254 // This may not be the current resolver procedure by the time we call |
| 387 // ResolveAddrInfo, but that's OK... we'll use it anyways, and the owning | 255 // ResolveAddrInfo, but that's OK... we'll use it anyways, and the owning |
| 388 // reference ensures that it remains valid until we are done. | 256 // reference ensures that it remains valid until we are done. |
| 389 scoped_refptr<HostMapper> host_mapper_; | 257 scoped_refptr<HostResolverProc> resolver_proc_; |
| 390 | 258 |
| 391 // Assigned on the worker thread, read on the origin thread. | 259 // Assigned on the worker thread, read on the origin thread. |
| 392 int error_; | 260 int error_; |
| 393 struct addrinfo* results_; | 261 AddressList results_; |
| 394 | 262 |
| 395 DISALLOW_COPY_AND_ASSIGN(Job); | 263 DISALLOW_COPY_AND_ASSIGN(Job); |
| 396 }; | 264 }; |
| 397 | 265 |
| 398 //----------------------------------------------------------------------------- | 266 //----------------------------------------------------------------------------- |
| 399 | 267 |
| 400 HostResolver::HostResolver(int max_cache_entries, int cache_duration_ms) | 268 HostResolverImpl::HostResolverImpl(HostResolverProc* resolver_proc, |
| 269 int max_cache_entries, |
| 270 int cache_duration_ms) |
| 401 : cache_(max_cache_entries, cache_duration_ms), next_request_id_(0), | 271 : cache_(max_cache_entries, cache_duration_ms), next_request_id_(0), |
| 402 shutdown_(false) { | 272 resolver_proc_(resolver_proc), shutdown_(false) { |
| 403 #if defined(OS_WIN) | 273 #if defined(OS_WIN) |
| 404 EnsureWinsockInit(); | 274 EnsureWinsockInit(); |
| 405 #endif | 275 #endif |
| 406 } | 276 } |
| 407 | 277 |
| 408 HostResolver::~HostResolver() { | 278 HostResolverImpl::~HostResolverImpl() { |
| 409 // Cancel the outstanding jobs. Those jobs may contain several attached | 279 // Cancel the outstanding jobs. Those jobs may contain several attached |
| 410 // requests, which will also be cancelled. | 280 // requests, which will also be cancelled. |
| 411 for (JobMap::iterator it = jobs_.begin(); it != jobs_.end(); ++it) | 281 for (JobMap::iterator it = jobs_.begin(); it != jobs_.end(); ++it) |
| 412 it->second->Cancel(); | 282 it->second->Cancel(); |
| 413 | 283 |
| 414 // In case we are being deleted during the processing of a callback. | 284 // In case we are being deleted during the processing of a callback. |
| 415 if (cur_completing_job_) | 285 if (cur_completing_job_) |
| 416 cur_completing_job_->Cancel(); | 286 cur_completing_job_->Cancel(); |
| 417 } | 287 } |
| 418 | 288 |
| 419 // TODO(eroman): Don't create cache entries for hostnames which are simply IP | 289 // TODO(eroman): Don't create cache entries for hostnames which are simply IP |
| 420 // address literals. | 290 // address literals. |
| 421 int HostResolver::Resolve(const RequestInfo& info, | 291 int HostResolverImpl::Resolve(const RequestInfo& info, |
| 422 AddressList* addresses, | 292 AddressList* addresses, |
| 423 CompletionCallback* callback, | 293 CompletionCallback* callback, |
| 424 Request** out_req) { | 294 RequestHandle* out_req) { |
| 425 if (shutdown_) | 295 if (shutdown_) |
| 426 return ERR_UNEXPECTED; | 296 return ERR_UNEXPECTED; |
| 427 | 297 |
| 428 // Choose a unique ID number for observers to see. | 298 // Choose a unique ID number for observers to see. |
| 429 int request_id = next_request_id_++; | 299 int request_id = next_request_id_++; |
| 430 | 300 |
| 431 // Notify registered observers. | 301 // Notify registered observers. |
| 432 NotifyObserversStartRequest(request_id, info); | 302 NotifyObserversStartRequest(request_id, info); |
| 433 | 303 |
| 434 // If we have an unexpired cache entry, use it. | 304 // If we have an unexpired cache entry, use it. |
| 435 if (info.allow_cached_response()) { | 305 if (info.allow_cached_response()) { |
| 436 const HostCache::Entry* cache_entry = cache_.Lookup( | 306 const HostCache::Entry* cache_entry = cache_.Lookup( |
| 437 info.hostname(), base::TimeTicks::Now()); | 307 info.hostname(), base::TimeTicks::Now()); |
| 438 if (cache_entry) { | 308 if (cache_entry) { |
| 439 addresses->SetFrom(cache_entry->addrlist, info.port()); | 309 addresses->SetFrom(cache_entry->addrlist, info.port()); |
| 440 int error = OK; | 310 int error = cache_entry->error; |
| 441 | 311 |
| 442 // Notify registered observers. | 312 // Notify registered observers. |
| 443 NotifyObserversFinishRequest(request_id, info, error); | 313 NotifyObserversFinishRequest(request_id, info, error); |
| 444 | 314 |
| 445 return error; | 315 return error; |
| 446 } | 316 } |
| 447 } | 317 } |
| 448 | 318 |
| 449 // If no callback was specified, do a synchronous resolution. | 319 // If no callback was specified, do a synchronous resolution. |
| 450 if (!callback) { | 320 if (!callback) { |
| 451 struct addrinfo* results; | |
| 452 int error = ResolveAddrInfo(host_mapper, info.hostname(), &results); | |
| 453 | |
| 454 // Adopt the address list. | |
| 455 AddressList addrlist; | 321 AddressList addrlist; |
| 322 int error = ResolveAddrInfo( |
| 323 effective_resolver_proc(), info.hostname(), &addrlist); |
| 456 if (error == OK) { | 324 if (error == OK) { |
| 457 addrlist.Adopt(results); | |
| 458 addrlist.SetPort(info.port()); | 325 addrlist.SetPort(info.port()); |
| 459 *addresses = addrlist; | 326 *addresses = addrlist; |
| 460 } | 327 } |
| 461 | 328 |
| 462 // Write to cache. | 329 // Write to cache. |
| 463 cache_.Set(info.hostname(), error, addrlist, base::TimeTicks::Now()); | 330 cache_.Set(info.hostname(), error, addrlist, base::TimeTicks::Now()); |
| 464 | 331 |
| 465 // Notify registered observers. | 332 // Notify registered observers. |
| 466 NotifyObserversFinishRequest(request_id, info, error); | 333 NotifyObserversFinishRequest(request_id, info, error); |
| 467 | 334 |
| 468 return error; | 335 return error; |
| 469 } | 336 } |
| 470 | 337 |
| 471 // Create a handle for this request, and pass it back to the user if they | 338 // Create a handle for this request, and pass it back to the user if they |
| 472 // asked for it (out_req != NULL). | 339 // asked for it (out_req != NULL). |
| 473 Request* req = new Request(request_id, info, callback, addresses); | 340 Request* req = new Request(request_id, info, callback, addresses); |
| 474 if (out_req) | 341 if (out_req) |
| 475 *out_req = req; | 342 *out_req = reinterpret_cast<RequestHandle>(req); |
| 476 | 343 |
| 477 // Next we need to attach our request to a "job". This job is responsible for | 344 // Next we need to attach our request to a "job". This job is responsible for |
| 478 // calling "getaddrinfo(hostname)" on a worker thread. | 345 // calling "getaddrinfo(hostname)" on a worker thread. |
| 479 scoped_refptr<Job> job; | 346 scoped_refptr<Job> job; |
| 480 | 347 |
| 481 // If there is already an outstanding job to resolve |info.hostname()|, use | 348 // If there is already an outstanding job to resolve |info.hostname()|, use |
| 482 // it. This prevents starting concurrent resolves for the same hostname. | 349 // it. This prevents starting concurrent resolves for the same hostname. |
| 483 job = FindOutstandingJob(info.hostname()); | 350 job = FindOutstandingJob(info.hostname()); |
| 484 if (job) { | 351 if (job) { |
| 485 job->AddRequest(req); | 352 job->AddRequest(req); |
| 486 } else { | 353 } else { |
| 487 // Create a new job for this request. | 354 // Create a new job for this request. |
| 488 job = new Job(this, info.hostname()); | 355 job = new Job(this, info.hostname()); |
| 489 job->AddRequest(req); | 356 job->AddRequest(req); |
| 490 AddOutstandingJob(job); | 357 AddOutstandingJob(job); |
| 491 // TODO(eroman): Bound the total number of concurrent jobs. | 358 // TODO(eroman): Bound the total number of concurrent jobs. |
| 492 // http://crbug.com/9598 | 359 // http://crbug.com/9598 |
| 493 job->Start(); | 360 job->Start(); |
| 494 } | 361 } |
| 495 | 362 |
| 496 // Completion happens during OnJobComplete(Job*). | 363 // Completion happens during OnJobComplete(Job*). |
| 497 return ERR_IO_PENDING; | 364 return ERR_IO_PENDING; |
| 498 } | 365 } |
| 499 | 366 |
| 500 // See OnJobComplete(Job*) for why it is important not to clean out | 367 // See OnJobComplete(Job*) for why it is important not to clean out |
| 501 // cancelled requests from Job::requests_. | 368 // cancelled requests from Job::requests_. |
| 502 void HostResolver::CancelRequest(Request* req) { | 369 void HostResolverImpl::CancelRequest(RequestHandle req_handle) { |
| 370 Request* req = reinterpret_cast<Request*>(req_handle); |
| 503 DCHECK(req); | 371 DCHECK(req); |
| 504 DCHECK(req->job()); | 372 DCHECK(req->job()); |
| 505 // NULL out the fields of req, to mark it as cancelled. | 373 // NULL out the fields of req, to mark it as cancelled. |
| 506 req->MarkAsCancelled(); | 374 req->MarkAsCancelled(); |
| 507 NotifyObserversCancelRequest(req->id(), req->info()); | 375 NotifyObserversCancelRequest(req->id(), req->info()); |
| 508 } | 376 } |
| 509 | 377 |
| 510 void HostResolver::AddObserver(Observer* observer) { | 378 void HostResolverImpl::AddObserver(Observer* observer) { |
| 511 observers_.push_back(observer); | 379 observers_.push_back(observer); |
| 512 } | 380 } |
| 513 | 381 |
| 514 void HostResolver::RemoveObserver(Observer* observer) { | 382 void HostResolverImpl::RemoveObserver(Observer* observer) { |
| 515 ObserversList::iterator it = | 383 ObserversList::iterator it = |
| 516 std::find(observers_.begin(), observers_.end(), observer); | 384 std::find(observers_.begin(), observers_.end(), observer); |
| 517 | 385 |
| 518 // Observer must exist. | 386 // Observer must exist. |
| 519 DCHECK(it != observers_.end()); | 387 DCHECK(it != observers_.end()); |
| 520 | 388 |
| 521 observers_.erase(it); | 389 observers_.erase(it); |
| 522 } | 390 } |
| 523 | 391 |
| 524 void HostResolver::Shutdown() { | 392 void HostResolverImpl::Shutdown() { |
| 525 shutdown_ = true; | 393 shutdown_ = true; |
| 526 | 394 |
| 527 // Cancel the outstanding jobs. | 395 // Cancel the outstanding jobs. |
| 528 for (JobMap::iterator it = jobs_.begin(); it != jobs_.end(); ++it) | 396 for (JobMap::iterator it = jobs_.begin(); it != jobs_.end(); ++it) |
| 529 it->second->Cancel(); | 397 it->second->Cancel(); |
| 530 jobs_.clear(); | 398 jobs_.clear(); |
| 531 } | 399 } |
| 532 | 400 |
| 533 void HostResolver::AddOutstandingJob(Job* job) { | 401 void HostResolverImpl::AddOutstandingJob(Job* job) { |
| 534 scoped_refptr<Job>& found_job = jobs_[job->host()]; | 402 scoped_refptr<Job>& found_job = jobs_[job->host()]; |
| 535 DCHECK(!found_job); | 403 DCHECK(!found_job); |
| 536 found_job = job; | 404 found_job = job; |
| 537 } | 405 } |
| 538 | 406 |
| 539 HostResolver::Job* HostResolver::FindOutstandingJob( | 407 HostResolverImpl::Job* HostResolverImpl::FindOutstandingJob( |
| 540 const std::string& hostname) { | 408 const std::string& hostname) { |
| 541 JobMap::iterator it = jobs_.find(hostname); | 409 JobMap::iterator it = jobs_.find(hostname); |
| 542 if (it != jobs_.end()) | 410 if (it != jobs_.end()) |
| 543 return it->second; | 411 return it->second; |
| 544 return NULL; | 412 return NULL; |
| 545 } | 413 } |
| 546 | 414 |
| 547 void HostResolver::RemoveOutstandingJob(Job* job) { | 415 void HostResolverImpl::RemoveOutstandingJob(Job* job) { |
| 548 JobMap::iterator it = jobs_.find(job->host()); | 416 JobMap::iterator it = jobs_.find(job->host()); |
| 549 DCHECK(it != jobs_.end()); | 417 DCHECK(it != jobs_.end()); |
| 550 DCHECK_EQ(it->second.get(), job); | 418 DCHECK_EQ(it->second.get(), job); |
| 551 jobs_.erase(it); | 419 jobs_.erase(it); |
| 552 } | 420 } |
| 553 | 421 |
| 554 void HostResolver::OnJobComplete(Job* job, | 422 void HostResolverImpl::OnJobComplete(Job* job, |
| 555 int error, | 423 int error, |
| 556 const AddressList& addrlist) { | 424 const AddressList& addrlist) { |
| 557 RemoveOutstandingJob(job); | 425 RemoveOutstandingJob(job); |
| 558 | 426 |
| 559 // Write result to the cache. | 427 // Write result to the cache. |
| 560 cache_.Set(job->host(), error, addrlist, base::TimeTicks::Now()); | 428 cache_.Set(job->host(), error, addrlist, base::TimeTicks::Now()); |
| 561 | 429 |
| 562 // Make a note that we are executing within OnJobComplete() in case the | 430 // Make a note that we are executing within OnJobComplete() in case the |
| 563 // HostResolver is deleted by a callback invocation. | 431 // HostResolver is deleted by a callback invocation. |
| 564 DCHECK(!cur_completing_job_); | 432 DCHECK(!cur_completing_job_); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 579 // Check if the job was cancelled as a result of running the callback. | 447 // Check if the job was cancelled as a result of running the callback. |
| 580 // (Meaning that |this| was deleted). | 448 // (Meaning that |this| was deleted). |
| 581 if (job->was_cancelled()) | 449 if (job->was_cancelled()) |
| 582 return; | 450 return; |
| 583 } | 451 } |
| 584 } | 452 } |
| 585 | 453 |
| 586 cur_completing_job_ = NULL; | 454 cur_completing_job_ = NULL; |
| 587 } | 455 } |
| 588 | 456 |
| 589 void HostResolver::NotifyObserversStartRequest(int request_id, | 457 void HostResolverImpl::NotifyObserversStartRequest(int request_id, |
| 590 const RequestInfo& info) { | 458 const RequestInfo& info) { |
| 591 for (ObserversList::iterator it = observers_.begin(); | 459 for (ObserversList::iterator it = observers_.begin(); |
| 592 it != observers_.end(); ++it) { | 460 it != observers_.end(); ++it) { |
| 593 (*it)->OnStartResolution(request_id, info); | 461 (*it)->OnStartResolution(request_id, info); |
| 594 } | 462 } |
| 595 } | 463 } |
| 596 | 464 |
| 597 void HostResolver::NotifyObserversFinishRequest(int request_id, | 465 void HostResolverImpl::NotifyObserversFinishRequest(int request_id, |
| 598 const RequestInfo& info, | 466 const RequestInfo& info, |
| 599 int error) { | 467 int error) { |
| 600 bool was_resolved = error == OK; | 468 bool was_resolved = error == OK; |
| 601 for (ObserversList::iterator it = observers_.begin(); | 469 for (ObserversList::iterator it = observers_.begin(); |
| 602 it != observers_.end(); ++it) { | 470 it != observers_.end(); ++it) { |
| 603 (*it)->OnFinishResolutionWithStatus(request_id, was_resolved, info); | 471 (*it)->OnFinishResolutionWithStatus(request_id, was_resolved, info); |
| 604 } | 472 } |
| 605 } | 473 } |
| 606 | 474 |
| 607 void HostResolver::NotifyObserversCancelRequest(int request_id, | 475 void HostResolverImpl::NotifyObserversCancelRequest(int request_id, |
| 608 const RequestInfo& info) { | 476 const RequestInfo& info) { |
| 609 for (ObserversList::iterator it = observers_.begin(); | 477 for (ObserversList::iterator it = observers_.begin(); |
| 610 it != observers_.end(); ++it) { | 478 it != observers_.end(); ++it) { |
| 611 (*it)->OnCancelResolution(request_id, info); | 479 (*it)->OnCancelResolution(request_id, info); |
| 612 } | 480 } |
| 613 } | 481 } |
| 614 | 482 |
| 615 //----------------------------------------------------------------------------- | |
| 616 | |
| 617 SingleRequestHostResolver::SingleRequestHostResolver(HostResolver* resolver) | |
| 618 : resolver_(resolver), | |
| 619 cur_request_(NULL), | |
| 620 cur_request_callback_(NULL), | |
| 621 ALLOW_THIS_IN_INITIALIZER_LIST( | |
| 622 callback_(this, &SingleRequestHostResolver::OnResolveCompletion)) { | |
| 623 DCHECK(resolver_ != NULL); | |
| 624 } | |
| 625 | |
| 626 SingleRequestHostResolver::~SingleRequestHostResolver() { | |
| 627 if (cur_request_) { | |
| 628 resolver_->CancelRequest(cur_request_); | |
| 629 } | |
| 630 } | |
| 631 | |
| 632 int SingleRequestHostResolver::Resolve(const HostResolver::RequestInfo& info, | |
| 633 AddressList* addresses, | |
| 634 CompletionCallback* callback) { | |
| 635 DCHECK(!cur_request_ && !cur_request_callback_) << "resolver already in use"; | |
| 636 | |
| 637 HostResolver::Request* request = NULL; | |
| 638 | |
| 639 // We need to be notified of completion before |callback| is called, so that | |
| 640 // we can clear out |cur_request_*|. | |
| 641 CompletionCallback* transient_callback = callback ? &callback_ : NULL; | |
| 642 | |
| 643 int rv = resolver_->Resolve(info, addresses, transient_callback, &request); | |
| 644 | |
| 645 if (rv == ERR_IO_PENDING) { | |
| 646 // Cleared in OnResolveCompletion(). | |
| 647 cur_request_ = request; | |
| 648 cur_request_callback_ = callback; | |
| 649 } | |
| 650 | |
| 651 return rv; | |
| 652 } | |
| 653 | |
| 654 void SingleRequestHostResolver::OnResolveCompletion(int result) { | |
| 655 DCHECK(cur_request_ && cur_request_callback_); | |
| 656 | |
| 657 CompletionCallback* callback = cur_request_callback_; | |
| 658 | |
| 659 // Clear the outstanding request information. | |
| 660 cur_request_ = NULL; | |
| 661 cur_request_callback_ = NULL; | |
| 662 | |
| 663 // Call the user's original callback. | |
| 664 callback->Run(result); | |
| 665 } | |
| 666 | |
| 667 } // namespace net | 483 } // namespace net |
| OLD | NEW |