Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(101)

Side by Side Diff: net/dns/async_host_resolver.cc

Issue 9369045: [net] HostResolverImpl + DnsTransaction + DnsConfigService = Asynchronous DNS ready for experiments. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Denitted. Created 8 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « net/dns/async_host_resolver.h ('k') | net/dns/async_host_resolver_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "net/dns/async_host_resolver.h"
6
7 #include <algorithm>
8
9 #include "base/bind.h"
10 #include "base/logging.h"
11 #include "base/message_loop.h"
12 #include "base/rand_util.h"
13 #include "base/stl_util.h"
14 #include "base/values.h"
15 #include "net/base/address_list.h"
16 #include "net/base/dns_util.h"
17 #include "net/base/net_errors.h"
18 #include "net/dns/dns_protocol.h"
19 #include "net/dns/dns_response.h"
20 #include "net/dns/dns_session.h"
21 #include "net/socket/client_socket_factory.h"
22
23 namespace net {
24
25 namespace {
26
27 // TODO(agayev): fix this when IPv6 support is added.
28 uint16 QueryTypeFromAddressFamily(AddressFamily address_family) {
29 return dns_protocol::kTypeA;
30 }
31
32 class RequestParameters : public NetLog::EventParameters {
33 public:
34 RequestParameters(const HostResolver::RequestInfo& info,
35 const NetLog::Source& source)
36 : info_(info), source_(source) {}
37
38 virtual Value* ToValue() const {
39 DictionaryValue* dict = new DictionaryValue();
40 dict->SetString("hostname", info_.host_port_pair().ToString());
41 dict->SetInteger("address_family",
42 static_cast<int>(info_.address_family()));
43 dict->SetBoolean("allow_cached_response", info_.allow_cached_response());
44 dict->SetBoolean("is_speculative", info_.is_speculative());
45 dict->SetInteger("priority", info_.priority());
46
47 if (source_.is_valid())
48 dict->Set("source_dependency", source_.ToValue());
49
50 return dict;
51 }
52
53 private:
54 const HostResolver::RequestInfo info_;
55 const NetLog::Source source_;
56 };
57
58 } // namespace
59
60 HostResolver* CreateAsyncHostResolver(size_t max_concurrent_resolves,
61 const IPAddressNumber& dns_ip,
62 NetLog* net_log) {
63 size_t max_dns_requests = max_concurrent_resolves;
64 if (max_dns_requests == 0)
65 max_dns_requests = 20;
66 size_t max_pending_requests = max_dns_requests * 100;
67 DnsConfig config;
68 config.nameservers.push_back(IPEndPoint(dns_ip, 53));
69 DnsSession* session = new DnsSession(
70 config,
71 ClientSocketFactory::GetDefaultFactory(),
72 base::Bind(&base::RandInt),
73 net_log);
74 HostResolver* resolver = new AsyncHostResolver(
75 max_dns_requests,
76 max_pending_requests,
77 HostCache::CreateDefaultCache(),
78 DnsTransactionFactory::CreateFactory(session),
79 net_log);
80 return resolver;
81 }
82
83 //-----------------------------------------------------------------------------
84 // Every call to Resolve() results in Request object being created. Such a
85 // call may complete either synchronously or asynchronously or it may get
86 // cancelled, which can be either through specific CancelRequest call or by
87 // the destruction of AsyncHostResolver, which would destruct pending or
88 // in-progress requests, causing them to be cancelled. Synchronous
89 // resolution sets |callback_| to NULL, thus, if in the destructor we still
90 // have a non-NULL |callback_|, we are being cancelled.
91 class AsyncHostResolver::Request {
92 public:
93 Request(AsyncHostResolver* resolver,
94 const BoundNetLog& source_net_log,
95 const BoundNetLog& request_net_log,
96 const HostResolver::RequestInfo& info,
97 const CompletionCallback& callback,
98 AddressList* addresses)
99 : resolver_(resolver),
100 source_net_log_(source_net_log),
101 request_net_log_(request_net_log),
102 info_(info),
103 callback_(callback),
104 addresses_(addresses),
105 result_(ERR_UNEXPECTED) {
106 DCHECK(addresses_);
107 DCHECK(resolver_);
108 resolver_->OnStart(this);
109 key_ = Key(info.hostname(),
110 QueryTypeFromAddressFamily(info.address_family()));
111 }
112
113 ~Request() {
114 if (!callback_.is_null())
115 resolver_->OnCancel(this);
116 }
117
118 int result() const { return result_; }
119 const Key& key() const {
120 DCHECK(IsValid());
121 return key_;
122 }
123 const HostResolver::RequestInfo& info() const { return info_; }
124 RequestPriority priority() const { return info_.priority(); }
125 const BoundNetLog& source_net_log() const { return source_net_log_; }
126 const BoundNetLog& request_net_log() const { return request_net_log_; }
127
128 bool ResolveAsIp() {
129 IPAddressNumber ip_number;
130 if (!ParseIPLiteralToNumber(info_.hostname(), &ip_number))
131 return false;
132
133 if (ip_number.size() != kIPv4AddressSize) {
134 result_ = ERR_NAME_NOT_RESOLVED;
135 } else {
136 *addresses_ = AddressList::CreateFromIPAddressWithCname(
137 ip_number,
138 info_.port(),
139 info_.host_resolver_flags() & HOST_RESOLVER_CANONNAME);
140 result_ = OK;
141 }
142 return true;
143 }
144
145 bool ServeFromCache() {
146 HostCache* cache = resolver_->cache_.get();
147 if (!cache || !info_.allow_cached_response())
148 return false;
149
150 HostCache::Key key(info_.hostname(), info_.address_family(),
151 info_.host_resolver_flags());
152 const HostCache::Entry* cache_entry = cache->Lookup(
153 key, base::TimeTicks::Now());
154 if (cache_entry) {
155 request_net_log_.AddEvent(
156 NetLog::TYPE_ASYNC_HOST_RESOLVER_CACHE_HIT, NULL);
157 DCHECK_EQ(OK, cache_entry->error);
158 result_ = cache_entry->error;
159 *addresses_ =
160 CreateAddressListUsingPort(cache_entry->addrlist, info_.port());
161 return true;
162 }
163 return false;
164 }
165
166 // Called when a request completes synchronously; we do not have an
167 // AddressList argument, since in case of a successful synchronous
168 // completion, either ResolveAsIp or ServerFromCache would set the
169 // |addresses_| and in case of an unsuccessful synchronous completion, we
170 // do not touch |addresses_|.
171 void OnSyncComplete(int result) {
172 callback_.Reset();
173 resolver_->OnFinish(this, result);
174 }
175
176 // Called when a request completes asynchronously.
177 void OnAsyncComplete(int result, const AddressList& addresses) {
178 if (result == OK)
179 *addresses_ = CreateAddressListUsingPort(addresses, info_.port());
180 DCHECK_EQ(false, callback_.is_null());
181 CompletionCallback callback = callback_;
182 callback_.Reset();
183 resolver_->OnFinish(this, result);
184 callback.Run(result);
185 }
186
187 // Returns true if request has a validly formed hostname.
188 bool IsValid() const {
189 return !info_.hostname().empty() && !key_.first.empty();
190 }
191
192 private:
193 AsyncHostResolver* resolver_;
194 BoundNetLog source_net_log_;
195 BoundNetLog request_net_log_;
196 const HostResolver::RequestInfo info_;
197 Key key_;
198 CompletionCallback callback_;
199 AddressList* addresses_;
200 int result_;
201 };
202
203 //-----------------------------------------------------------------------------
204 AsyncHostResolver::AsyncHostResolver(size_t max_dns_requests,
205 size_t max_pending_requests,
206 HostCache* cache,
207 scoped_ptr<DnsTransactionFactory> client,
208 NetLog* net_log)
209 : max_dns_transactions_(max_dns_requests),
210 max_pending_requests_(max_pending_requests),
211 cache_(cache),
212 client_(client.Pass()),
213 net_log_(net_log) {
214 }
215
216 AsyncHostResolver::~AsyncHostResolver() {
217 // Destroy request lists.
218 for (KeyRequestListMap::iterator it = requestlist_map_.begin();
219 it != requestlist_map_.end(); ++it)
220 STLDeleteElements(&it->second);
221
222 // Destroy DNS transactions.
223 STLDeleteElements(&dns_transactions_);
224
225 // Destroy pending requests.
226 for (size_t i = 0; i < arraysize(pending_requests_); ++i)
227 STLDeleteElements(&pending_requests_[i]);
228 }
229
230 int AsyncHostResolver::Resolve(const RequestInfo& info,
231 AddressList* addresses,
232 const CompletionCallback& callback,
233 RequestHandle* out_req,
234 const BoundNetLog& source_net_log) {
235 DCHECK(addresses);
236 DCHECK_EQ(false, callback.is_null());
237 scoped_ptr<Request> request(
238 CreateNewRequest(info, callback, addresses, source_net_log));
239
240 int rv = ERR_UNEXPECTED;
241 if (!request->IsValid())
242 rv = ERR_NAME_NOT_RESOLVED;
243 else if (request->ResolveAsIp() || request->ServeFromCache())
244 rv = request->result();
245 else if (AttachToRequestList(request.get()))
246 rv = ERR_IO_PENDING;
247 else if (dns_transactions_.size() < max_dns_transactions_)
248 rv = StartNewDnsRequestFor(request.get());
249 else
250 rv = Enqueue(request.get());
251
252 if (rv != ERR_IO_PENDING) {
253 request->OnSyncComplete(rv);
254 } else {
255 Request* req = request.release();
256 if (out_req)
257 *out_req = reinterpret_cast<RequestHandle>(req);
258 }
259 return rv;
260 }
261
262 int AsyncHostResolver::ResolveFromCache(const RequestInfo& info,
263 AddressList* addresses,
264 const BoundNetLog& source_net_log) {
265 scoped_ptr<Request> request(
266 CreateNewRequest(info, CompletionCallback(), addresses, source_net_log));
267 int rv = ERR_UNEXPECTED;
268 if (!request->IsValid())
269 rv = ERR_NAME_NOT_RESOLVED;
270 else if (request->ResolveAsIp() || request->ServeFromCache())
271 rv = request->result();
272 else
273 rv = ERR_DNS_CACHE_MISS;
274 request->OnSyncComplete(rv);
275 return rv;
276 }
277
278 void AsyncHostResolver::OnStart(Request* request) {
279 DCHECK(request);
280
281 request->source_net_log().BeginEvent(
282 NetLog::TYPE_ASYNC_HOST_RESOLVER,
283 make_scoped_refptr(new NetLogSourceParameter(
284 "source_dependency", request->request_net_log().source())));
285 request->request_net_log().BeginEvent(
286 NetLog::TYPE_ASYNC_HOST_RESOLVER_REQUEST,
287 make_scoped_refptr(new RequestParameters(
288 request->info(), request->source_net_log().source())));
289 }
290
291 void AsyncHostResolver::OnFinish(Request* request, int result) {
292 DCHECK(request);
293 request->request_net_log().EndEventWithNetErrorCode(
294 NetLog::TYPE_ASYNC_HOST_RESOLVER_REQUEST, result);
295 request->source_net_log().EndEvent(
296 NetLog::TYPE_ASYNC_HOST_RESOLVER, NULL);
297 }
298
299 void AsyncHostResolver::OnCancel(Request* request) {
300 DCHECK(request);
301
302 request->request_net_log().AddEvent(
303 NetLog::TYPE_CANCELLED, NULL);
304 request->request_net_log().EndEvent(
305 NetLog::TYPE_ASYNC_HOST_RESOLVER_REQUEST, NULL);
306 request->source_net_log().EndEvent(
307 NetLog::TYPE_ASYNC_HOST_RESOLVER, NULL);
308 }
309
310 void AsyncHostResolver::CancelRequest(RequestHandle req_handle) {
311 scoped_ptr<Request> request(reinterpret_cast<Request*>(req_handle));
312 DCHECK(request.get());
313
314 KeyRequestListMap::iterator it = requestlist_map_.find(request->key());
315 if (it != requestlist_map_.end())
316 it->second.remove(request.get());
317 else
318 pending_requests_[request->priority()].remove(request.get());
319 }
320
321 void AsyncHostResolver::SetDefaultAddressFamily(
322 AddressFamily address_family) {
323 NOTIMPLEMENTED();
324 }
325
326 AddressFamily AsyncHostResolver::GetDefaultAddressFamily() const {
327 return ADDRESS_FAMILY_IPV4;
328 }
329
330 HostCache* AsyncHostResolver::GetHostCache() {
331 return cache_.get();
332 }
333
334 void AsyncHostResolver::OnDnsTransactionComplete(
335 DnsTransaction* transaction,
336 int result,
337 const DnsResponse* response) {
338 DCHECK(std::find(dns_transactions_.begin(),
339 dns_transactions_.end(),
340 transaction) != dns_transactions_.end());
341
342 // If by the time requests that caused |transaction| are cancelled, we do
343 // not have a port number to associate with the result, therefore, we
344 // assume the most common port, otherwise we use the port number of the
345 // first request.
346 KeyRequestListMap::iterator rit = requestlist_map_.find(
347 std::make_pair(transaction->GetHostname(), transaction->GetType()));
348 DCHECK(rit != requestlist_map_.end());
349 RequestList& requests = rit->second;
350 int port = requests.empty() ? 80 : requests.front()->info().port();
351
352 // Extract AddressList and TTL out of DnsResponse.
353 AddressList addr_list;
354 uint32 ttl = kuint32max;
355 if (result == OK) {
356 IPAddressList ip_addresses;
357 DnsRecordParser parser = response->Parser();
358 DnsResourceRecord record;
359 // TODO(szym): Add stricter checking of names, aliases and address lengths.
360 while (parser.ParseRecord(&record)) {
361 if (record.type == transaction->GetType() &&
362 (record.rdata.size() == kIPv4AddressSize ||
363 record.rdata.size() == kIPv6AddressSize)) {
364 ip_addresses.push_back(IPAddressNumber(record.rdata.begin(),
365 record.rdata.end()));
366 ttl = std::min(ttl, record.ttl);
367 }
368 }
369 if (!ip_addresses.empty())
370 addr_list = AddressList::CreateFromIPAddressList(ip_addresses, port);
371 else
372 result = ERR_NAME_NOT_RESOLVED;
373 }
374
375 // Run callback of every request that was depending on this DNS request,
376 // also notify observers.
377 for (RequestList::iterator it = requests.begin(); it != requests.end(); ++it)
378 (*it)->OnAsyncComplete(result, addr_list);
379
380 // It is possible that the requests that caused |transaction| to be
381 // created are cancelled by the time |transaction| completes. In that
382 // case |requests| would be empty. We are knowingly throwing away the
383 // result of a DNS resolution in that case, because (a) if there are no
384 // requests, we do not have info to obtain a key from, (b) DnsTransaction
385 // does not have info().
386 // TODO(szym): Should DnsTransaction ignore HostResolverFlags or use defaults?
387 if ((result == OK || result == ERR_NAME_NOT_RESOLVED) && cache_.get() &&
388 !requests.empty()) {
389 Request* request = requests.front();
390 HostResolver::RequestInfo info = request->info();
391 HostCache::Key key(
392 info.hostname(), info.address_family(), info.host_resolver_flags());
393 // Store negative results with TTL 0 to flush out the old entry.
394 cache_->Set(key,
395 result,
396 addr_list,
397 base::TimeTicks::Now(),
398 (result == OK) ? base::TimeDelta::FromSeconds(ttl)
399 : base::TimeDelta());
400 }
401
402 // Cleanup requests.
403 STLDeleteElements(&requests);
404 requestlist_map_.erase(rit);
405
406 // Cleanup |transaction| and start a new one if there are pending requests.
407 dns_transactions_.remove(transaction);
408 delete transaction;
409 ProcessPending();
410 }
411
412 AsyncHostResolver::Request* AsyncHostResolver::CreateNewRequest(
413 const RequestInfo& info,
414 const CompletionCallback& callback,
415 AddressList* addresses,
416 const BoundNetLog& source_net_log) {
417 BoundNetLog request_net_log = BoundNetLog::Make(net_log_,
418 NetLog::SOURCE_ASYNC_HOST_RESOLVER_REQUEST);
419 return new Request(
420 this, source_net_log, request_net_log, info, callback, addresses);
421 }
422
423 bool AsyncHostResolver::AttachToRequestList(Request* request) {
424 KeyRequestListMap::iterator it = requestlist_map_.find(request->key());
425 if (it == requestlist_map_.end())
426 return false;
427 it->second.push_back(request);
428 return true;
429 }
430
431 int AsyncHostResolver::StartNewDnsRequestFor(Request* request) {
432 DCHECK(requestlist_map_.find(request->key()) == requestlist_map_.end());
433 DCHECK(dns_transactions_.size() < max_dns_transactions_);
434
435 request->request_net_log().AddEvent(
436 NetLog::TYPE_ASYNC_HOST_RESOLVER_CREATE_DNS_TRANSACTION, NULL);
437
438 requestlist_map_[request->key()].push_back(request);
439 scoped_ptr<DnsTransaction> transaction(client_->CreateTransaction(
440 request->key().first,
441 request->key().second,
442 base::Bind(&AsyncHostResolver::OnDnsTransactionComplete,
443 base::Unretained(this)),
444 request->request_net_log()));
445 int rv = transaction->Start();
446 if (rv == ERR_IO_PENDING)
447 dns_transactions_.push_back(transaction.release());
448 return rv;
449 }
450
451 int AsyncHostResolver::Enqueue(Request* request) {
452 Request* evicted_request = Insert(request);
453 int rv = ERR_HOST_RESOLVER_QUEUE_TOO_LARGE;
454 if (evicted_request == request)
455 return rv;
456 if (evicted_request != NULL) {
457 evicted_request->OnAsyncComplete(rv, AddressList());
458 delete evicted_request;
459 }
460 return ERR_IO_PENDING;
461 }
462
463 AsyncHostResolver::Request* AsyncHostResolver::Insert(Request* request) {
464 pending_requests_[request->priority()].push_back(request);
465 if (GetNumPending() > max_pending_requests_) {
466 Request* req = RemoveLowest();
467 DCHECK(req);
468 return req;
469 }
470 return NULL;
471 }
472
473 size_t AsyncHostResolver::GetNumPending() const {
474 size_t num_pending = 0;
475 for (size_t i = 0; i < arraysize(pending_requests_); ++i)
476 num_pending += pending_requests_[i].size();
477 return num_pending;
478 }
479
480 AsyncHostResolver::Request* AsyncHostResolver::RemoveLowest() {
481 for (int i = static_cast<int>(arraysize(pending_requests_)) - 1;
482 i >= 0; --i) {
483 RequestList& requests = pending_requests_[i];
484 if (!requests.empty()) {
485 Request* request = requests.front();
486 requests.pop_front();
487 return request;
488 }
489 }
490 return NULL;
491 }
492
493 AsyncHostResolver::Request* AsyncHostResolver::RemoveHighest() {
494 for (size_t i = 0; i < arraysize(pending_requests_) - 1; ++i) {
495 RequestList& requests = pending_requests_[i];
496 if (!requests.empty()) {
497 Request* request = requests.front();
498 requests.pop_front();
499 return request;
500 }
501 }
502 return NULL;
503 }
504
505 void AsyncHostResolver::ProcessPending() {
506 Request* request = RemoveHighest();
507 if (!request)
508 return;
509 for (size_t i = 0; i < arraysize(pending_requests_); ++i) {
510 RequestList& requests = pending_requests_[i];
511 RequestList::iterator it = requests.begin();
512 while (it != requests.end()) {
513 if (request->key() == (*it)->key()) {
514 requestlist_map_[request->key()].push_back(*it);
515 it = requests.erase(it);
516 } else {
517 ++it;
518 }
519 }
520 }
521 StartNewDnsRequestFor(request);
522 }
523
524 } // namespace net
OLDNEW
« no previous file with comments | « net/dns/async_host_resolver.h ('k') | net/dns/async_host_resolver_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698