OLD | NEW |
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/base/host_resolver.h" | 5 #include "net/base/host_resolver.h" |
6 | 6 |
7 #if defined(OS_WIN) | 7 #if defined(OS_WIN) |
8 #include <ws2tcpip.h> | 8 #include <ws2tcpip.h> |
9 #include <wspiapi.h> // Needed for Win2k compat. | 9 #include <wspiapi.h> // Needed for Win2k compat. |
10 #elif defined(OS_POSIX) | 10 #elif defined(OS_POSIX) |
11 #include <netdb.h> | 11 #include <netdb.h> |
12 #include <sys/socket.h> | 12 #include <sys/socket.h> |
13 #endif | 13 #endif |
14 #if defined(OS_LINUX) | 14 #if defined(OS_LINUX) |
15 #include <resolv.h> | 15 #include <resolv.h> |
16 #endif | 16 #endif |
17 | 17 |
| 18 #include "base/compiler_specific.h" |
18 #include "base/message_loop.h" | 19 #include "base/message_loop.h" |
| 20 #include "base/stl_util-inl.h" |
19 #include "base/string_util.h" | 21 #include "base/string_util.h" |
| 22 #include "base/time.h" |
20 #include "base/worker_pool.h" | 23 #include "base/worker_pool.h" |
21 #include "net/base/address_list.h" | 24 #include "net/base/address_list.h" |
22 #include "net/base/net_errors.h" | 25 #include "net/base/net_errors.h" |
23 | 26 |
24 #if defined(OS_LINUX) | 27 #if defined(OS_LINUX) |
25 #include "base/singleton.h" | 28 #include "base/singleton.h" |
26 #include "base/thread_local_storage.h" | 29 #include "base/thread_local_storage.h" |
27 #include "base/time.h" | |
28 #endif | 30 #endif |
29 | 31 |
30 #if defined(OS_WIN) | 32 #if defined(OS_WIN) |
31 #include "net/base/winsock_init.h" | 33 #include "net/base/winsock_init.h" |
32 #endif | 34 #endif |
33 | 35 |
34 namespace net { | 36 namespace net { |
35 | 37 |
36 //----------------------------------------------------------------------------- | 38 //----------------------------------------------------------------------------- |
37 | 39 |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
103 | 105 |
104 DISALLOW_COPY_AND_ASSIGN(DnsReloadTimer); | 106 DISALLOW_COPY_AND_ASSIGN(DnsReloadTimer); |
105 }; | 107 }; |
106 | 108 |
107 // A TLS slot to the TimeTicks for the current thread. | 109 // A TLS slot to the TimeTicks for the current thread. |
108 // static | 110 // static |
109 ThreadLocalStorage::Slot DnsReloadTimer::tls_index_(base::LINKER_INITIALIZED); | 111 ThreadLocalStorage::Slot DnsReloadTimer::tls_index_(base::LINKER_INITIALIZED); |
110 | 112 |
111 #endif // defined(OS_LINUX) | 113 #endif // defined(OS_LINUX) |
112 | 114 |
113 static int HostResolverProc( | 115 static int HostResolverProc(const std::string& host, struct addrinfo** out) { |
114 const std::string& host, const std::string& port, struct addrinfo** out) { | |
115 struct addrinfo hints = {0}; | 116 struct addrinfo hints = {0}; |
116 hints.ai_family = AF_UNSPEC; | 117 hints.ai_family = AF_UNSPEC; |
117 | 118 |
118 #if defined(OS_WIN) | 119 #if defined(OS_WIN) |
119 // DO NOT USE AI_ADDRCONFIG ON WINDOWS. | 120 // DO NOT USE AI_ADDRCONFIG ON WINDOWS. |
120 // | 121 // |
121 // The following comment in <winsock2.h> is the best documentation I found | 122 // The following comment in <winsock2.h> is the best documentation I found |
122 // on AI_ADDRCONFIG for Windows: | 123 // on AI_ADDRCONFIG for Windows: |
123 // Flags used in "hints" argument to getaddrinfo() | 124 // Flags used in "hints" argument to getaddrinfo() |
124 // - AI_ADDRCONFIG is supported starting with Vista | 125 // - AI_ADDRCONFIG is supported starting with Vista |
(...skipping 12 matching lines...) Expand all Loading... |
137 // address. | 138 // address. |
138 // See http://crbug.com/5234. | 139 // See http://crbug.com/5234. |
139 hints.ai_flags = 0; | 140 hints.ai_flags = 0; |
140 #else | 141 #else |
141 hints.ai_flags = AI_ADDRCONFIG; | 142 hints.ai_flags = AI_ADDRCONFIG; |
142 #endif | 143 #endif |
143 | 144 |
144 // Restrict result set to only this socket type to avoid duplicates. | 145 // Restrict result set to only this socket type to avoid duplicates. |
145 hints.ai_socktype = SOCK_STREAM; | 146 hints.ai_socktype = SOCK_STREAM; |
146 | 147 |
147 int err = getaddrinfo(host.c_str(), port.c_str(), &hints, out); | 148 int err = getaddrinfo(host.c_str(), NULL, &hints, out); |
148 #if defined(OS_LINUX) | 149 #if defined(OS_LINUX) |
149 net::DnsReloadTimer* dns_timer = Singleton<net::DnsReloadTimer>::get(); | 150 net::DnsReloadTimer* dns_timer = Singleton<net::DnsReloadTimer>::get(); |
150 // If we fail, re-initialise the resolver just in case there have been any | 151 // If we fail, re-initialise the resolver just in case there have been any |
151 // changes to /etc/resolv.conf and retry. See http://crbug.com/11380 for info. | 152 // changes to /etc/resolv.conf and retry. See http://crbug.com/11380 for info. |
152 if (err && dns_timer->Expired()) { | 153 if (err && dns_timer->Expired()) { |
153 res_nclose(&_res); | 154 res_nclose(&_res); |
154 if (!res_ninit(&_res)) | 155 if (!res_ninit(&_res)) |
155 err = getaddrinfo(host.c_str(), port.c_str(), &hints, out); | 156 err = getaddrinfo(host.c_str(), NULL, &hints, out); |
156 } | 157 } |
157 #endif | 158 #endif |
158 | 159 |
159 return err ? ERR_NAME_NOT_RESOLVED : OK; | 160 return err ? ERR_NAME_NOT_RESOLVED : OK; |
160 } | 161 } |
161 | 162 |
162 static int ResolveAddrInfo(HostMapper* mapper, const std::string& host, | 163 static int ResolveAddrInfo(HostMapper* mapper, const std::string& host, |
163 const std::string& port, struct addrinfo** out) { | 164 struct addrinfo** out) { |
164 if (mapper) { | 165 if (mapper) { |
165 std::string mapped_host = mapper->Map(host); | 166 std::string mapped_host = mapper->Map(host); |
166 | 167 |
167 if (mapped_host.empty()) | 168 if (mapped_host.empty()) |
168 return ERR_NAME_NOT_RESOLVED; | 169 return ERR_NAME_NOT_RESOLVED; |
169 | 170 |
170 return HostResolverProc(mapped_host, port, out); | 171 return HostResolverProc(mapped_host, out); |
171 } else { | 172 } else { |
172 return HostResolverProc(host, port, out); | 173 return HostResolverProc(host, out); |
173 } | 174 } |
174 } | 175 } |
175 | 176 |
176 //----------------------------------------------------------------------------- | 177 //----------------------------------------------------------------------------- |
177 | 178 |
178 class HostResolver::Request : | 179 class HostResolver::Request { |
179 public base::RefCountedThreadSafe<HostResolver::Request> { | |
180 public: | 180 public: |
181 Request(HostResolver* resolver, | 181 Request(CompletionCallback* callback, AddressList* addresses, int port) |
182 const std::string& host, | 182 : job_(NULL), callback_(callback), addresses_(addresses), port_(port) {} |
183 const std::string& port, | 183 |
184 AddressList* addresses, | 184 // Mark the request as cancelled. |
185 CompletionCallback* callback) | 185 void Cancel() { |
| 186 job_ = NULL; |
| 187 callback_ = NULL; |
| 188 addresses_ = NULL; |
| 189 } |
| 190 |
| 191 bool was_cancelled() const { |
| 192 return callback_ == NULL; |
| 193 } |
| 194 |
| 195 void set_job(Job* job) { |
| 196 DCHECK(job != NULL); |
| 197 // Identify which job the request is waiting on. |
| 198 job_ = job; |
| 199 } |
| 200 |
| 201 void OnComplete(int error, const AddressList& addrlist) { |
| 202 if (error == OK) |
| 203 addresses_->SetFrom(addrlist, port_); |
| 204 callback_->Run(error); |
| 205 } |
| 206 |
| 207 int port() const { |
| 208 return port_; |
| 209 } |
| 210 |
| 211 Job* job() const { |
| 212 return job_; |
| 213 } |
| 214 |
| 215 private: |
| 216 // The resolve job (running in worker pool) that this request is dependent on. |
| 217 Job* job_; |
| 218 |
| 219 // The user's callback to invoke when the request completes. |
| 220 CompletionCallback* callback_; |
| 221 |
| 222 // The address list to save result into. |
| 223 AddressList* addresses_; |
| 224 |
| 225 // The desired port number for the socket addresses. |
| 226 int port_; |
| 227 |
| 228 DISALLOW_COPY_AND_ASSIGN(Request); |
| 229 }; |
| 230 |
| 231 //----------------------------------------------------------------------------- |
| 232 |
| 233 // This class represents a request to the worker pool for a "getaddrinfo()" |
| 234 // call. |
| 235 class HostResolver::Job : public base::RefCountedThreadSafe<HostResolver::Job> { |
| 236 public: |
| 237 Job(HostResolver* resolver, const std::string& host) |
186 : host_(host), | 238 : host_(host), |
187 port_(port), | |
188 resolver_(resolver), | 239 resolver_(resolver), |
189 addresses_(addresses), | |
190 callback_(callback), | |
191 origin_loop_(MessageLoop::current()), | 240 origin_loop_(MessageLoop::current()), |
192 host_mapper_(host_mapper), | 241 host_mapper_(host_mapper), |
193 error_(OK), | 242 error_(OK), |
194 results_(NULL) { | 243 results_(NULL) { |
195 } | 244 } |
196 | 245 |
197 ~Request() { | 246 ~Job() { |
198 if (results_) | 247 if (results_) |
199 freeaddrinfo(results_); | 248 freeaddrinfo(results_); |
| 249 |
| 250 // Free the requests attached to this job. |
| 251 STLDeleteElements(&requests_); |
200 } | 252 } |
201 | 253 |
| 254 // Attaches a request to this job. The job takes ownership of |req| and will |
| 255 // take care to delete it. |
| 256 void AddRequest(HostResolver::Request* req) { |
| 257 req->set_job(this); |
| 258 requests_.push_back(req); |
| 259 } |
| 260 |
| 261 // Called from origin loop. |
| 262 void Start() { |
| 263 // Dispatch the job to a worker thread. |
| 264 if (!WorkerPool::PostTask(FROM_HERE, |
| 265 NewRunnableMethod(this, &Job::DoLookup), true)) { |
| 266 NOTREACHED(); |
| 267 |
| 268 // Since we could be running within Resolve() right now, we can't just |
| 269 // call OnLookupComplete(). Instead we must wait until Resolve() has |
| 270 // returned (IO_PENDING). |
| 271 error_ = ERR_UNEXPECTED; |
| 272 MessageLoop::current()->PostTask( |
| 273 FROM_HERE, NewRunnableMethod(this, &Job::OnLookupComplete)); |
| 274 } |
| 275 } |
| 276 |
| 277 // Cancels the current job. Callable from origin thread. |
| 278 void Cancel() { |
| 279 resolver_ = NULL; |
| 280 |
| 281 AutoLock locked(origin_loop_lock_); |
| 282 origin_loop_ = NULL; |
| 283 } |
| 284 |
| 285 // Called from origin thread. |
| 286 bool was_cancelled() const { |
| 287 return resolver_ == NULL; |
| 288 } |
| 289 |
| 290 // Called from origin thread. |
| 291 const std::string& host() const { |
| 292 return host_; |
| 293 } |
| 294 |
| 295 // Called from origin thread. |
| 296 const RequestsList& requests() const { |
| 297 return requests_; |
| 298 } |
| 299 |
| 300 private: |
202 void DoLookup() { | 301 void DoLookup() { |
203 // Running on the worker thread | 302 // Running on the worker thread |
204 error_ = ResolveAddrInfo(host_mapper_, host_, port_, &results_); | 303 error_ = ResolveAddrInfo(host_mapper_, host_, &results_); |
205 | 304 |
206 Task* reply = NewRunnableMethod(this, &Request::DoCallback); | 305 Task* reply = NewRunnableMethod(this, &Job::OnLookupComplete); |
207 | 306 |
208 // The origin loop could go away while we are trying to post to it, so we | 307 // The origin loop could go away while we are trying to post to it, so we |
209 // need to call its PostTask method inside a lock. See ~HostResolver. | 308 // need to call its PostTask method inside a lock. See ~HostResolver. |
210 { | 309 { |
211 AutoLock locked(origin_loop_lock_); | 310 AutoLock locked(origin_loop_lock_); |
212 if (origin_loop_) { | 311 if (origin_loop_) { |
213 origin_loop_->PostTask(FROM_HERE, reply); | 312 origin_loop_->PostTask(FROM_HERE, reply); |
214 reply = NULL; | 313 reply = NULL; |
215 } | 314 } |
216 } | 315 } |
217 | 316 |
218 // Does nothing if it got posted. | 317 // Does nothing if it got posted. |
219 delete reply; | 318 delete reply; |
220 } | 319 } |
221 | 320 |
222 void DoCallback() { | 321 // Callback for when DoLookup() completes (runs on origin thread). |
223 // Running on the origin thread. | 322 void OnLookupComplete() { |
| 323 DCHECK_EQ(origin_loop_, MessageLoop::current()); |
224 DCHECK(error_ || results_); | 324 DCHECK(error_ || results_); |
225 | 325 |
226 // We may have been cancelled! | 326 if (was_cancelled()) |
227 if (!resolver_) | |
228 return; | 327 return; |
229 | 328 |
230 if (!error_) { | 329 DCHECK(!requests_.empty()); |
231 addresses_->Adopt(results_); | 330 |
| 331 // Adopt the address list using the port number of the first request. |
| 332 AddressList addrlist; |
| 333 if (error_ == OK) { |
| 334 addrlist.Adopt(results_); |
| 335 addrlist.SetPort(requests_[0]->port()); |
232 results_ = NULL; | 336 results_ = NULL; |
233 } | 337 } |
234 | 338 |
235 // Drop the resolver's reference to us. Do this before running the | 339 resolver_->OnJobComplete(this, error_, addrlist); |
236 // callback since the callback might result in the resolver being | |
237 // destroyed. | |
238 resolver_->request_ = NULL; | |
239 | |
240 callback_->Run(error_); | |
241 } | 340 } |
242 | 341 |
243 void Cancel() { | |
244 resolver_ = NULL; | |
245 | |
246 AutoLock locked(origin_loop_lock_); | |
247 origin_loop_ = NULL; | |
248 } | |
249 | |
250 private: | |
251 // Set on the origin thread, read on the worker thread. | 342 // Set on the origin thread, read on the worker thread. |
252 std::string host_; | 343 std::string host_; |
253 std::string port_; | |
254 | 344 |
255 // Only used on the origin thread (where Resolve was called). | 345 // Only used on the origin thread (where Resolve was called). |
256 HostResolver* resolver_; | 346 HostResolver* resolver_; |
257 AddressList* addresses_; | 347 RequestsList requests_; // The requests waiting on this job. |
258 CompletionCallback* callback_; | |
259 | 348 |
260 // Used to post ourselves onto the origin thread. | 349 // Used to post ourselves onto the origin thread. |
261 Lock origin_loop_lock_; | 350 Lock origin_loop_lock_; |
262 MessageLoop* origin_loop_; | 351 MessageLoop* origin_loop_; |
263 | 352 |
264 // Hold an owning reference to the host mapper that we are going to use. | 353 // Hold an owning reference to the host mapper that we are going to use. |
265 // This may not be the current host mapper by the time we call | 354 // This may not be the current host mapper by the time we call |
266 // ResolveAddrInfo, but that's OK... we'll use it anyways, and the owning | 355 // ResolveAddrInfo, but that's OK... we'll use it anyways, and the owning |
267 // reference ensures that it remains valid until we are done. | 356 // reference ensures that it remains valid until we are done. |
268 scoped_refptr<HostMapper> host_mapper_; | 357 scoped_refptr<HostMapper> host_mapper_; |
269 | 358 |
270 // Assigned on the worker thread, read on the origin thread. | 359 // Assigned on the worker thread, read on the origin thread. |
271 int error_; | 360 int error_; |
272 struct addrinfo* results_; | 361 struct addrinfo* results_; |
| 362 |
| 363 DISALLOW_COPY_AND_ASSIGN(Job); |
273 }; | 364 }; |
274 | 365 |
275 //----------------------------------------------------------------------------- | 366 //----------------------------------------------------------------------------- |
276 | 367 |
277 HostResolver::HostResolver() { | 368 HostResolver::HostResolver(int max_cache_entries, int cache_duration_ms) |
| 369 : cache_(max_cache_entries, cache_duration_ms) { |
278 #if defined(OS_WIN) | 370 #if defined(OS_WIN) |
279 EnsureWinsockInit(); | 371 EnsureWinsockInit(); |
280 #endif | 372 #endif |
281 } | 373 } |
282 | 374 |
283 HostResolver::~HostResolver() { | 375 HostResolver::~HostResolver() { |
284 if (request_) | 376 // Cancel the outstanding jobs. Those jobs may contain several attached |
285 request_->Cancel(); | 377 // requests, which will now never be completed. |
286 } | 378 for (JobMap::iterator it = jobs_.begin(); it != jobs_.end(); ++it) |
287 | 379 it->second->Cancel(); |
| 380 |
| 381 // In case we are being deleted during the processing of a callback. |
| 382 if (cur_completing_job_) |
| 383 cur_completing_job_->Cancel(); |
| 384 } |
| 385 |
| 386 // TODO(eroman): Don't create cache entries for hostnames which are simply IP |
| 387 // address literals. |
288 int HostResolver::Resolve(const std::string& hostname, int port, | 388 int HostResolver::Resolve(const std::string& hostname, int port, |
289 AddressList* addresses, | 389 AddressList* addresses, |
290 CompletionCallback* callback) { | 390 CompletionCallback* callback, |
291 DCHECK(!request_) << "resolver already in use"; | 391 Request** out_req) { |
292 | 392 // If we have an unexpired cache entry, use it. |
293 const std::string& port_str = IntToString(port); | 393 const HostCache::Entry* cache_entry = cache_.Lookup( |
294 | 394 hostname, base::TimeTicks::Now()); |
295 // Do a synchronous resolution. | 395 if (cache_entry) { |
| 396 addresses->SetFrom(cache_entry->addrlist, port); |
| 397 return OK; |
| 398 } |
| 399 |
| 400 // If no callback was specified, do a synchronous resolution. |
296 if (!callback) { | 401 if (!callback) { |
297 struct addrinfo* results; | 402 struct addrinfo* results; |
298 int rv = ResolveAddrInfo(host_mapper, hostname, port_str, &results); | 403 int error = ResolveAddrInfo(host_mapper, hostname, &results); |
299 if (rv == OK) | 404 |
300 addresses->Adopt(results); | 405 // Adopt the address list. |
301 return rv; | 406 AddressList addrlist; |
302 } | 407 if (error == OK) { |
303 | 408 addrlist.Adopt(results); |
304 request_ = new Request(this, hostname, port_str, addresses, callback); | 409 addrlist.SetPort(port); |
305 | 410 *addresses = addrlist; |
306 // Dispatch to worker thread... | 411 } |
307 if (!WorkerPool::PostTask(FROM_HERE, | 412 |
308 NewRunnableMethod(request_.get(), &Request::DoLookup), true)) { | 413 // Write to cache. |
309 NOTREACHED(); | 414 cache_.Set(hostname, error, addrlist, base::TimeTicks::Now()); |
310 request_ = NULL; | 415 |
311 return ERR_FAILED; | 416 return error; |
312 } | 417 } |
313 | 418 |
| 419 // Create a handle for this request, and pass it back to the user if they |
| 420 // asked for it (out_req != NULL). |
| 421 Request* req = new Request(callback, addresses, port); |
| 422 if (out_req) |
| 423 *out_req = req; |
| 424 |
| 425 // Next we need to attach our request to a "job". This job is responsible for |
| 426 // calling "getaddrinfo(hostname)" on a worker thread. |
| 427 scoped_refptr<Job> job; |
| 428 |
| 429 // If there is already an outstanding job to resolve |hostname|, use it. |
| 430 // This prevents starting concurrent resolves for the same hostname. |
| 431 job = FindOutstandingJob(hostname); |
| 432 if (job) { |
| 433 job->AddRequest(req); |
| 434 } else { |
| 435 // Create a new job for this request. |
| 436 job = new Job(this, hostname); |
| 437 job->AddRequest(req); |
| 438 AddOutstandingJob(job); |
| 439 // TODO(eroman): Bound the total number of concurrent jobs. |
| 440 // http://crbug.com/9598 |
| 441 job->Start(); |
| 442 } |
| 443 |
| 444 // Completion happens during OnJobComplete(Job*). |
314 return ERR_IO_PENDING; | 445 return ERR_IO_PENDING; |
315 } | 446 } |
316 | 447 |
| 448 // See OnJobComplete(Job*) for why it is important not to clean out |
| 449 // cancelled requests from Job::requests_. |
| 450 void HostResolver::CancelRequest(Request* req) { |
| 451 DCHECK(req); |
| 452 DCHECK(req->job()); |
| 453 // NULL out the fields of req, to mark it as cancelled. |
| 454 req->Cancel(); |
| 455 } |
| 456 |
| 457 void HostResolver::AddOutstandingJob(Job* job) { |
| 458 scoped_refptr<Job>& found_job = jobs_[job->host()]; |
| 459 DCHECK(!found_job); |
| 460 found_job = job; |
| 461 } |
| 462 |
| 463 HostResolver::Job* HostResolver::FindOutstandingJob( |
| 464 const std::string& hostname) { |
| 465 JobMap::iterator it = jobs_.find(hostname); |
| 466 if (it != jobs_.end()) |
| 467 return it->second; |
| 468 return NULL; |
| 469 } |
| 470 |
| 471 void HostResolver::RemoveOutstandingJob(Job* job) { |
| 472 JobMap::iterator it = jobs_.find(job->host()); |
| 473 DCHECK(it != jobs_.end()); |
| 474 DCHECK_EQ(it->second.get(), job); |
| 475 jobs_.erase(it); |
| 476 } |
| 477 |
| 478 void HostResolver::OnJobComplete(Job* job, |
| 479 int error, |
| 480 const AddressList& addrlist) { |
| 481 RemoveOutstandingJob(job); |
| 482 |
| 483 // Write result to the cache. |
| 484 cache_.Set(job->host(), error, addrlist, base::TimeTicks::Now()); |
| 485 |
| 486 // Make a note that we are executing within OnJobComplete() in case the |
| 487 // HostResolver is deleted by a callback invocation. |
| 488 DCHECK(!cur_completing_job_); |
| 489 cur_completing_job_ = job; |
| 490 |
| 491 // Complete all of the requests that were attached to the job. |
| 492 for (RequestsList::const_iterator it = job->requests().begin(); |
| 493 it != job->requests().end(); ++it) { |
| 494 Request* req = *it; |
| 495 if (!req->was_cancelled()) { |
| 496 DCHECK_EQ(job, req->job()); |
| 497 req->OnComplete(error, addrlist); |
| 498 |
| 499 // Check if the job was cancelled as a result of running the callback. |
| 500 // (Meaning that |this| was deleted). |
| 501 if (job->was_cancelled()) |
| 502 return; |
| 503 } |
| 504 } |
| 505 |
| 506 cur_completing_job_ = NULL; |
| 507 } |
| 508 |
| 509 //----------------------------------------------------------------------------- |
| 510 |
| 511 SingleRequestHostResolver::SingleRequestHostResolver(HostResolver* resolver) |
| 512 : resolver_(resolver), |
| 513 cur_request_(NULL), |
| 514 cur_request_callback_(NULL), |
| 515 ALLOW_THIS_IN_INITIALIZER_LIST( |
| 516 callback_(this, &SingleRequestHostResolver::OnResolveCompletion)) { |
| 517 DCHECK(resolver_ != NULL); |
| 518 } |
| 519 |
| 520 SingleRequestHostResolver::~SingleRequestHostResolver() { |
| 521 if (cur_request_) { |
| 522 resolver_->CancelRequest(cur_request_); |
| 523 } |
| 524 } |
| 525 |
| 526 int SingleRequestHostResolver::Resolve( |
| 527 const std::string& hostname, int port, |
| 528 AddressList* addresses, |
| 529 CompletionCallback* callback) { |
| 530 DCHECK(!cur_request_ && !cur_request_callback_) << "resolver already in use"; |
| 531 |
| 532 HostResolver::Request* request = NULL; |
| 533 |
| 534 // We need to be notified of completion before |callback| is called, so that |
| 535 // we can clear out |cur_request_*|. |
| 536 CompletionCallback* transient_callback = callback ? &callback_ : NULL; |
| 537 |
| 538 int rv = resolver_->Resolve( |
| 539 hostname, port, addresses, transient_callback, &request); |
| 540 |
| 541 if (rv == ERR_IO_PENDING) { |
| 542 // Cleared in OnResolveCompletion(). |
| 543 cur_request_ = request; |
| 544 cur_request_callback_ = callback; |
| 545 } |
| 546 |
| 547 return rv; |
| 548 } |
| 549 |
| 550 void SingleRequestHostResolver::OnResolveCompletion(int result) { |
| 551 DCHECK(cur_request_ && cur_request_callback_); |
| 552 |
| 553 CompletionCallback* callback = cur_request_callback_; |
| 554 |
| 555 // Clear the outstanding request information. |
| 556 cur_request_ = NULL; |
| 557 cur_request_callback_ = NULL; |
| 558 |
| 559 // Call the user's original callback. |
| 560 callback->Run(result); |
| 561 } |
| 562 |
317 } // namespace net | 563 } // namespace net |
OLD | NEW |