blob: 6fbd828869163c8ec70acf4735e796c0ac5c471d [file] [log] [blame]
[email protected]b59ff372009-07-15 22:04:321// 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
3// found in the LICENSE file.
4
5#include "net/base/host_resolver_impl.h"
6
[email protected]68ad3ee2010-01-30 03:45:397#include <cmath>
8#include <deque>
9
10#include "base/basictypes.h"
[email protected]b59ff372009-07-15 22:04:3211#include "base/compiler_specific.h"
[email protected]bf0b51c2009-08-01 23:46:4012#include "base/debug_util.h"
[email protected]f2d8c4212010-02-02 00:56:3513#include "base/lock.h"
[email protected]b59ff372009-07-15 22:04:3214#include "base/message_loop.h"
15#include "base/stl_util-inl.h"
16#include "base/string_util.h"
17#include "base/time.h"
18#include "base/worker_pool.h"
19#include "net/base/address_list.h"
20#include "net/base/host_resolver_proc.h"
[email protected]54e13772009-08-14 03:01:0921#include "net/base/load_log.h"
[email protected]b59ff372009-07-15 22:04:3222#include "net/base/net_errors.h"
[email protected]e95d3aca2010-01-11 22:47:4323#include "net/base/network_change_notifier.h"
[email protected]b59ff372009-07-15 22:04:3224
25#if defined(OS_WIN)
26#include "net/base/winsock_init.h"
27#endif
28
29namespace net {
30
[email protected]e95d3aca2010-01-11 22:47:4331namespace {
32
33HostCache* CreateDefaultCache() {
[email protected]b59ff372009-07-15 22:04:3234 static const size_t kMaxHostCacheEntries = 100;
[email protected]112bd462009-12-10 07:23:4035
36 HostCache* cache = new HostCache(
37 kMaxHostCacheEntries,
38 base::TimeDelta::FromMinutes(1),
39 base::TimeDelta::FromSeconds(1));
40
[email protected]e95d3aca2010-01-11 22:47:4341 return cache;
42}
43
44} // anonymous namespace
45
[email protected]d13c3272010-02-04 00:24:5146HostResolver* CreateSystemHostResolver(
47 NetworkChangeNotifier* network_change_notifier) {
[email protected]68ad3ee2010-01-30 03:45:3948 // Maximum of 50 concurrent threads.
49 // TODO(eroman): Adjust this, do some A/B experiments.
50 static const size_t kMaxJobs = 50u;
51
[email protected]e95d3aca2010-01-11 22:47:4352 // TODO(willchan): Pass in the NetworkChangeNotifier.
[email protected]68ad3ee2010-01-30 03:45:3953 HostResolverImpl* resolver = new HostResolverImpl(
[email protected]d13c3272010-02-04 00:24:5154 NULL, CreateDefaultCache(), network_change_notifier, kMaxJobs);
[email protected]68ad3ee2010-01-30 03:45:3955
56 return resolver;
[email protected]b59ff372009-07-15 22:04:3257}
58
59static int ResolveAddrInfo(HostResolverProc* resolver_proc,
[email protected]123ab1e32009-10-21 19:12:5760 const std::string& host,
61 AddressFamily address_family,
62 AddressList* out) {
[email protected]b59ff372009-07-15 22:04:3263 if (resolver_proc) {
64 // Use the custom procedure.
[email protected]123ab1e32009-10-21 19:12:5765 return resolver_proc->Resolve(host, address_family, out);
[email protected]b59ff372009-07-15 22:04:3266 } else {
67 // Use the system procedure (getaddrinfo).
[email protected]123ab1e32009-10-21 19:12:5768 return SystemHostResolverProc(host, address_family, out);
[email protected]b59ff372009-07-15 22:04:3269 }
70}
71
72//-----------------------------------------------------------------------------
73
74class HostResolverImpl::Request {
75 public:
[email protected]54e13772009-08-14 03:01:0976 Request(LoadLog* load_log,
77 int id,
78 const RequestInfo& info,
79 CompletionCallback* callback,
[email protected]b59ff372009-07-15 22:04:3280 AddressList* addresses)
[email protected]54e13772009-08-14 03:01:0981 : load_log_(load_log),
82 id_(id),
83 info_(info),
84 job_(NULL),
85 callback_(callback),
86 addresses_(addresses) {
87 }
[email protected]b59ff372009-07-15 22:04:3288
89 // Mark the request as cancelled.
90 void MarkAsCancelled() {
91 job_ = NULL;
92 callback_ = NULL;
93 addresses_ = NULL;
94 }
95
96 bool was_cancelled() const {
97 return callback_ == NULL;
98 }
99
100 void set_job(Job* job) {
101 DCHECK(job != NULL);
102 // Identify which job the request is waiting on.
103 job_ = job;
104 }
105
106 void OnComplete(int error, const AddressList& addrlist) {
107 if (error == OK)
108 addresses_->SetFrom(addrlist, port());
109 callback_->Run(error);
110 }
111
112 int port() const {
113 return info_.port();
114 }
115
116 Job* job() const {
117 return job_;
118 }
119
[email protected]54e13772009-08-14 03:01:09120 LoadLog* load_log() const {
121 return load_log_;
122 }
123
[email protected]b59ff372009-07-15 22:04:32124 int id() const {
125 return id_;
126 }
127
128 const RequestInfo& info() const {
129 return info_;
130 }
131
132 private:
[email protected]54e13772009-08-14 03:01:09133 scoped_refptr<LoadLog> load_log_;
134
[email protected]b59ff372009-07-15 22:04:32135 // Unique ID for this request. Used by observers to identify requests.
136 int id_;
137
138 // The request info that started the request.
139 RequestInfo info_;
140
141 // The resolve job (running in worker pool) that this request is dependent on.
142 Job* job_;
143
144 // The user's callback to invoke when the request completes.
145 CompletionCallback* callback_;
146
147 // The address list to save result into.
148 AddressList* addresses_;
149
150 DISALLOW_COPY_AND_ASSIGN(Request);
151};
152
153//-----------------------------------------------------------------------------
154
[email protected]f2d8c4212010-02-02 00:56:35155// Threadsafe log.
156class HostResolverImpl::RequestsTrace
157 : public base::RefCountedThreadSafe<HostResolverImpl::RequestsTrace> {
158 public:
159 RequestsTrace() : log_(new LoadLog(LoadLog::kUnbounded)) {}
160
161 void Add(const std::string& msg) {
162 AutoLock l(lock_);
163 LoadLog::AddString(log_, msg);
164 }
165
166 void Get(LoadLog* out) {
167 AutoLock l(lock_);
168 out->Append(log_);
169 }
170
171 void Clear() {
172 AutoLock l(lock_);
173 log_ = new LoadLog(LoadLog::kUnbounded);
174 }
175
176 private:
177 Lock lock_;
178 scoped_refptr<LoadLog> log_;
179};
180
181//-----------------------------------------------------------------------------
182
[email protected]b59ff372009-07-15 22:04:32183// This class represents a request to the worker pool for a "getaddrinfo()"
184// call.
185class HostResolverImpl::Job
186 : public base::RefCountedThreadSafe<HostResolverImpl::Job> {
187 public:
[email protected]f2d8c4212010-02-02 00:56:35188 Job(int id, HostResolverImpl* resolver, const Key& key,
189 RequestsTrace* requests_trace)
190 : id_(id), key_(key),
[email protected]b59ff372009-07-15 22:04:32191 resolver_(resolver),
192 origin_loop_(MessageLoop::current()),
193 resolver_proc_(resolver->effective_resolver_proc()),
[email protected]f2d8c4212010-02-02 00:56:35194 requests_trace_(requests_trace),
[email protected]b59ff372009-07-15 22:04:32195 error_(OK) {
[email protected]f2d8c4212010-02-02 00:56:35196 if (requests_trace_) {
197 requests_trace_->Add(StringPrintf(
198 "Created job j%d for {hostname='%s', address_family=%d}",
199 id_, key.hostname.c_str(),
200 static_cast<int>(key.address_family)));
201 }
[email protected]b59ff372009-07-15 22:04:32202 }
203
[email protected]b59ff372009-07-15 22:04:32204 // Attaches a request to this job. The job takes ownership of |req| and will
205 // take care to delete it.
206 void AddRequest(Request* req) {
[email protected]f2d8c4212010-02-02 00:56:35207 if (requests_trace_) {
208 requests_trace_->Add(StringPrintf(
209 "Attached request r%d to job j%d", req->id(), id_));
210 }
211
[email protected]b59ff372009-07-15 22:04:32212 req->set_job(this);
213 requests_.push_back(req);
214 }
215
216 // Called from origin loop.
217 void Start() {
[email protected]f2d8c4212010-02-02 00:56:35218 if (requests_trace_)
219 requests_trace_->Add(StringPrintf("Starting job j%d", id_));
220
[email protected]b59ff372009-07-15 22:04:32221 // Dispatch the job to a worker thread.
222 if (!WorkerPool::PostTask(FROM_HERE,
223 NewRunnableMethod(this, &Job::DoLookup), true)) {
224 NOTREACHED();
225
226 // Since we could be running within Resolve() right now, we can't just
227 // call OnLookupComplete(). Instead we must wait until Resolve() has
228 // returned (IO_PENDING).
229 error_ = ERR_UNEXPECTED;
230 MessageLoop::current()->PostTask(
231 FROM_HERE, NewRunnableMethod(this, &Job::OnLookupComplete));
232 }
233 }
234
235 // Cancels the current job. Callable from origin thread.
236 void Cancel() {
237 HostResolver* resolver = resolver_;
238 resolver_ = NULL;
239
[email protected]f2d8c4212010-02-02 00:56:35240 if (requests_trace_)
241 requests_trace_->Add(StringPrintf("Cancelled job j%d", id_));
242
[email protected]b59ff372009-07-15 22:04:32243 // Mark the job as cancelled, so when worker thread completes it will
244 // not try to post completion to origin loop.
245 {
246 AutoLock locked(origin_loop_lock_);
247 origin_loop_ = NULL;
248 }
249
[email protected]1877a2212009-09-18 21:09:26250 // We will call HostResolverImpl::CancelRequest(Request*) on each one
[email protected]27f99c82009-10-29 22:21:00251 // in order to notify any observers.
[email protected]b59ff372009-07-15 22:04:32252 for (RequestsList::const_iterator it = requests_.begin();
253 it != requests_.end(); ++it) {
254 HostResolverImpl::Request* req = *it;
255 if (!req->was_cancelled())
256 resolver->CancelRequest(req);
257 }
258 }
259
260 // Called from origin thread.
261 bool was_cancelled() const {
262 return resolver_ == NULL;
263 }
264
265 // Called from origin thread.
[email protected]123ab1e32009-10-21 19:12:57266 const Key& key() const {
267 return key_;
[email protected]b59ff372009-07-15 22:04:32268 }
269
[email protected]a2fbebe2010-02-05 01:40:12270 int id() const {
271 return id_;
272 }
273
[email protected]b59ff372009-07-15 22:04:32274 // Called from origin thread.
275 const RequestsList& requests() const {
276 return requests_;
277 }
278
[email protected]68ad3ee2010-01-30 03:45:39279 // Returns the first request attached to the job.
280 const Request* initial_request() const {
281 DCHECK_EQ(origin_loop_, MessageLoop::current());
282 DCHECK(!requests_.empty());
283 return requests_[0];
284 }
285
[email protected]137af622010-02-05 02:14:35286 // Returns true if |req_info| can be fulfilled by this job.
287 bool CanServiceRequest(const RequestInfo& req_info) const {
288 return key_ == resolver_->GetEffectiveKeyForRequest(req_info);
289 }
290
[email protected]b59ff372009-07-15 22:04:32291 private:
[email protected]5389bc72009-11-05 23:34:24292 friend class base::RefCountedThreadSafe<HostResolverImpl::Job>;
293
294 ~Job() {
295 // Free the requests attached to this job.
296 STLDeleteElements(&requests_);
297 }
298
[email protected]b59ff372009-07-15 22:04:32299 void DoLookup() {
[email protected]f2d8c4212010-02-02 00:56:35300 if (requests_trace_) {
301 requests_trace_->Add(StringPrintf(
302 "[resolver thread] Running job j%d", id_));
303 }
304
[email protected]b59ff372009-07-15 22:04:32305 // Running on the worker thread
[email protected]123ab1e32009-10-21 19:12:57306 error_ = ResolveAddrInfo(resolver_proc_,
307 key_.hostname,
308 key_.address_family,
309 &results_);
[email protected]b59ff372009-07-15 22:04:32310
[email protected]f2d8c4212010-02-02 00:56:35311 if (requests_trace_) {
312 requests_trace_->Add(StringPrintf(
313 "[resolver thread] Completed job j%d", id_));
314 }
315
[email protected]b59ff372009-07-15 22:04:32316 Task* reply = NewRunnableMethod(this, &Job::OnLookupComplete);
317
318 // The origin loop could go away while we are trying to post to it, so we
319 // need to call its PostTask method inside a lock. See ~HostResolver.
320 {
321 AutoLock locked(origin_loop_lock_);
322 if (origin_loop_) {
323 origin_loop_->PostTask(FROM_HERE, reply);
324 reply = NULL;
325 }
326 }
327
328 // Does nothing if it got posted.
329 delete reply;
330 }
331
332 // Callback for when DoLookup() completes (runs on origin thread).
333 void OnLookupComplete() {
334 // Should be running on origin loop.
335 // TODO(eroman): this is being hit by URLRequestTest.CancelTest*,
336 // because MessageLoop::current() == NULL.
337 //DCHECK_EQ(origin_loop_, MessageLoop::current());
338 DCHECK(error_ || results_.head());
339
[email protected]f2d8c4212010-02-02 00:56:35340 if (requests_trace_)
341 requests_trace_->Add(StringPrintf("Completing job j%d", id_));
342
[email protected]b59ff372009-07-15 22:04:32343 if (was_cancelled())
344 return;
345
346 DCHECK(!requests_.empty());
347
348 // Use the port number of the first request.
349 if (error_ == OK)
350 results_.SetPort(requests_[0]->port());
351
352 resolver_->OnJobComplete(this, error_, results_);
353 }
354
[email protected]f2d8c4212010-02-02 00:56:35355 // Immutable. Can be read from either thread,
356 const int id_;
357
[email protected]b59ff372009-07-15 22:04:32358 // Set on the origin thread, read on the worker thread.
[email protected]123ab1e32009-10-21 19:12:57359 Key key_;
[email protected]b59ff372009-07-15 22:04:32360
361 // Only used on the origin thread (where Resolve was called).
362 HostResolverImpl* resolver_;
363 RequestsList requests_; // The requests waiting on this job.
364
365 // Used to post ourselves onto the origin thread.
366 Lock origin_loop_lock_;
367 MessageLoop* origin_loop_;
368
369 // Hold an owning reference to the HostResolverProc that we are going to use.
370 // This may not be the current resolver procedure by the time we call
371 // ResolveAddrInfo, but that's OK... we'll use it anyways, and the owning
372 // reference ensures that it remains valid until we are done.
373 scoped_refptr<HostResolverProc> resolver_proc_;
374
[email protected]f2d8c4212010-02-02 00:56:35375 // Thread safe log to write details into, or NULL.
376 scoped_refptr<RequestsTrace> requests_trace_;
377
[email protected]b59ff372009-07-15 22:04:32378 // Assigned on the worker thread, read on the origin thread.
379 int error_;
380 AddressList results_;
381
382 DISALLOW_COPY_AND_ASSIGN(Job);
383};
384
385//-----------------------------------------------------------------------------
386
[email protected]68ad3ee2010-01-30 03:45:39387// We rely on the priority enum values being sequential having starting at 0,
388// and increasing for lower priorities.
389COMPILE_ASSERT(HIGHEST == 0u &&
390 LOWEST > HIGHEST &&
391 NUM_PRIORITIES > LOWEST,
392 priority_indexes_incompatible);
393
394// JobPool contains all the information relating to queued requests, including
395// the limits on how many jobs are allowed to be used for this category of
396// requests.
397class HostResolverImpl::JobPool {
398 public:
399 JobPool(size_t max_outstanding_jobs, size_t max_pending_requests)
400 : num_outstanding_jobs_(0u) {
401 SetConstraints(max_outstanding_jobs, max_pending_requests);
402 }
403
404 ~JobPool() {
405 // Free the pending requests.
406 for (size_t i = 0; i < arraysize(pending_requests_); ++i)
407 STLDeleteElements(&pending_requests_[i]);
408 }
409
410 // Sets the constraints for this pool. See SetPoolConstraints() for the
411 // specific meaning of these parameters.
412 void SetConstraints(size_t max_outstanding_jobs,
413 size_t max_pending_requests) {
414 CHECK(max_outstanding_jobs != 0u);
415 max_outstanding_jobs_ = max_outstanding_jobs;
416 max_pending_requests_ = max_pending_requests;
417 }
418
419 // Returns the number of pending requests enqueued to this pool.
420 // A pending request is one waiting to be attached to a job.
421 size_t GetNumPendingRequests() const {
422 size_t total = 0u;
423 for (size_t i = 0u; i < arraysize(pending_requests_); ++i)
424 total += pending_requests_[i].size();
425 return total;
426 }
427
428 bool HasPendingRequests() const {
429 return GetNumPendingRequests() > 0u;
430 }
431
432 // Enqueues a request to this pool. As a result of enqueing this request,
433 // the queue may have reached its maximum size. In this case, a request is
434 // evicted from the queue, and returned. Otherwise returns NULL. The caller
435 // is responsible for freeing the evicted request.
436 Request* InsertPendingRequest(Request* req) {
437 PendingRequestsQueue& q = pending_requests_[req->info().priority()];
438 q.push_back(req);
439
440 // If the queue is too big, kick out the lowest priority oldest request.
441 if (GetNumPendingRequests() > max_pending_requests_) {
442 // Iterate over the queues from lowest priority to highest priority.
443 for (int i = static_cast<int>(arraysize(pending_requests_)) - 1;
444 i >= 0; --i) {
445 PendingRequestsQueue& q = pending_requests_[i];
446 if (!q.empty()) {
447 Request* req = q.front();
448 q.pop_front();
449 return req;
450 }
451 }
452 }
453
454 return NULL;
455 }
456
457 // Erases |req| from this container. Caller is responsible for freeing
458 // |req| afterwards.
459 void RemovePendingRequest(Request* req) {
460 PendingRequestsQueue& q = pending_requests_[req->info().priority()];
461 PendingRequestsQueue::iterator it = std::find(q.begin(), q.end(), req);
462 DCHECK(it != q.end());
463 q.erase(it);
464 }
465
466 // Removes and returns the highest priority pending request.
467 Request* RemoveTopPendingRequest() {
468 DCHECK(HasPendingRequests());
469
470 for (size_t i = 0u; i < arraysize(pending_requests_); ++i) {
471 PendingRequestsQueue& q = pending_requests_[i];
472 if (!q.empty()) {
473 Request* req = q.front();
474 q.pop_front();
475 return req;
476 }
477 }
478
479 NOTREACHED();
480 return NULL;
481 }
482
483 // Keeps track of a job that was just added/removed, and belongs to this pool.
484 void AdjustNumOutstandingJobs(int offset) {
485 DCHECK(offset == 1 || (offset == -1 && num_outstanding_jobs_ > 0u));
486 num_outstanding_jobs_ += offset;
487 }
488
489 // Returns true if a new job can be created for this pool.
490 bool CanCreateJob() const {
491 return num_outstanding_jobs_ + 1u <= max_outstanding_jobs_;
492 }
493
494 // Removes any pending requests from the queue which are for the
[email protected]137af622010-02-05 02:14:35495 // same (hostname / effective address-family) as |job|, and attaches them to
496 // |job|.
[email protected]68ad3ee2010-01-30 03:45:39497 void MoveRequestsToJob(Job* job) {
498 for (size_t i = 0u; i < arraysize(pending_requests_); ++i) {
499 PendingRequestsQueue& q = pending_requests_[i];
500 PendingRequestsQueue::iterator req_it = q.begin();
501 while (req_it != q.end()) {
502 Request* req = *req_it;
[email protected]137af622010-02-05 02:14:35503 if (job->CanServiceRequest(req->info())) {
[email protected]68ad3ee2010-01-30 03:45:39504 // Job takes ownership of |req|.
505 job->AddRequest(req);
506 req_it = q.erase(req_it);
507 } else {
508 ++req_it;
509 }
510 }
511 }
512 }
513
514 private:
515 typedef std::deque<Request*> PendingRequestsQueue;
516
517 // Maximum number of concurrent jobs allowed to be started for requests
518 // belonging to this pool.
519 size_t max_outstanding_jobs_;
520
521 // The current number of running jobs that were started for requests
522 // belonging to this pool.
523 size_t num_outstanding_jobs_;
524
525 // The maximum number of requests we allow to be waiting on a job,
526 // for this pool.
527 size_t max_pending_requests_;
528
529 // The requests which are waiting to be started for this pool.
530 PendingRequestsQueue pending_requests_[NUM_PRIORITIES];
531};
532
533//-----------------------------------------------------------------------------
534
[email protected]e95d3aca2010-01-11 22:47:43535HostResolverImpl::HostResolverImpl(
536 HostResolverProc* resolver_proc,
537 HostCache* cache,
[email protected]d13c3272010-02-04 00:24:51538 NetworkChangeNotifier* network_change_notifier,
[email protected]68ad3ee2010-01-30 03:45:39539 size_t max_jobs)
[email protected]112bd462009-12-10 07:23:40540 : cache_(cache),
[email protected]68ad3ee2010-01-30 03:45:39541 max_jobs_(max_jobs),
[email protected]123ab1e32009-10-21 19:12:57542 next_request_id_(0),
[email protected]f2d8c4212010-02-02 00:56:35543 next_job_id_(0),
[email protected]123ab1e32009-10-21 19:12:57544 resolver_proc_(resolver_proc),
[email protected]0c7798452009-10-26 17:59:51545 default_address_family_(ADDRESS_FAMILY_UNSPECIFIED),
[email protected]e95d3aca2010-01-11 22:47:43546 shutdown_(false),
547 network_change_notifier_(network_change_notifier) {
[email protected]68ad3ee2010-01-30 03:45:39548 DCHECK_GT(max_jobs, 0u);
549
550 // It is cumbersome to expose all of the constraints in the constructor,
551 // so we choose some defaults, which users can override later.
552 job_pools_[POOL_NORMAL] = new JobPool(max_jobs, 100u * max_jobs);
553
[email protected]b59ff372009-07-15 22:04:32554#if defined(OS_WIN)
555 EnsureWinsockInit();
556#endif
[email protected]e95d3aca2010-01-11 22:47:43557 if (network_change_notifier_)
558 network_change_notifier_->AddObserver(this);
[email protected]b59ff372009-07-15 22:04:32559}
560
561HostResolverImpl::~HostResolverImpl() {
562 // Cancel the outstanding jobs. Those jobs may contain several attached
563 // requests, which will also be cancelled.
564 for (JobMap::iterator it = jobs_.begin(); it != jobs_.end(); ++it)
565 it->second->Cancel();
566
567 // In case we are being deleted during the processing of a callback.
568 if (cur_completing_job_)
569 cur_completing_job_->Cancel();
[email protected]e95d3aca2010-01-11 22:47:43570
571 if (network_change_notifier_)
572 network_change_notifier_->RemoveObserver(this);
[email protected]68ad3ee2010-01-30 03:45:39573
574 // Delete the job pools.
575 for (size_t i = 0u; i < arraysize(job_pools_); ++i)
576 delete job_pools_[i];
[email protected]b59ff372009-07-15 22:04:32577}
578
579// TODO(eroman): Don't create cache entries for hostnames which are simply IP
580// address literals.
[email protected]684970b2009-08-14 04:54:46581int HostResolverImpl::Resolve(const RequestInfo& info,
[email protected]b59ff372009-07-15 22:04:32582 AddressList* addresses,
583 CompletionCallback* callback,
[email protected]684970b2009-08-14 04:54:46584 RequestHandle* out_req,
585 LoadLog* load_log) {
[email protected]b59ff372009-07-15 22:04:32586 if (shutdown_)
587 return ERR_UNEXPECTED;
588
589 // Choose a unique ID number for observers to see.
590 int request_id = next_request_id_++;
591
[email protected]54e13772009-08-14 03:01:09592 // Update the load log and notify registered observers.
593 OnStartRequest(load_log, request_id, info);
[email protected]b59ff372009-07-15 22:04:32594
[email protected]123ab1e32009-10-21 19:12:57595 // Build a key that identifies the request in the cache and in the
596 // outstanding jobs map.
[email protected]137af622010-02-05 02:14:35597 Key key = GetEffectiveKeyForRequest(info);
[email protected]123ab1e32009-10-21 19:12:57598
[email protected]b59ff372009-07-15 22:04:32599 // If we have an unexpired cache entry, use it.
[email protected]112bd462009-12-10 07:23:40600 if (info.allow_cached_response() && cache_.get()) {
601 const HostCache::Entry* cache_entry = cache_->Lookup(
[email protected]123ab1e32009-10-21 19:12:57602 key, base::TimeTicks::Now());
[email protected]b59ff372009-07-15 22:04:32603 if (cache_entry) {
[email protected]b59ff372009-07-15 22:04:32604 int error = cache_entry->error;
[email protected]112bd462009-12-10 07:23:40605 if (error == OK)
606 addresses->SetFrom(cache_entry->addrlist, info.port());
[email protected]b59ff372009-07-15 22:04:32607
[email protected]54e13772009-08-14 03:01:09608 // Update the load log and notify registered observers.
609 OnFinishRequest(load_log, request_id, info, error);
[email protected]b59ff372009-07-15 22:04:32610
611 return error;
612 }
613 }
614
615 // If no callback was specified, do a synchronous resolution.
616 if (!callback) {
617 AddressList addrlist;
618 int error = ResolveAddrInfo(
[email protected]123ab1e32009-10-21 19:12:57619 effective_resolver_proc(), key.hostname, key.address_family, &addrlist);
[email protected]b59ff372009-07-15 22:04:32620 if (error == OK) {
621 addrlist.SetPort(info.port());
622 *addresses = addrlist;
623 }
624
625 // Write to cache.
[email protected]112bd462009-12-10 07:23:40626 if (cache_.get())
627 cache_->Set(key, error, addrlist, base::TimeTicks::Now());
[email protected]b59ff372009-07-15 22:04:32628
[email protected]54e13772009-08-14 03:01:09629 // Update the load log and notify registered observers.
630 OnFinishRequest(load_log, request_id, info, error);
[email protected]b59ff372009-07-15 22:04:32631
632 return error;
633 }
634
635 // Create a handle for this request, and pass it back to the user if they
636 // asked for it (out_req != NULL).
[email protected]54e13772009-08-14 03:01:09637 Request* req = new Request(load_log, request_id, info, callback, addresses);
[email protected]b59ff372009-07-15 22:04:32638 if (out_req)
639 *out_req = reinterpret_cast<RequestHandle>(req);
640
641 // Next we need to attach our request to a "job". This job is responsible for
642 // calling "getaddrinfo(hostname)" on a worker thread.
643 scoped_refptr<Job> job;
644
[email protected]123ab1e32009-10-21 19:12:57645 // If there is already an outstanding job to resolve |key|, use
[email protected]b59ff372009-07-15 22:04:32646 // it. This prevents starting concurrent resolves for the same hostname.
[email protected]123ab1e32009-10-21 19:12:57647 job = FindOutstandingJob(key);
[email protected]b59ff372009-07-15 22:04:32648 if (job) {
649 job->AddRequest(req);
650 } else {
[email protected]68ad3ee2010-01-30 03:45:39651 JobPool* pool = GetPoolForRequest(req);
652 if (CanCreateJobForPool(*pool)) {
653 CreateAndStartJob(req);
654 } else {
655 return EnqueueRequest(pool, req);
656 }
[email protected]b59ff372009-07-15 22:04:32657 }
658
659 // Completion happens during OnJobComplete(Job*).
660 return ERR_IO_PENDING;
661}
662
663// See OnJobComplete(Job*) for why it is important not to clean out
664// cancelled requests from Job::requests_.
665void HostResolverImpl::CancelRequest(RequestHandle req_handle) {
[email protected]bf0b51c2009-08-01 23:46:40666 if (shutdown_) {
[email protected]ff1f61b92009-08-03 23:20:23667 // TODO(eroman): temp hack for: http://crbug.com/18373
668 // Because we destroy outstanding requests during Shutdown(),
669 // |req_handle| is already cancelled.
[email protected]bf0b51c2009-08-01 23:46:40670 LOG(ERROR) << "Called HostResolverImpl::CancelRequest() after Shutdown().";
671 StackTrace().PrintBacktrace();
672 return;
673 }
[email protected]b59ff372009-07-15 22:04:32674 Request* req = reinterpret_cast<Request*>(req_handle);
675 DCHECK(req);
[email protected]68ad3ee2010-01-30 03:45:39676
677 scoped_ptr<Request> request_deleter; // Frees at end of function.
678
679 if (!req->job()) {
680 // If the request was not attached to a job yet, it must have been
681 // enqueued into a pool. Remove it from that pool's queue.
682 // Otherwise if it was attached to a job, the job is responsible for
683 // deleting it.
684 JobPool* pool = GetPoolForRequest(req);
685 pool->RemovePendingRequest(req);
686 request_deleter.reset(req);
687 }
688
[email protected]b59ff372009-07-15 22:04:32689 // NULL out the fields of req, to mark it as cancelled.
690 req->MarkAsCancelled();
[email protected]27f99c82009-10-29 22:21:00691 OnCancelRequest(req->load_log(), req->id(), req->info());
[email protected]b59ff372009-07-15 22:04:32692}
693
[email protected]e95d3aca2010-01-11 22:47:43694void HostResolverImpl::AddObserver(HostResolver::Observer* observer) {
[email protected]b59ff372009-07-15 22:04:32695 observers_.push_back(observer);
696}
697
[email protected]e95d3aca2010-01-11 22:47:43698void HostResolverImpl::RemoveObserver(HostResolver::Observer* observer) {
[email protected]b59ff372009-07-15 22:04:32699 ObserversList::iterator it =
700 std::find(observers_.begin(), observers_.end(), observer);
701
702 // Observer must exist.
703 DCHECK(it != observers_.end());
704
705 observers_.erase(it);
706}
707
[email protected]b59ff372009-07-15 22:04:32708void HostResolverImpl::Shutdown() {
709 shutdown_ = true;
710
711 // Cancel the outstanding jobs.
712 for (JobMap::iterator it = jobs_.begin(); it != jobs_.end(); ++it)
713 it->second->Cancel();
714 jobs_.clear();
715}
716
[email protected]f2d8c4212010-02-02 00:56:35717void HostResolverImpl::ClearRequestsTrace() {
718 if (requests_trace_)
719 requests_trace_->Clear();
720}
721
722void HostResolverImpl::EnableRequestsTracing(bool enable) {
723 requests_trace_ = enable ? new RequestsTrace : NULL;
724 if (enable) {
725 // Print the state of the world when logging was started.
726 requests_trace_->Add("Enabled tracing");
727 requests_trace_->Add(StringPrintf(
728 "Current num outstanding jobs: %d",
729 static_cast<int>(jobs_.size())));
730
[email protected]a2fbebe2010-02-05 01:40:12731 // Dump all of the outstanding jobs.
732 if (!jobs_.empty()) {
733 for (JobMap::iterator job_it = jobs_.begin();
734 job_it != jobs_.end(); ++job_it) {
735 Job* job = job_it->second;
736
737 requests_trace_->Add(StringPrintf(
738 "Outstanding job j%d for {host='%s', address_family=%d}",
739 job->id(),
740 job->key().hostname.c_str(),
741 static_cast<int>(job->key().address_family)));
742
743 // Dump all of the requests attached to this job.
744 for (RequestsList::const_iterator req_it = job->requests().begin();
745 req_it != job->requests().end(); ++req_it) {
746 Request* req = *req_it;
747 requests_trace_->Add(StringPrintf(
748 " %sOutstanding request r%d is attached to job j%d "
749 "{priority=%d, speculative=%d, referrer='%s'}",
750 req->was_cancelled() ? "[CANCELLED] " : "",
751 req->id(),
752 job->id(),
753 static_cast<int>(req->info().priority()),
754 static_cast<int>(req->info().is_speculative()),
755 req->info().referrer().spec().c_str()));
756 }
757 }
758 }
759
[email protected]f2d8c4212010-02-02 00:56:35760 size_t total = 0u;
761 for (size_t i = 0; i < arraysize(job_pools_); ++i)
762 total += job_pools_[i]->GetNumPendingRequests();
763
764 requests_trace_->Add(StringPrintf(
765 "Number of queued requests: %d", static_cast<int>(total)));
766 }
767}
768
769bool HostResolverImpl::IsRequestsTracingEnabled() const {
770 return !!requests_trace_; // Cast to bool.
771}
772
773scoped_refptr<LoadLog> HostResolverImpl::GetRequestsTrace() {
774 if (!requests_trace_)
775 return NULL;
776
777 scoped_refptr<LoadLog> copy_of_log = new LoadLog(LoadLog::kUnbounded);
778 requests_trace_->Get(copy_of_log);
779 return copy_of_log;
780}
781
[email protected]68ad3ee2010-01-30 03:45:39782void HostResolverImpl::SetPoolConstraints(JobPoolIndex pool_index,
783 size_t max_outstanding_jobs,
784 size_t max_pending_requests) {
785 CHECK(pool_index >= 0);
786 CHECK(pool_index < POOL_COUNT);
787 CHECK(jobs_.empty()) << "Can only set constraints during setup";
788 JobPool* pool = job_pools_[pool_index];
789 pool->SetConstraints(max_outstanding_jobs, max_pending_requests);
790}
791
[email protected]b59ff372009-07-15 22:04:32792void HostResolverImpl::AddOutstandingJob(Job* job) {
[email protected]123ab1e32009-10-21 19:12:57793 scoped_refptr<Job>& found_job = jobs_[job->key()];
[email protected]b59ff372009-07-15 22:04:32794 DCHECK(!found_job);
795 found_job = job;
[email protected]68ad3ee2010-01-30 03:45:39796
797 JobPool* pool = GetPoolForRequest(job->initial_request());
798 pool->AdjustNumOutstandingJobs(1);
[email protected]b59ff372009-07-15 22:04:32799}
800
[email protected]123ab1e32009-10-21 19:12:57801HostResolverImpl::Job* HostResolverImpl::FindOutstandingJob(const Key& key) {
802 JobMap::iterator it = jobs_.find(key);
[email protected]b59ff372009-07-15 22:04:32803 if (it != jobs_.end())
804 return it->second;
805 return NULL;
806}
807
808void HostResolverImpl::RemoveOutstandingJob(Job* job) {
[email protected]123ab1e32009-10-21 19:12:57809 JobMap::iterator it = jobs_.find(job->key());
[email protected]b59ff372009-07-15 22:04:32810 DCHECK(it != jobs_.end());
811 DCHECK_EQ(it->second.get(), job);
812 jobs_.erase(it);
[email protected]68ad3ee2010-01-30 03:45:39813
814 JobPool* pool = GetPoolForRequest(job->initial_request());
815 pool->AdjustNumOutstandingJobs(-1);
[email protected]b59ff372009-07-15 22:04:32816}
817
818void HostResolverImpl::OnJobComplete(Job* job,
[email protected]27f99c82009-10-29 22:21:00819 int error,
820 const AddressList& addrlist) {
[email protected]b59ff372009-07-15 22:04:32821 RemoveOutstandingJob(job);
822
823 // Write result to the cache.
[email protected]112bd462009-12-10 07:23:40824 if (cache_.get())
825 cache_->Set(job->key(), error, addrlist, base::TimeTicks::Now());
[email protected]b59ff372009-07-15 22:04:32826
827 // Make a note that we are executing within OnJobComplete() in case the
828 // HostResolver is deleted by a callback invocation.
829 DCHECK(!cur_completing_job_);
830 cur_completing_job_ = job;
831
[email protected]68ad3ee2010-01-30 03:45:39832 // Try to start any queued requests now that a job-slot has freed up.
833 ProcessQueuedRequests();
834
[email protected]b59ff372009-07-15 22:04:32835 // Complete all of the requests that were attached to the job.
836 for (RequestsList::const_iterator it = job->requests().begin();
837 it != job->requests().end(); ++it) {
838 Request* req = *it;
839 if (!req->was_cancelled()) {
840 DCHECK_EQ(job, req->job());
841
[email protected]54e13772009-08-14 03:01:09842 // Update the load log and notify registered observers.
843 OnFinishRequest(req->load_log(), req->id(), req->info(), error);
[email protected]b59ff372009-07-15 22:04:32844
845 req->OnComplete(error, addrlist);
846
847 // Check if the job was cancelled as a result of running the callback.
848 // (Meaning that |this| was deleted).
849 if (job->was_cancelled())
850 return;
851 }
852 }
853
854 cur_completing_job_ = NULL;
855}
856
[email protected]54e13772009-08-14 03:01:09857void HostResolverImpl::OnStartRequest(LoadLog* load_log,
858 int request_id,
859 const RequestInfo& info) {
860 LoadLog::BeginEvent(load_log, LoadLog::TYPE_HOST_RESOLVER_IMPL);
861
[email protected]f2d8c4212010-02-02 00:56:35862 if (requests_trace_) {
863 requests_trace_->Add(StringPrintf(
864 "Received request r%d for {hostname='%s', port=%d, priority=%d, "
865 "speculative=%d, address_family=%d, allow_cached=%d, referrer='%s'}",
866 request_id,
867 info.hostname().c_str(),
868 info.port(),
869 static_cast<int>(info.priority()),
870 static_cast<int>(info.is_speculative()),
871 static_cast<int>(info.address_family()),
872 static_cast<int>(info.allow_cached_response()),
873 info.referrer().spec().c_str()));
874 }
875
[email protected]54e13772009-08-14 03:01:09876 // Notify the observers of the start.
877 if (!observers_.empty()) {
878 LoadLog::BeginEvent(
879 load_log, LoadLog::TYPE_HOST_RESOLVER_IMPL_OBSERVER_ONSTART);
880
881 for (ObserversList::iterator it = observers_.begin();
882 it != observers_.end(); ++it) {
883 (*it)->OnStartResolution(request_id, info);
884 }
885
886 LoadLog::EndEvent(
887 load_log, LoadLog::TYPE_HOST_RESOLVER_IMPL_OBSERVER_ONSTART);
[email protected]b59ff372009-07-15 22:04:32888 }
889}
890
[email protected]54e13772009-08-14 03:01:09891void HostResolverImpl::OnFinishRequest(LoadLog* load_log,
892 int request_id,
893 const RequestInfo& info,
894 int error) {
[email protected]f2d8c4212010-02-02 00:56:35895 if (requests_trace_) {
896 requests_trace_->Add(StringPrintf(
897 "Finished request r%d with error=%d", request_id, error));
898 }
899
[email protected]54e13772009-08-14 03:01:09900 // Notify the observers of the completion.
901 if (!observers_.empty()) {
902 LoadLog::BeginEvent(
903 load_log, LoadLog::TYPE_HOST_RESOLVER_IMPL_OBSERVER_ONFINISH);
904
905 bool was_resolved = error == OK;
906 for (ObserversList::iterator it = observers_.begin();
907 it != observers_.end(); ++it) {
908 (*it)->OnFinishResolutionWithStatus(request_id, was_resolved, info);
909 }
910
911 LoadLog::EndEvent(
912 load_log, LoadLog::TYPE_HOST_RESOLVER_IMPL_OBSERVER_ONFINISH);
[email protected]b59ff372009-07-15 22:04:32913 }
[email protected]54e13772009-08-14 03:01:09914
915 LoadLog::EndEvent(load_log, LoadLog::TYPE_HOST_RESOLVER_IMPL);
[email protected]b59ff372009-07-15 22:04:32916}
917
[email protected]54e13772009-08-14 03:01:09918void HostResolverImpl::OnCancelRequest(LoadLog* load_log,
919 int request_id,
920 const RequestInfo& info) {
921 LoadLog::AddEvent(load_log, LoadLog::TYPE_CANCELLED);
922
[email protected]f2d8c4212010-02-02 00:56:35923 if (requests_trace_)
924 requests_trace_->Add(StringPrintf("Cancelled request r%d", request_id));
925
[email protected]54e13772009-08-14 03:01:09926 // Notify the observers of the cancellation.
927 if (!observers_.empty()) {
928 LoadLog::BeginEvent(
929 load_log, LoadLog::TYPE_HOST_RESOLVER_IMPL_OBSERVER_ONCANCEL);
930
931 for (ObserversList::iterator it = observers_.begin();
932 it != observers_.end(); ++it) {
933 (*it)->OnCancelResolution(request_id, info);
934 }
935
936 LoadLog::EndEvent(
937 load_log, LoadLog::TYPE_HOST_RESOLVER_IMPL_OBSERVER_ONCANCEL);
[email protected]b59ff372009-07-15 22:04:32938 }
[email protected]54e13772009-08-14 03:01:09939
940 LoadLog::EndEvent(load_log, LoadLog::TYPE_HOST_RESOLVER_IMPL);
[email protected]b59ff372009-07-15 22:04:32941}
942
[email protected]e95d3aca2010-01-11 22:47:43943void HostResolverImpl::OnIPAddressChanged() {
944 if (cache_.get())
945 cache_->clear();
946}
947
[email protected]68ad3ee2010-01-30 03:45:39948// static
949HostResolverImpl::JobPoolIndex HostResolverImpl::GetJobPoolIndexForRequest(
950 const Request* req) {
951 return POOL_NORMAL;
952}
953
954bool HostResolverImpl::CanCreateJobForPool(const JobPool& pool) const {
955 DCHECK_LE(jobs_.size(), max_jobs_);
956
957 // We can't create another job if it would exceed the global total.
958 if (jobs_.size() + 1 > max_jobs_)
959 return false;
960
961 // Check whether the pool's constraints are met.
962 return pool.CanCreateJob();
963}
964
965void HostResolverImpl::ProcessQueuedRequests() {
966 // Find the highest priority request that can be scheduled.
967 Request* top_req = NULL;
968 for (size_t i = 0; i < arraysize(job_pools_); ++i) {
969 JobPool* pool = job_pools_[i];
970 if (pool->HasPendingRequests() && CanCreateJobForPool(*pool)) {
971 top_req = pool->RemoveTopPendingRequest();
972 break;
973 }
974 }
975
976 if (!top_req)
977 return;
978
979 scoped_refptr<Job> job = CreateAndStartJob(top_req);
980
981 // Search for any other pending request which can piggy-back off this job.
982 for (size_t pool_i = 0; pool_i < POOL_COUNT; ++pool_i) {
983 JobPool* pool = job_pools_[pool_i];
984 pool->MoveRequestsToJob(job);
985 }
986}
987
[email protected]137af622010-02-05 02:14:35988HostResolverImpl::Key HostResolverImpl::GetEffectiveKeyForRequest(
989 const RequestInfo& info) const {
990 AddressFamily effective_address_family = info.address_family();
991 if (effective_address_family == ADDRESS_FAMILY_UNSPECIFIED)
992 effective_address_family = default_address_family_;
993 return Key(info.hostname(), effective_address_family);
994}
995
[email protected]68ad3ee2010-01-30 03:45:39996HostResolverImpl::Job* HostResolverImpl::CreateAndStartJob(Request* req) {
997 DCHECK(CanCreateJobForPool(*GetPoolForRequest(req)));
[email protected]137af622010-02-05 02:14:35998 Key key = GetEffectiveKeyForRequest(req->info());
[email protected]f2d8c4212010-02-02 00:56:35999 scoped_refptr<Job> job = new Job(next_job_id_++, this, key, requests_trace_);
[email protected]68ad3ee2010-01-30 03:45:391000 job->AddRequest(req);
1001 AddOutstandingJob(job);
1002 job->Start();
1003 return job.get();
1004}
1005
1006int HostResolverImpl::EnqueueRequest(JobPool* pool, Request* req) {
[email protected]f2d8c4212010-02-02 00:56:351007 if (requests_trace_)
1008 requests_trace_->Add(StringPrintf("Queued request r%d", req->id()));
1009
[email protected]68ad3ee2010-01-30 03:45:391010 scoped_ptr<Request> req_evicted_from_queue(
1011 pool->InsertPendingRequest(req));
1012
1013 // If the queue has become too large, we need to kick something out.
1014 if (req_evicted_from_queue.get()) {
1015 Request* r = req_evicted_from_queue.get();
1016 int error = ERR_HOST_RESOLVER_QUEUE_TOO_LARGE;
1017
[email protected]f2d8c4212010-02-02 00:56:351018 if (requests_trace_)
1019 requests_trace_->Add(StringPrintf("Evicted request r%d", r->id()));
1020
[email protected]68ad3ee2010-01-30 03:45:391021 OnFinishRequest(r->load_log(), r->id(), r->info(), error);
1022
1023 if (r == req)
1024 return error;
1025
1026 r->OnComplete(error, AddressList());
1027 }
1028
1029 return ERR_IO_PENDING;
1030}
1031
[email protected]b59ff372009-07-15 22:04:321032} // namespace net