| 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_impl.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) |
| (...skipping 23 matching lines...) Expand all Loading... |
| 34 namespace net { | 34 namespace net { |
| 35 | 35 |
| 36 HostResolver* CreateSystemHostResolver() { | 36 HostResolver* CreateSystemHostResolver() { |
| 37 static const size_t kMaxHostCacheEntries = 100; | 37 static const size_t kMaxHostCacheEntries = 100; |
| 38 static const size_t kHostCacheExpirationMs = 60000; // 1 minute. | 38 static const size_t kHostCacheExpirationMs = 60000; // 1 minute. |
| 39 return new HostResolverImpl( | 39 return new HostResolverImpl( |
| 40 NULL, kMaxHostCacheEntries, kHostCacheExpirationMs); | 40 NULL, kMaxHostCacheEntries, kHostCacheExpirationMs); |
| 41 } | 41 } |
| 42 | 42 |
| 43 static int ResolveAddrInfo(HostResolverProc* resolver_proc, | 43 static int ResolveAddrInfo(HostResolverProc* resolver_proc, |
| 44 const std::string& host, AddressList* out) { | 44 const std::string& host, |
| 45 AddressFamily address_family, |
| 46 AddressList* out) { |
| 45 if (resolver_proc) { | 47 if (resolver_proc) { |
| 46 // Use the custom procedure. | 48 // Use the custom procedure. |
| 47 return resolver_proc->Resolve(host, out); | 49 return resolver_proc->Resolve(host, address_family, out); |
| 48 } else { | 50 } else { |
| 49 // Use the system procedure (getaddrinfo). | 51 // Use the system procedure (getaddrinfo). |
| 50 return SystemHostResolverProc(host, out); | 52 return SystemHostResolverProc(host, address_family, out); |
| 51 } | 53 } |
| 52 } | 54 } |
| 53 | 55 |
| 54 //----------------------------------------------------------------------------- | 56 //----------------------------------------------------------------------------- |
| 55 | 57 |
| 56 class HostResolverImpl::Request { | 58 class HostResolverImpl::Request { |
| 57 public: | 59 public: |
| 58 Request(LoadLog* load_log, | 60 Request(LoadLog* load_log, |
| 59 int id, | 61 int id, |
| 60 const RequestInfo& info, | 62 const RequestInfo& info, |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 135 DISALLOW_COPY_AND_ASSIGN(Request); | 137 DISALLOW_COPY_AND_ASSIGN(Request); |
| 136 }; | 138 }; |
| 137 | 139 |
| 138 //----------------------------------------------------------------------------- | 140 //----------------------------------------------------------------------------- |
| 139 | 141 |
| 140 // This class represents a request to the worker pool for a "getaddrinfo()" | 142 // This class represents a request to the worker pool for a "getaddrinfo()" |
| 141 // call. | 143 // call. |
| 142 class HostResolverImpl::Job | 144 class HostResolverImpl::Job |
| 143 : public base::RefCountedThreadSafe<HostResolverImpl::Job> { | 145 : public base::RefCountedThreadSafe<HostResolverImpl::Job> { |
| 144 public: | 146 public: |
| 145 Job(HostResolverImpl* resolver, const std::string& host) | 147 Job(HostResolverImpl* resolver, const Key& key) |
| 146 : host_(host), | 148 : key_(key), |
| 147 resolver_(resolver), | 149 resolver_(resolver), |
| 148 origin_loop_(MessageLoop::current()), | 150 origin_loop_(MessageLoop::current()), |
| 149 resolver_proc_(resolver->effective_resolver_proc()), | 151 resolver_proc_(resolver->effective_resolver_proc()), |
| 150 error_(OK) { | 152 error_(OK) { |
| 151 } | 153 } |
| 152 | 154 |
| 153 ~Job() { | 155 ~Job() { |
| 154 // Free the requests attached to this job. | 156 // Free the requests attached to this job. |
| 155 STLDeleteElements(&requests_); | 157 STLDeleteElements(&requests_); |
| 156 } | 158 } |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 199 resolver->CancelRequest(req); | 201 resolver->CancelRequest(req); |
| 200 } | 202 } |
| 201 } | 203 } |
| 202 | 204 |
| 203 // Called from origin thread. | 205 // Called from origin thread. |
| 204 bool was_cancelled() const { | 206 bool was_cancelled() const { |
| 205 return resolver_ == NULL; | 207 return resolver_ == NULL; |
| 206 } | 208 } |
| 207 | 209 |
| 208 // Called from origin thread. | 210 // Called from origin thread. |
| 209 const std::string& host() const { | 211 const Key& key() const { |
| 210 return host_; | 212 return key_; |
| 211 } | 213 } |
| 212 | 214 |
| 213 // Called from origin thread. | 215 // Called from origin thread. |
| 214 const RequestsList& requests() const { | 216 const RequestsList& requests() const { |
| 215 return requests_; | 217 return requests_; |
| 216 } | 218 } |
| 217 | 219 |
| 218 private: | 220 private: |
| 219 void DoLookup() { | 221 void DoLookup() { |
| 220 // Running on the worker thread | 222 // Running on the worker thread |
| 221 error_ = ResolveAddrInfo(resolver_proc_, host_, &results_); | 223 error_ = ResolveAddrInfo(resolver_proc_, |
| 224 key_.hostname, |
| 225 key_.address_family, |
| 226 &results_); |
| 222 | 227 |
| 223 Task* reply = NewRunnableMethod(this, &Job::OnLookupComplete); | 228 Task* reply = NewRunnableMethod(this, &Job::OnLookupComplete); |
| 224 | 229 |
| 225 // The origin loop could go away while we are trying to post to it, so we | 230 // The origin loop could go away while we are trying to post to it, so we |
| 226 // need to call its PostTask method inside a lock. See ~HostResolver. | 231 // need to call its PostTask method inside a lock. See ~HostResolver. |
| 227 { | 232 { |
| 228 AutoLock locked(origin_loop_lock_); | 233 AutoLock locked(origin_loop_lock_); |
| 229 if (origin_loop_) { | 234 if (origin_loop_) { |
| 230 origin_loop_->PostTask(FROM_HERE, reply); | 235 origin_loop_->PostTask(FROM_HERE, reply); |
| 231 reply = NULL; | 236 reply = NULL; |
| (...skipping 18 matching lines...) Expand all Loading... |
| 250 DCHECK(!requests_.empty()); | 255 DCHECK(!requests_.empty()); |
| 251 | 256 |
| 252 // Use the port number of the first request. | 257 // Use the port number of the first request. |
| 253 if (error_ == OK) | 258 if (error_ == OK) |
| 254 results_.SetPort(requests_[0]->port()); | 259 results_.SetPort(requests_[0]->port()); |
| 255 | 260 |
| 256 resolver_->OnJobComplete(this, error_, results_); | 261 resolver_->OnJobComplete(this, error_, results_); |
| 257 } | 262 } |
| 258 | 263 |
| 259 // Set on the origin thread, read on the worker thread. | 264 // Set on the origin thread, read on the worker thread. |
| 260 std::string host_; | 265 Key key_; |
| 261 | 266 |
| 262 // Only used on the origin thread (where Resolve was called). | 267 // Only used on the origin thread (where Resolve was called). |
| 263 HostResolverImpl* resolver_; | 268 HostResolverImpl* resolver_; |
| 264 RequestsList requests_; // The requests waiting on this job. | 269 RequestsList requests_; // The requests waiting on this job. |
| 265 | 270 |
| 266 // Used to post ourselves onto the origin thread. | 271 // Used to post ourselves onto the origin thread. |
| 267 Lock origin_loop_lock_; | 272 Lock origin_loop_lock_; |
| 268 MessageLoop* origin_loop_; | 273 MessageLoop* origin_loop_; |
| 269 | 274 |
| 270 // Hold an owning reference to the HostResolverProc that we are going to use. | 275 // Hold an owning reference to the HostResolverProc that we are going to use. |
| 271 // This may not be the current resolver procedure by the time we call | 276 // This may not be the current resolver procedure by the time we call |
| 272 // ResolveAddrInfo, but that's OK... we'll use it anyways, and the owning | 277 // ResolveAddrInfo, but that's OK... we'll use it anyways, and the owning |
| 273 // reference ensures that it remains valid until we are done. | 278 // reference ensures that it remains valid until we are done. |
| 274 scoped_refptr<HostResolverProc> resolver_proc_; | 279 scoped_refptr<HostResolverProc> resolver_proc_; |
| 275 | 280 |
| 276 // Assigned on the worker thread, read on the origin thread. | 281 // Assigned on the worker thread, read on the origin thread. |
| 277 int error_; | 282 int error_; |
| 278 AddressList results_; | 283 AddressList results_; |
| 279 | 284 |
| 280 DISALLOW_COPY_AND_ASSIGN(Job); | 285 DISALLOW_COPY_AND_ASSIGN(Job); |
| 281 }; | 286 }; |
| 282 | 287 |
| 283 //----------------------------------------------------------------------------- | 288 //----------------------------------------------------------------------------- |
| 284 | 289 |
| 285 HostResolverImpl::HostResolverImpl(HostResolverProc* resolver_proc, | 290 HostResolverImpl::HostResolverImpl(HostResolverProc* resolver_proc, |
| 286 int max_cache_entries, | 291 int max_cache_entries, |
| 287 int cache_duration_ms) | 292 int cache_duration_ms) |
| 288 : cache_(max_cache_entries, cache_duration_ms), next_request_id_(0), | 293 : cache_(max_cache_entries, cache_duration_ms), |
| 289 resolver_proc_(resolver_proc), shutdown_(false) { | 294 next_request_id_(0), |
| 295 resolver_proc_(resolver_proc), |
| 296 disable_ipv6_(false), |
| 297 shutdown_(false) { |
| 290 #if defined(OS_WIN) | 298 #if defined(OS_WIN) |
| 291 EnsureWinsockInit(); | 299 EnsureWinsockInit(); |
| 292 #endif | 300 #endif |
| 293 } | 301 } |
| 294 | 302 |
| 295 HostResolverImpl::~HostResolverImpl() { | 303 HostResolverImpl::~HostResolverImpl() { |
| 296 // Cancel the outstanding jobs. Those jobs may contain several attached | 304 // Cancel the outstanding jobs. Those jobs may contain several attached |
| 297 // requests, which will also be cancelled. | 305 // requests, which will also be cancelled. |
| 298 for (JobMap::iterator it = jobs_.begin(); it != jobs_.end(); ++it) | 306 for (JobMap::iterator it = jobs_.begin(); it != jobs_.end(); ++it) |
| 299 it->second->Cancel(); | 307 it->second->Cancel(); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 312 LoadLog* load_log) { | 320 LoadLog* load_log) { |
| 313 if (shutdown_) | 321 if (shutdown_) |
| 314 return ERR_UNEXPECTED; | 322 return ERR_UNEXPECTED; |
| 315 | 323 |
| 316 // Choose a unique ID number for observers to see. | 324 // Choose a unique ID number for observers to see. |
| 317 int request_id = next_request_id_++; | 325 int request_id = next_request_id_++; |
| 318 | 326 |
| 319 // Update the load log and notify registered observers. | 327 // Update the load log and notify registered observers. |
| 320 OnStartRequest(load_log, request_id, info); | 328 OnStartRequest(load_log, request_id, info); |
| 321 | 329 |
| 330 // Build a key that identifies the request in the cache and in the |
| 331 // outstanding jobs map. |
| 332 Key key(info.hostname(), info.address_family()); |
| 333 if (disable_ipv6_) |
| 334 key.address_family = ADDRESS_FAMILY_IPV4_ONLY; |
| 335 |
| 322 // If we have an unexpired cache entry, use it. | 336 // If we have an unexpired cache entry, use it. |
| 323 if (info.allow_cached_response()) { | 337 if (info.allow_cached_response()) { |
| 324 const HostCache::Entry* cache_entry = cache_.Lookup( | 338 const HostCache::Entry* cache_entry = cache_.Lookup( |
| 325 info.hostname(), base::TimeTicks::Now()); | 339 key, base::TimeTicks::Now()); |
| 326 if (cache_entry) { | 340 if (cache_entry) { |
| 327 addresses->SetFrom(cache_entry->addrlist, info.port()); | 341 addresses->SetFrom(cache_entry->addrlist, info.port()); |
| 328 int error = cache_entry->error; | 342 int error = cache_entry->error; |
| 329 | 343 |
| 330 // Update the load log and notify registered observers. | 344 // Update the load log and notify registered observers. |
| 331 OnFinishRequest(load_log, request_id, info, error); | 345 OnFinishRequest(load_log, request_id, info, error); |
| 332 | 346 |
| 333 return error; | 347 return error; |
| 334 } | 348 } |
| 335 } | 349 } |
| 336 | 350 |
| 337 // If no callback was specified, do a synchronous resolution. | 351 // If no callback was specified, do a synchronous resolution. |
| 338 if (!callback) { | 352 if (!callback) { |
| 339 AddressList addrlist; | 353 AddressList addrlist; |
| 340 int error = ResolveAddrInfo( | 354 int error = ResolveAddrInfo( |
| 341 effective_resolver_proc(), info.hostname(), &addrlist); | 355 effective_resolver_proc(), key.hostname, key.address_family, &addrlist); |
| 342 if (error == OK) { | 356 if (error == OK) { |
| 343 addrlist.SetPort(info.port()); | 357 addrlist.SetPort(info.port()); |
| 344 *addresses = addrlist; | 358 *addresses = addrlist; |
| 345 } | 359 } |
| 346 | 360 |
| 347 // Write to cache. | 361 // Write to cache. |
| 348 cache_.Set(info.hostname(), error, addrlist, base::TimeTicks::Now()); | 362 cache_.Set(key, error, addrlist, base::TimeTicks::Now()); |
| 349 | 363 |
| 350 // Update the load log and notify registered observers. | 364 // Update the load log and notify registered observers. |
| 351 OnFinishRequest(load_log, request_id, info, error); | 365 OnFinishRequest(load_log, request_id, info, error); |
| 352 | 366 |
| 353 return error; | 367 return error; |
| 354 } | 368 } |
| 355 | 369 |
| 356 // Create a handle for this request, and pass it back to the user if they | 370 // Create a handle for this request, and pass it back to the user if they |
| 357 // asked for it (out_req != NULL). | 371 // asked for it (out_req != NULL). |
| 358 Request* req = new Request(load_log, request_id, info, callback, addresses); | 372 Request* req = new Request(load_log, request_id, info, callback, addresses); |
| 359 if (out_req) | 373 if (out_req) |
| 360 *out_req = reinterpret_cast<RequestHandle>(req); | 374 *out_req = reinterpret_cast<RequestHandle>(req); |
| 361 | 375 |
| 362 // Next we need to attach our request to a "job". This job is responsible for | 376 // Next we need to attach our request to a "job". This job is responsible for |
| 363 // calling "getaddrinfo(hostname)" on a worker thread. | 377 // calling "getaddrinfo(hostname)" on a worker thread. |
| 364 scoped_refptr<Job> job; | 378 scoped_refptr<Job> job; |
| 365 | 379 |
| 366 // If there is already an outstanding job to resolve |info.hostname()|, use | 380 // If there is already an outstanding job to resolve |key|, use |
| 367 // it. This prevents starting concurrent resolves for the same hostname. | 381 // it. This prevents starting concurrent resolves for the same hostname. |
| 368 job = FindOutstandingJob(info.hostname()); | 382 job = FindOutstandingJob(key); |
| 369 if (job) { | 383 if (job) { |
| 370 job->AddRequest(req); | 384 job->AddRequest(req); |
| 371 } else { | 385 } else { |
| 372 // Create a new job for this request. | 386 // Create a new job for this request. |
| 373 job = new Job(this, info.hostname()); | 387 job = new Job(this, key); |
| 374 job->AddRequest(req); | 388 job->AddRequest(req); |
| 375 AddOutstandingJob(job); | 389 AddOutstandingJob(job); |
| 376 // TODO(eroman): Bound the total number of concurrent jobs. | 390 // TODO(eroman): Bound the total number of concurrent jobs. |
| 377 // http://crbug.com/9598 | 391 // http://crbug.com/9598 |
| 378 job->Start(); | 392 job->Start(); |
| 379 } | 393 } |
| 380 | 394 |
| 381 // Completion happens during OnJobComplete(Job*). | 395 // Completion happens during OnJobComplete(Job*). |
| 382 return ERR_IO_PENDING; | 396 return ERR_IO_PENDING; |
| 383 } | 397 } |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 424 void HostResolverImpl::Shutdown() { | 438 void HostResolverImpl::Shutdown() { |
| 425 shutdown_ = true; | 439 shutdown_ = true; |
| 426 | 440 |
| 427 // Cancel the outstanding jobs. | 441 // Cancel the outstanding jobs. |
| 428 for (JobMap::iterator it = jobs_.begin(); it != jobs_.end(); ++it) | 442 for (JobMap::iterator it = jobs_.begin(); it != jobs_.end(); ++it) |
| 429 it->second->Cancel(); | 443 it->second->Cancel(); |
| 430 jobs_.clear(); | 444 jobs_.clear(); |
| 431 } | 445 } |
| 432 | 446 |
| 433 void HostResolverImpl::AddOutstandingJob(Job* job) { | 447 void HostResolverImpl::AddOutstandingJob(Job* job) { |
| 434 scoped_refptr<Job>& found_job = jobs_[job->host()]; | 448 scoped_refptr<Job>& found_job = jobs_[job->key()]; |
| 435 DCHECK(!found_job); | 449 DCHECK(!found_job); |
| 436 found_job = job; | 450 found_job = job; |
| 437 } | 451 } |
| 438 | 452 |
| 439 HostResolverImpl::Job* HostResolverImpl::FindOutstandingJob( | 453 HostResolverImpl::Job* HostResolverImpl::FindOutstandingJob(const Key& key) { |
| 440 const std::string& hostname) { | 454 JobMap::iterator it = jobs_.find(key); |
| 441 JobMap::iterator it = jobs_.find(hostname); | |
| 442 if (it != jobs_.end()) | 455 if (it != jobs_.end()) |
| 443 return it->second; | 456 return it->second; |
| 444 return NULL; | 457 return NULL; |
| 445 } | 458 } |
| 446 | 459 |
| 447 void HostResolverImpl::RemoveOutstandingJob(Job* job) { | 460 void HostResolverImpl::RemoveOutstandingJob(Job* job) { |
| 448 JobMap::iterator it = jobs_.find(job->host()); | 461 JobMap::iterator it = jobs_.find(job->key()); |
| 449 DCHECK(it != jobs_.end()); | 462 DCHECK(it != jobs_.end()); |
| 450 DCHECK_EQ(it->second.get(), job); | 463 DCHECK_EQ(it->second.get(), job); |
| 451 jobs_.erase(it); | 464 jobs_.erase(it); |
| 452 } | 465 } |
| 453 | 466 |
| 454 void HostResolverImpl::OnJobComplete(Job* job, | 467 void HostResolverImpl::OnJobComplete(Job* job, |
| 455 int error, | 468 int error, |
| 456 const AddressList& addrlist) { | 469 const AddressList& addrlist) { |
| 457 RemoveOutstandingJob(job); | 470 RemoveOutstandingJob(job); |
| 458 | 471 |
| 459 // Write result to the cache. | 472 // Write result to the cache. |
| 460 cache_.Set(job->host(), error, addrlist, base::TimeTicks::Now()); | 473 cache_.Set(job->key(), error, addrlist, base::TimeTicks::Now()); |
| 461 | 474 |
| 462 // Make a note that we are executing within OnJobComplete() in case the | 475 // Make a note that we are executing within OnJobComplete() in case the |
| 463 // HostResolver is deleted by a callback invocation. | 476 // HostResolver is deleted by a callback invocation. |
| 464 DCHECK(!cur_completing_job_); | 477 DCHECK(!cur_completing_job_); |
| 465 cur_completing_job_ = job; | 478 cur_completing_job_ = job; |
| 466 | 479 |
| 467 // Complete all of the requests that were attached to the job. | 480 // Complete all of the requests that were attached to the job. |
| 468 for (RequestsList::const_iterator it = job->requests().begin(); | 481 for (RequestsList::const_iterator it = job->requests().begin(); |
| 469 it != job->requests().end(); ++it) { | 482 it != job->requests().end(); ++it) { |
| 470 Request* req = *it; | 483 Request* req = *it; |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 544 } | 557 } |
| 545 | 558 |
| 546 LoadLog::EndEvent( | 559 LoadLog::EndEvent( |
| 547 load_log, LoadLog::TYPE_HOST_RESOLVER_IMPL_OBSERVER_ONCANCEL); | 560 load_log, LoadLog::TYPE_HOST_RESOLVER_IMPL_OBSERVER_ONCANCEL); |
| 548 } | 561 } |
| 549 | 562 |
| 550 LoadLog::EndEvent(load_log, LoadLog::TYPE_HOST_RESOLVER_IMPL); | 563 LoadLog::EndEvent(load_log, LoadLog::TYPE_HOST_RESOLVER_IMPL); |
| 551 } | 564 } |
| 552 | 565 |
| 553 } // namespace net | 566 } // namespace net |
| OLD | NEW |