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_proc.h" |
| 6 |
| 7 #include "build/build_config.h" |
6 | 8 |
7 #if defined(OS_WIN) | 9 #if defined(OS_WIN) |
8 #include <ws2tcpip.h> | 10 #include <ws2tcpip.h> |
9 #include <wspiapi.h> // Needed for Win2k compat. | 11 #include <wspiapi.h> // Needed for Win2k compat. |
10 #elif defined(OS_POSIX) | 12 #elif defined(OS_POSIX) |
11 #include <netdb.h> | 13 #include <netdb.h> |
12 #include <sys/socket.h> | 14 #include <sys/socket.h> |
13 #endif | 15 #endif |
14 #if defined(OS_LINUX) | 16 #if defined(OS_LINUX) |
15 #include <resolv.h> | 17 #include <resolv.h> |
16 #endif | 18 #endif |
17 | 19 |
18 #include "base/compiler_specific.h" | 20 #include "base/logging.h" |
19 #include "base/message_loop.h" | |
20 #include "base/stl_util-inl.h" | |
21 #include "base/string_util.h" | |
22 #include "base/time.h" | 21 #include "base/time.h" |
23 #include "base/worker_pool.h" | |
24 #include "net/base/address_list.h" | 22 #include "net/base/address_list.h" |
25 #include "net/base/net_errors.h" | 23 #include "net/base/net_errors.h" |
26 | 24 |
27 #if defined(OS_LINUX) | 25 #if defined(OS_LINUX) |
28 #include "base/singleton.h" | 26 #include "base/singleton.h" |
29 #include "base/thread_local_storage.h" | 27 #include "base/thread_local_storage.h" |
30 #endif | 28 #endif |
31 | 29 |
32 #if defined(OS_WIN) | |
33 #include "net/base/winsock_init.h" | |
34 #endif | |
35 | |
36 namespace net { | 30 namespace net { |
37 | 31 |
38 //----------------------------------------------------------------------------- | 32 HostResolverProc* HostResolverProc::default_proc_ = NULL; |
39 | 33 |
40 static HostMapper* host_mapper; | 34 HostResolverProc::HostResolverProc(HostResolverProc* previous) { |
| 35 set_previous_proc(previous); |
41 | 36 |
42 std::string HostMapper::MapUsingPrevious(const std::string& host) { | 37 // Implicitly fall-back to the global default procedure. |
43 return previous_mapper_.get() ? previous_mapper_->Map(host) : host; | 38 if (!previous) |
| 39 set_previous_proc(default_proc_); |
44 } | 40 } |
45 | 41 |
46 HostMapper* SetHostMapper(HostMapper* value) { | 42 // static |
47 std::swap(host_mapper, value); | 43 HostResolverProc* HostResolverProc::SetDefault(HostResolverProc* proc) { |
48 return value; | 44 HostResolverProc* old = default_proc_; |
| 45 default_proc_ = proc; |
| 46 return old; |
| 47 } |
| 48 |
| 49 // static |
| 50 HostResolverProc* HostResolverProc::GetDefault() { |
| 51 return default_proc_; |
| 52 } |
| 53 |
| 54 int HostResolverProc::ResolveUsingPrevious(const std::string& host, |
| 55 AddressList* addrlist) { |
| 56 if (previous_proc_) |
| 57 return previous_proc_->Resolve(host, addrlist); |
| 58 |
| 59 // Final fallback is the system resolver. |
| 60 return SystemHostResolverProc(host, addrlist); |
49 } | 61 } |
50 | 62 |
51 #if defined(OS_LINUX) | 63 #if defined(OS_LINUX) |
52 // On Linux changes to /etc/resolv.conf can go unnoticed thus resulting in | 64 // On Linux changes to /etc/resolv.conf can go unnoticed thus resulting in |
53 // DNS queries failing either because nameservers are unknown on startup | 65 // 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 | 66 // 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 | 67 // 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 | 68 // 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 | 69 // universal and even patched systems such as Jaunty appear to need calls |
58 // to res_ninit to reload the nameserver information in different threads. | 70 // to res_ninit to reload the nameserver information in different threads. |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
105 | 117 |
106 DISALLOW_COPY_AND_ASSIGN(DnsReloadTimer); | 118 DISALLOW_COPY_AND_ASSIGN(DnsReloadTimer); |
107 }; | 119 }; |
108 | 120 |
109 // A TLS slot to the TimeTicks for the current thread. | 121 // A TLS slot to the TimeTicks for the current thread. |
110 // static | 122 // static |
111 ThreadLocalStorage::Slot DnsReloadTimer::tls_index_(base::LINKER_INITIALIZED); | 123 ThreadLocalStorage::Slot DnsReloadTimer::tls_index_(base::LINKER_INITIALIZED); |
112 | 124 |
113 #endif // defined(OS_LINUX) | 125 #endif // defined(OS_LINUX) |
114 | 126 |
115 static int HostResolverProc(const std::string& host, struct addrinfo** out) { | 127 int SystemHostResolverProc(const std::string& host, AddressList* addrlist) { |
| 128 struct addrinfo* ai = NULL; |
116 struct addrinfo hints = {0}; | 129 struct addrinfo hints = {0}; |
117 hints.ai_family = AF_UNSPEC; | 130 hints.ai_family = AF_UNSPEC; |
118 | 131 |
119 #if defined(OS_WIN) | 132 #if defined(OS_WIN) |
120 // DO NOT USE AI_ADDRCONFIG ON WINDOWS. | 133 // DO NOT USE AI_ADDRCONFIG ON WINDOWS. |
121 // | 134 // |
122 // The following comment in <winsock2.h> is the best documentation I found | 135 // The following comment in <winsock2.h> is the best documentation I found |
123 // on AI_ADDRCONFIG for Windows: | 136 // on AI_ADDRCONFIG for Windows: |
124 // Flags used in "hints" argument to getaddrinfo() | 137 // Flags used in "hints" argument to getaddrinfo() |
125 // - AI_ADDRCONFIG is supported starting with Vista | 138 // - AI_ADDRCONFIG is supported starting with Vista |
(...skipping 12 matching lines...) Expand all Loading... |
138 // address. | 151 // address. |
139 // See http://crbug.com/5234. | 152 // See http://crbug.com/5234. |
140 hints.ai_flags = 0; | 153 hints.ai_flags = 0; |
141 #else | 154 #else |
142 hints.ai_flags = AI_ADDRCONFIG; | 155 hints.ai_flags = AI_ADDRCONFIG; |
143 #endif | 156 #endif |
144 | 157 |
145 // Restrict result set to only this socket type to avoid duplicates. | 158 // Restrict result set to only this socket type to avoid duplicates. |
146 hints.ai_socktype = SOCK_STREAM; | 159 hints.ai_socktype = SOCK_STREAM; |
147 | 160 |
148 int err = getaddrinfo(host.c_str(), NULL, &hints, out); | 161 int err = getaddrinfo(host.c_str(), NULL, &hints, &ai); |
149 #if defined(OS_LINUX) | 162 #if defined(OS_LINUX) |
150 net::DnsReloadTimer* dns_timer = Singleton<net::DnsReloadTimer>::get(); | 163 net::DnsReloadTimer* dns_timer = Singleton<net::DnsReloadTimer>::get(); |
151 // If we fail, re-initialise the resolver just in case there have been any | 164 // 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. | 165 // changes to /etc/resolv.conf and retry. See http://crbug.com/11380 for info. |
153 if (err && dns_timer->Expired()) { | 166 if (err && dns_timer->Expired()) { |
154 res_nclose(&_res); | 167 res_nclose(&_res); |
155 if (!res_ninit(&_res)) | 168 if (!res_ninit(&_res)) |
156 err = getaddrinfo(host.c_str(), NULL, &hints, out); | 169 err = getaddrinfo(host.c_str(), NULL, &hints, &ai); |
157 } | 170 } |
158 #endif | 171 #endif |
159 | 172 |
160 return err ? ERR_NAME_NOT_RESOLVED : OK; | 173 if (err) |
161 } | 174 return ERR_NAME_NOT_RESOLVED; |
162 | 175 |
163 static int ResolveAddrInfo(HostMapper* mapper, const std::string& host, | 176 addrlist->Adopt(ai); |
164 struct addrinfo** out) { | 177 return OK; |
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) | |
618 : resolver_(resolver), | |
619 cur_request_(NULL), | |
620 cur_request_callback_(NULL), | |
621 ALLOW_THIS_IN_INITIALIZER_LIST( | |
622 callback_(this, &SingleRequestHostResolver::OnResolveCompletion)) { | |
623 DCHECK(resolver_ != NULL); | |
624 } | |
625 | |
626 SingleRequestHostResolver::~SingleRequestHostResolver() { | |
627 if (cur_request_) { | |
628 resolver_->CancelRequest(cur_request_); | |
629 } | |
630 } | |
631 | |
632 int SingleRequestHostResolver::Resolve(const HostResolver::RequestInfo& info, | |
633 AddressList* addresses, | |
634 CompletionCallback* callback) { | |
635 DCHECK(!cur_request_ && !cur_request_callback_) << "resolver already in use"; | |
636 | |
637 HostResolver::Request* request = NULL; | |
638 | |
639 // We need to be notified of completion before |callback| is called, so that | |
640 // we can clear out |cur_request_*|. | |
641 CompletionCallback* transient_callback = callback ? &callback_ : NULL; | |
642 | |
643 int rv = resolver_->Resolve(info, addresses, transient_callback, &request); | |
644 | |
645 if (rv == ERR_IO_PENDING) { | |
646 // Cleared in OnResolveCompletion(). | |
647 cur_request_ = request; | |
648 cur_request_callback_ = callback; | |
649 } | |
650 | |
651 return rv; | |
652 } | |
653 | |
654 void SingleRequestHostResolver::OnResolveCompletion(int result) { | |
655 DCHECK(cur_request_ && cur_request_callback_); | |
656 | |
657 CompletionCallback* callback = cur_request_callback_; | |
658 | |
659 // Clear the outstanding request information. | |
660 cur_request_ = NULL; | |
661 cur_request_callback_ = NULL; | |
662 | |
663 // Call the user's original callback. | |
664 callback->Run(result); | |
665 } | 178 } |
666 | 179 |
667 } // namespace net | 180 } // namespace net |
OLD | NEW |