| 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.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/dns_resolution_observer.h" |
| 25 #include "net/base/net_errors.h" | 26 #include "net/base/net_errors.h" |
| 26 | 27 |
| 27 #if defined(OS_LINUX) | 28 #if defined(OS_LINUX) |
| 28 #include "base/singleton.h" | 29 #include "base/singleton.h" |
| 29 #include "base/thread_local_storage.h" | 30 #include "base/thread_local_storage.h" |
| 30 #endif | 31 #endif |
| 31 | 32 |
| 32 #if defined(OS_WIN) | 33 #if defined(OS_WIN) |
| 33 #include "net/base/winsock_init.h" | 34 #include "net/base/winsock_init.h" |
| 34 #endif | 35 #endif |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 171 return HostResolverProc(mapped_host, out); | 172 return HostResolverProc(mapped_host, out); |
| 172 } else { | 173 } else { |
| 173 return HostResolverProc(host, out); | 174 return HostResolverProc(host, out); |
| 174 } | 175 } |
| 175 } | 176 } |
| 176 | 177 |
| 177 //----------------------------------------------------------------------------- | 178 //----------------------------------------------------------------------------- |
| 178 | 179 |
| 179 class HostResolver::Request { | 180 class HostResolver::Request { |
| 180 public: | 181 public: |
| 181 Request(CompletionCallback* callback, AddressList* addresses, int port) | 182 Request(int id, const RequestInfo& info, CompletionCallback* callback, |
| 182 : job_(NULL), callback_(callback), addresses_(addresses), port_(port) {} | 183 AddressList* addresses) |
| 184 : id_(id), info_(info), job_(NULL), callback_(callback), |
| 185 addresses_(addresses) {} |
| 183 | 186 |
| 184 // Mark the request as cancelled. | 187 // Mark the request as cancelled. |
| 185 void Cancel() { | 188 void Cancel() { |
| 186 job_ = NULL; | 189 job_ = NULL; |
| 187 callback_ = NULL; | 190 callback_ = NULL; |
| 188 addresses_ = NULL; | 191 addresses_ = NULL; |
| 189 } | 192 } |
| 190 | 193 |
| 191 bool was_cancelled() const { | 194 bool was_cancelled() const { |
| 192 return callback_ == NULL; | 195 return callback_ == NULL; |
| 193 } | 196 } |
| 194 | 197 |
| 195 void set_job(Job* job) { | 198 void set_job(Job* job) { |
| 196 DCHECK(job != NULL); | 199 DCHECK(job != NULL); |
| 197 // Identify which job the request is waiting on. | 200 // Identify which job the request is waiting on. |
| 198 job_ = job; | 201 job_ = job; |
| 199 } | 202 } |
| 200 | 203 |
| 201 void OnComplete(int error, const AddressList& addrlist) { | 204 void OnComplete(int error, const AddressList& addrlist) { |
| 202 if (error == OK) | 205 if (error == OK) |
| 203 addresses_->SetFrom(addrlist, port_); | 206 addresses_->SetFrom(addrlist, port()); |
| 204 callback_->Run(error); | 207 callback_->Run(error); |
| 205 } | 208 } |
| 206 | 209 |
| 207 int port() const { | 210 int port() const { |
| 208 return port_; | 211 return info_.port(); |
| 209 } | 212 } |
| 210 | 213 |
| 211 Job* job() const { | 214 Job* job() const { |
| 212 return job_; | 215 return job_; |
| 213 } | 216 } |
| 214 | 217 |
| 218 int id() const { |
| 219 return id_; |
| 220 } |
| 221 |
| 222 const RequestInfo& info() const { |
| 223 return info_; |
| 224 } |
| 225 |
| 215 private: | 226 private: |
| 227 // Unique ID for this request. Used by observers to identify requests. |
| 228 int id_; |
| 229 |
| 230 // The request info that started the request. |
| 231 RequestInfo info_; |
| 232 |
| 216 // The resolve job (running in worker pool) that this request is dependent on. | 233 // The resolve job (running in worker pool) that this request is dependent on. |
| 217 Job* job_; | 234 Job* job_; |
| 218 | 235 |
| 219 // The user's callback to invoke when the request completes. | 236 // The user's callback to invoke when the request completes. |
| 220 CompletionCallback* callback_; | 237 CompletionCallback* callback_; |
| 221 | 238 |
| 222 // The address list to save result into. | 239 // The address list to save result into. |
| 223 AddressList* addresses_; | 240 AddressList* addresses_; |
| 224 | 241 |
| 225 // The desired port number for the socket addresses. | |
| 226 int port_; | |
| 227 | |
| 228 DISALLOW_COPY_AND_ASSIGN(Request); | 242 DISALLOW_COPY_AND_ASSIGN(Request); |
| 229 }; | 243 }; |
| 230 | 244 |
| 231 //----------------------------------------------------------------------------- | 245 //----------------------------------------------------------------------------- |
| 232 | 246 |
| 233 // This class represents a request to the worker pool for a "getaddrinfo()" | 247 // This class represents a request to the worker pool for a "getaddrinfo()" |
| 234 // call. | 248 // call. |
| 235 class HostResolver::Job : public base::RefCountedThreadSafe<HostResolver::Job> { | 249 class HostResolver::Job : public base::RefCountedThreadSafe<HostResolver::Job> { |
| 236 public: | 250 public: |
| 237 Job(HostResolver* resolver, const std::string& host) | 251 Job(HostResolver* resolver, const std::string& host) |
| (...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 362 // Assigned on the worker thread, read on the origin thread. | 376 // Assigned on the worker thread, read on the origin thread. |
| 363 int error_; | 377 int error_; |
| 364 struct addrinfo* results_; | 378 struct addrinfo* results_; |
| 365 | 379 |
| 366 DISALLOW_COPY_AND_ASSIGN(Job); | 380 DISALLOW_COPY_AND_ASSIGN(Job); |
| 367 }; | 381 }; |
| 368 | 382 |
| 369 //----------------------------------------------------------------------------- | 383 //----------------------------------------------------------------------------- |
| 370 | 384 |
| 371 HostResolver::HostResolver(int max_cache_entries, int cache_duration_ms) | 385 HostResolver::HostResolver(int max_cache_entries, int cache_duration_ms) |
| 372 : cache_(max_cache_entries, cache_duration_ms) { | 386 : cache_(max_cache_entries, cache_duration_ms), next_request_id_(0) { |
| 373 #if defined(OS_WIN) | 387 #if defined(OS_WIN) |
| 374 EnsureWinsockInit(); | 388 EnsureWinsockInit(); |
| 375 #endif | 389 #endif |
| 376 } | 390 } |
| 377 | 391 |
| 378 HostResolver::~HostResolver() { | 392 HostResolver::~HostResolver() { |
| 379 // Cancel the outstanding jobs. Those jobs may contain several attached | 393 // Cancel the outstanding jobs. Those jobs may contain several attached |
| 380 // requests, which will now never be completed. | 394 // requests, which will now never be completed. |
| 381 for (JobMap::iterator it = jobs_.begin(); it != jobs_.end(); ++it) | 395 for (JobMap::iterator it = jobs_.begin(); it != jobs_.end(); ++it) |
| 382 it->second->Cancel(); | 396 it->second->Cancel(); |
| 383 | 397 |
| 384 // In case we are being deleted during the processing of a callback. | 398 // In case we are being deleted during the processing of a callback. |
| 385 if (cur_completing_job_) | 399 if (cur_completing_job_) |
| 386 cur_completing_job_->Cancel(); | 400 cur_completing_job_->Cancel(); |
| 387 } | 401 } |
| 388 | 402 |
| 389 // TODO(eroman): Don't create cache entries for hostnames which are simply IP | 403 // TODO(eroman): Don't create cache entries for hostnames which are simply IP |
| 390 // address literals. | 404 // address literals. |
| 391 int HostResolver::Resolve(const std::string& hostname, int port, | 405 int HostResolver::Resolve(const RequestInfo& info, |
| 392 AddressList* addresses, | 406 AddressList* addresses, |
| 393 CompletionCallback* callback, | 407 CompletionCallback* callback, |
| 394 Request** out_req) { | 408 Request** out_req) { |
| 409 // Choose a unique ID number for observers to see. |
| 410 int request_id = next_request_id_++; |
| 411 |
| 412 // Notify registered observers. |
| 413 NotifyObserversStartRequest(request_id, info); |
| 414 |
| 395 // If we have an unexpired cache entry, use it. | 415 // If we have an unexpired cache entry, use it. |
| 396 const HostCache::Entry* cache_entry = cache_.Lookup( | 416 if (info.allow_cached_response()) { |
| 397 hostname, base::TimeTicks::Now()); | 417 const HostCache::Entry* cache_entry = cache_.Lookup( |
| 398 if (cache_entry) { | 418 info.hostname(), base::TimeTicks::Now()); |
| 399 addresses->SetFrom(cache_entry->addrlist, port); | 419 if (cache_entry) { |
| 400 return OK; | 420 addresses->SetFrom(cache_entry->addrlist, info.port()); |
| 421 return OK; |
| 422 } |
| 401 } | 423 } |
| 402 | 424 |
| 403 // If no callback was specified, do a synchronous resolution. | 425 // If no callback was specified, do a synchronous resolution. |
| 404 if (!callback) { | 426 if (!callback) { |
| 405 struct addrinfo* results; | 427 struct addrinfo* results; |
| 406 int error = ResolveAddrInfo(host_mapper, hostname, &results); | 428 int error = ResolveAddrInfo(host_mapper, info.hostname(), &results); |
| 407 | 429 |
| 408 // Adopt the address list. | 430 // Adopt the address list. |
| 409 AddressList addrlist; | 431 AddressList addrlist; |
| 410 if (error == OK) { | 432 if (error == OK) { |
| 411 addrlist.Adopt(results); | 433 addrlist.Adopt(results); |
| 412 addrlist.SetPort(port); | 434 addrlist.SetPort(info.port()); |
| 413 *addresses = addrlist; | 435 *addresses = addrlist; |
| 414 } | 436 } |
| 415 | 437 |
| 416 // Write to cache. | 438 // Write to cache. |
| 417 cache_.Set(hostname, error, addrlist, base::TimeTicks::Now()); | 439 cache_.Set(info.hostname(), error, addrlist, base::TimeTicks::Now()); |
| 440 |
| 441 // Notify registered observers. |
| 442 NotifyObserversFinishRequest(request_id, info, error); |
| 418 | 443 |
| 419 return error; | 444 return error; |
| 420 } | 445 } |
| 421 | 446 |
| 422 // Create a handle for this request, and pass it back to the user if they | 447 // Create a handle for this request, and pass it back to the user if they |
| 423 // asked for it (out_req != NULL). | 448 // asked for it (out_req != NULL). |
| 424 Request* req = new Request(callback, addresses, port); | 449 Request* req = new Request(request_id, info, callback, addresses); |
| 425 if (out_req) | 450 if (out_req) |
| 426 *out_req = req; | 451 *out_req = req; |
| 427 | 452 |
| 428 // Next we need to attach our request to a "job". This job is responsible for | 453 // Next we need to attach our request to a "job". This job is responsible for |
| 429 // calling "getaddrinfo(hostname)" on a worker thread. | 454 // calling "getaddrinfo(hostname)" on a worker thread. |
| 430 scoped_refptr<Job> job; | 455 scoped_refptr<Job> job; |
| 431 | 456 |
| 432 // If there is already an outstanding job to resolve |hostname|, use it. | 457 // If there is already an outstanding job to resolve |info.hostname()|, use |
| 433 // This prevents starting concurrent resolves for the same hostname. | 458 // it. This prevents starting concurrent resolves for the same hostname. |
| 434 job = FindOutstandingJob(hostname); | 459 job = FindOutstandingJob(info.hostname()); |
| 435 if (job) { | 460 if (job) { |
| 436 job->AddRequest(req); | 461 job->AddRequest(req); |
| 437 } else { | 462 } else { |
| 438 // Create a new job for this request. | 463 // Create a new job for this request. |
| 439 job = new Job(this, hostname); | 464 job = new Job(this, info.hostname()); |
| 440 job->AddRequest(req); | 465 job->AddRequest(req); |
| 441 AddOutstandingJob(job); | 466 AddOutstandingJob(job); |
| 442 // TODO(eroman): Bound the total number of concurrent jobs. | 467 // TODO(eroman): Bound the total number of concurrent jobs. |
| 443 // http://crbug.com/9598 | 468 // http://crbug.com/9598 |
| 444 job->Start(); | 469 job->Start(); |
| 445 } | 470 } |
| 446 | 471 |
| 447 // Completion happens during OnJobComplete(Job*). | 472 // Completion happens during OnJobComplete(Job*). |
| 448 return ERR_IO_PENDING; | 473 return ERR_IO_PENDING; |
| 449 } | 474 } |
| 450 | 475 |
| 451 // See OnJobComplete(Job*) for why it is important not to clean out | 476 // See OnJobComplete(Job*) for why it is important not to clean out |
| 452 // cancelled requests from Job::requests_. | 477 // cancelled requests from Job::requests_. |
| 453 void HostResolver::CancelRequest(Request* req) { | 478 void HostResolver::CancelRequest(Request* req) { |
| 454 DCHECK(req); | 479 DCHECK(req); |
| 455 DCHECK(req->job()); | 480 DCHECK(req->job()); |
| 456 // NULL out the fields of req, to mark it as cancelled. | 481 // NULL out the fields of req, to mark it as cancelled. |
| 457 req->Cancel(); | 482 req->Cancel(); |
| 458 } | 483 } |
| 459 | 484 |
| 485 void HostResolver::AddObserver(DnsResolutionObserver* observer) { |
| 486 observers_.push_back(observer); |
| 487 } |
| 488 |
| 489 void HostResolver::RemoveObserver(DnsResolutionObserver* observer) { |
| 490 ObserversList::iterator it = |
| 491 std::find(observers_.begin(), observers_.end(), observer); |
| 492 |
| 493 // Observer must exist. |
| 494 DCHECK(it != observers_.end()); |
| 495 |
| 496 observers_.erase(it); |
| 497 } |
| 498 |
| 460 void HostResolver::AddOutstandingJob(Job* job) { | 499 void HostResolver::AddOutstandingJob(Job* job) { |
| 461 scoped_refptr<Job>& found_job = jobs_[job->host()]; | 500 scoped_refptr<Job>& found_job = jobs_[job->host()]; |
| 462 DCHECK(!found_job); | 501 DCHECK(!found_job); |
| 463 found_job = job; | 502 found_job = job; |
| 464 } | 503 } |
| 465 | 504 |
| 466 HostResolver::Job* HostResolver::FindOutstandingJob( | 505 HostResolver::Job* HostResolver::FindOutstandingJob( |
| 467 const std::string& hostname) { | 506 const std::string& hostname) { |
| 468 JobMap::iterator it = jobs_.find(hostname); | 507 JobMap::iterator it = jobs_.find(hostname); |
| 469 if (it != jobs_.end()) | 508 if (it != jobs_.end()) |
| (...skipping 20 matching lines...) Expand all Loading... |
| 490 // HostResolver is deleted by a callback invocation. | 529 // HostResolver is deleted by a callback invocation. |
| 491 DCHECK(!cur_completing_job_); | 530 DCHECK(!cur_completing_job_); |
| 492 cur_completing_job_ = job; | 531 cur_completing_job_ = job; |
| 493 | 532 |
| 494 // Complete all of the requests that were attached to the job. | 533 // Complete all of the requests that were attached to the job. |
| 495 for (RequestsList::const_iterator it = job->requests().begin(); | 534 for (RequestsList::const_iterator it = job->requests().begin(); |
| 496 it != job->requests().end(); ++it) { | 535 it != job->requests().end(); ++it) { |
| 497 Request* req = *it; | 536 Request* req = *it; |
| 498 if (!req->was_cancelled()) { | 537 if (!req->was_cancelled()) { |
| 499 DCHECK_EQ(job, req->job()); | 538 DCHECK_EQ(job, req->job()); |
| 539 |
| 540 // Notify registered observers. |
| 541 NotifyObserversFinishRequest(req->id(), req->info(), error); |
| 542 |
| 500 req->OnComplete(error, addrlist); | 543 req->OnComplete(error, addrlist); |
| 501 | 544 |
| 502 // Check if the job was cancelled as a result of running the callback. | 545 // Check if the job was cancelled as a result of running the callback. |
| 503 // (Meaning that |this| was deleted). | 546 // (Meaning that |this| was deleted). |
| 504 if (job->was_cancelled()) | 547 if (job->was_cancelled()) |
| 505 return; | 548 return; |
| 506 } | 549 } |
| 507 } | 550 } |
| 508 | 551 |
| 509 cur_completing_job_ = NULL; | 552 cur_completing_job_ = NULL; |
| 510 } | 553 } |
| 511 | 554 |
| 555 void HostResolver::NotifyObserversStartRequest(int request_id, |
| 556 const RequestInfo& info) { |
| 557 for (ObserversList::iterator it = observers_.begin(); |
| 558 it != observers_.end(); ++it) { |
| 559 (*it)->OnStartResolution(request_id, info); |
| 560 } |
| 561 } |
| 562 |
| 563 void HostResolver::NotifyObserversFinishRequest(int request_id, |
| 564 const RequestInfo& info, |
| 565 int error) { |
| 566 bool was_resolved = error == OK; |
| 567 for (ObserversList::iterator it = observers_.begin(); |
| 568 it != observers_.end(); ++it) { |
| 569 (*it)->OnFinishResolutionWithStatus(request_id, was_resolved, info); |
| 570 } |
| 571 } |
| 572 |
| 512 //----------------------------------------------------------------------------- | 573 //----------------------------------------------------------------------------- |
| 513 | 574 |
| 514 SingleRequestHostResolver::SingleRequestHostResolver(HostResolver* resolver) | 575 SingleRequestHostResolver::SingleRequestHostResolver(HostResolver* resolver) |
| 515 : resolver_(resolver), | 576 : resolver_(resolver), |
| 516 cur_request_(NULL), | 577 cur_request_(NULL), |
| 517 cur_request_callback_(NULL), | 578 cur_request_callback_(NULL), |
| 518 ALLOW_THIS_IN_INITIALIZER_LIST( | 579 ALLOW_THIS_IN_INITIALIZER_LIST( |
| 519 callback_(this, &SingleRequestHostResolver::OnResolveCompletion)) { | 580 callback_(this, &SingleRequestHostResolver::OnResolveCompletion)) { |
| 520 DCHECK(resolver_ != NULL); | 581 DCHECK(resolver_ != NULL); |
| 521 } | 582 } |
| 522 | 583 |
| 523 SingleRequestHostResolver::~SingleRequestHostResolver() { | 584 SingleRequestHostResolver::~SingleRequestHostResolver() { |
| 524 if (cur_request_) { | 585 if (cur_request_) { |
| 525 resolver_->CancelRequest(cur_request_); | 586 resolver_->CancelRequest(cur_request_); |
| 526 } | 587 } |
| 527 } | 588 } |
| 528 | 589 |
| 529 int SingleRequestHostResolver::Resolve( | 590 int SingleRequestHostResolver::Resolve(const HostResolver::RequestInfo& info, |
| 530 const std::string& hostname, int port, | 591 AddressList* addresses, |
| 531 AddressList* addresses, | 592 CompletionCallback* callback) { |
| 532 CompletionCallback* callback) { | |
| 533 DCHECK(!cur_request_ && !cur_request_callback_) << "resolver already in use"; | 593 DCHECK(!cur_request_ && !cur_request_callback_) << "resolver already in use"; |
| 534 | 594 |
| 535 HostResolver::Request* request = NULL; | 595 HostResolver::Request* request = NULL; |
| 536 | 596 |
| 537 // We need to be notified of completion before |callback| is called, so that | 597 // We need to be notified of completion before |callback| is called, so that |
| 538 // we can clear out |cur_request_*|. | 598 // we can clear out |cur_request_*|. |
| 539 CompletionCallback* transient_callback = callback ? &callback_ : NULL; | 599 CompletionCallback* transient_callback = callback ? &callback_ : NULL; |
| 540 | 600 |
| 541 int rv = resolver_->Resolve( | 601 int rv = resolver_->Resolve(info, addresses, transient_callback, &request); |
| 542 hostname, port, addresses, transient_callback, &request); | |
| 543 | 602 |
| 544 if (rv == ERR_IO_PENDING) { | 603 if (rv == ERR_IO_PENDING) { |
| 545 // Cleared in OnResolveCompletion(). | 604 // Cleared in OnResolveCompletion(). |
| 546 cur_request_ = request; | 605 cur_request_ = request; |
| 547 cur_request_callback_ = callback; | 606 cur_request_callback_ = callback; |
| 548 } | 607 } |
| 549 | 608 |
| 550 return rv; | 609 return rv; |
| 551 } | 610 } |
| 552 | 611 |
| 553 void SingleRequestHostResolver::OnResolveCompletion(int result) { | 612 void SingleRequestHostResolver::OnResolveCompletion(int result) { |
| 554 DCHECK(cur_request_ && cur_request_callback_); | 613 DCHECK(cur_request_ && cur_request_callback_); |
| 555 | 614 |
| 556 CompletionCallback* callback = cur_request_callback_; | 615 CompletionCallback* callback = cur_request_callback_; |
| 557 | 616 |
| 558 // Clear the outstanding request information. | 617 // Clear the outstanding request information. |
| 559 cur_request_ = NULL; | 618 cur_request_ = NULL; |
| 560 cur_request_callback_ = NULL; | 619 cur_request_callback_ = NULL; |
| 561 | 620 |
| 562 // Call the user's original callback. | 621 // Call the user's original callback. |
| 563 callback->Run(result); | 622 callback->Run(result); |
| 564 } | 623 } |
| 565 | 624 |
| 566 } // namespace net | 625 } // namespace net |
| OLD | NEW |