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 |