| 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 |