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