Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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/async_host_resolver.h" | 5 #include "net/base/async_host_resolver.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 59 dict->Set("source_dependency", source_.ToValue()); | 59 dict->Set("source_dependency", source_.ToValue()); |
| 60 | 60 |
| 61 return dict; | 61 return dict; |
| 62 } | 62 } |
| 63 | 63 |
| 64 private: | 64 private: |
| 65 const HostResolver::RequestInfo info_; | 65 const HostResolver::RequestInfo info_; |
| 66 const NetLog::Source source_; | 66 const NetLog::Source source_; |
| 67 }; | 67 }; |
| 68 | 68 |
| 69 HostCache* CreateDefaultCache() { | |
|
cbentzel
2011/07/21 15:31:10
This should be shared with the one in host_resolve
agayev
2011/07/21 17:48:03
Done.
| |
| 70 static const size_t kMaxHostCacheEntries = 100; | |
| 71 | |
| 72 HostCache* cache = new HostCache( | |
| 73 kMaxHostCacheEntries, | |
| 74 base::TimeDelta::FromMinutes(1), | |
| 75 base::TimeDelta::FromSeconds(0)); // Disable caching of failed DNS. | |
| 76 | |
| 77 return cache; | |
| 78 } | |
| 79 | |
| 69 } // namespace | 80 } // namespace |
| 70 | 81 |
| 71 HostResolver* CreateAsyncHostResolver(size_t max_concurrent_resolves, | 82 HostResolver* CreateAsyncHostResolver(size_t max_concurrent_resolves, |
| 72 const IPAddressNumber& dns_ip, | 83 const IPAddressNumber& dns_ip, |
| 73 NetLog* net_log) { | 84 NetLog* net_log) { |
| 74 size_t max_transactions = max_concurrent_resolves; | 85 size_t max_transactions = max_concurrent_resolves; |
| 75 if (max_transactions == 0) | 86 if (max_transactions == 0) |
| 76 max_transactions = 20; | 87 max_transactions = 20; |
| 77 size_t max_pending_requests = max_transactions * 100; | 88 size_t max_pending_requests = max_transactions * 100; |
| 78 HostResolver* resolver = new AsyncHostResolver( | 89 HostResolver* resolver = new AsyncHostResolver( |
| 79 IPEndPoint(dns_ip, 53), | 90 IPEndPoint(dns_ip, 53), |
| 80 max_transactions, | 91 max_transactions, |
| 81 max_pending_requests, | 92 max_pending_requests, |
| 82 base::Bind(&base::RandInt), | 93 base::Bind(&base::RandInt), |
| 94 CreateDefaultCache(), | |
| 83 NULL, | 95 NULL, |
| 84 net_log); | 96 net_log); |
| 85 return resolver; | 97 return resolver; |
| 86 } | 98 } |
| 87 | 99 |
| 88 //----------------------------------------------------------------------------- | 100 //----------------------------------------------------------------------------- |
| 89 class AsyncHostResolver::Request { | 101 class AsyncHostResolver::Request { |
| 90 public: | 102 public: |
| 91 Request(const BoundNetLog& source_net_log, | 103 Request(const BoundNetLog& source_net_log, |
| 92 const BoundNetLog& request_net_log, | 104 const BoundNetLog& request_net_log, |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 104 addresses_(addresses) { | 116 addresses_(addresses) { |
| 105 DCHECK(addresses_); | 117 DCHECK(addresses_); |
| 106 } | 118 } |
| 107 | 119 |
| 108 int id() const { return id_; } | 120 int id() const { return id_; } |
| 109 const HostResolver::RequestInfo& info() const { return info_; } | 121 const HostResolver::RequestInfo& info() const { return info_; } |
| 110 const Key& key() const { return key_; } | 122 const Key& key() const { return key_; } |
| 111 RequestPriority priority() const { return info_.priority(); } | 123 RequestPriority priority() const { return info_.priority(); } |
| 112 const BoundNetLog& source_net_log() const { return source_net_log_; } | 124 const BoundNetLog& source_net_log() const { return source_net_log_; } |
| 113 const BoundNetLog& request_net_log() const { return request_net_log_; } | 125 const BoundNetLog& request_net_log() const { return request_net_log_; } |
| 114 const AddressList* addresses() const { return addresses_; } | 126 void set_addresses(const AddressList& addresses) { *addresses_ = addresses; } |
| 115 | 127 |
| 116 void OnComplete(int result, const IPAddressList& ip_addresses) { | 128 void OnComplete(int result, const IPAddressList& ip_addresses) { |
| 117 DCHECK(callback_); | 129 DCHECK(callback_); |
| 118 if (result == OK) | 130 if (result == OK) |
| 119 *addresses_ = | 131 *addresses_ = |
| 120 AddressList::CreateFromIPAddressList(ip_addresses, info_.port()); | 132 AddressList::CreateFromIPAddressList(ip_addresses, info_.port()); |
| 121 callback_->Run(result); | 133 callback_->Run(result); |
| 122 } | 134 } |
| 123 | 135 |
| 124 private: | 136 private: |
| 125 BoundNetLog source_net_log_; | 137 BoundNetLog source_net_log_; |
| 126 BoundNetLog request_net_log_; | 138 BoundNetLog request_net_log_; |
| 127 const int id_; | 139 const int id_; |
| 128 const HostResolver::RequestInfo info_; | 140 const HostResolver::RequestInfo info_; |
| 129 const Key key_; | 141 const Key key_; |
| 130 CompletionCallback* callback_; | 142 CompletionCallback* callback_; |
| 131 AddressList* addresses_; | 143 AddressList* addresses_; |
| 132 }; | 144 }; |
| 133 | 145 |
| 134 //----------------------------------------------------------------------------- | 146 //----------------------------------------------------------------------------- |
| 135 AsyncHostResolver::AsyncHostResolver(const IPEndPoint& dns_server, | 147 AsyncHostResolver::AsyncHostResolver(const IPEndPoint& dns_server, |
| 136 size_t max_transactions, | 148 size_t max_transactions, |
| 137 size_t max_pending_requests, | 149 size_t max_pending_requests, |
| 138 const RandIntCallback& rand_int_cb, | 150 const RandIntCallback& rand_int_cb, |
| 151 HostCache* cache, | |
| 139 ClientSocketFactory* factory, | 152 ClientSocketFactory* factory, |
| 140 NetLog* net_log) | 153 NetLog* net_log) |
| 141 : max_transactions_(max_transactions), | 154 : max_transactions_(max_transactions), |
| 142 max_pending_requests_(max_pending_requests), | 155 max_pending_requests_(max_pending_requests), |
| 143 dns_server_(dns_server), | 156 dns_server_(dns_server), |
| 144 rand_int_cb_(rand_int_cb), | 157 rand_int_cb_(rand_int_cb), |
| 158 cache_(cache), | |
| 145 factory_(factory), | 159 factory_(factory), |
| 146 next_request_id_(0), | 160 next_request_id_(0), |
| 147 net_log_(net_log) { | 161 net_log_(net_log) { |
| 148 } | 162 } |
| 149 | 163 |
| 150 AsyncHostResolver::~AsyncHostResolver() { | 164 AsyncHostResolver::~AsyncHostResolver() { |
| 165 // Destroy request lists. | |
| 151 for (KeyRequestListMap::iterator it = requestlist_map_.begin(); | 166 for (KeyRequestListMap::iterator it = requestlist_map_.begin(); |
| 152 it != requestlist_map_.end(); ++it) | 167 it != requestlist_map_.end(); ++it) |
| 153 STLDeleteElements(&it->second); | 168 STLDeleteElements(&it->second); |
| 169 | |
| 170 // Destroy transactions. | |
| 154 STLDeleteElements(&transactions_); | 171 STLDeleteElements(&transactions_); |
| 172 | |
| 173 // Destroy pending requests. | |
| 174 for (size_t i = 0; i < arraysize(pending_requests_); ++i) | |
| 175 STLDeleteElements(&pending_requests_[i]); | |
| 155 } | 176 } |
| 156 | 177 |
| 157 int AsyncHostResolver::Resolve(const RequestInfo& info, | 178 int AsyncHostResolver::Resolve(const RequestInfo& info, |
| 158 AddressList* addresses, | 179 AddressList* addresses, |
| 159 CompletionCallback* callback, | 180 CompletionCallback* callback, |
| 160 RequestHandle* out_req, | 181 RequestHandle* out_req, |
| 161 const BoundNetLog& source_net_log) { | 182 const BoundNetLog& source_net_log) { |
| 162 DCHECK(addresses); | 183 DCHECK(addresses); |
| 163 | |
| 164 IPAddressNumber ip_number; | 184 IPAddressNumber ip_number; |
| 165 std::string dns_name; | 185 std::string dns_name; |
| 166 int rv = ERR_UNEXPECTED; | 186 int rv = ERR_UNEXPECTED; |
| 167 if (info.hostname().empty()) | 187 if (info.hostname().empty()) |
| 168 rv = ERR_NAME_NOT_RESOLVED; | 188 rv = ERR_NAME_NOT_RESOLVED; |
| 169 else if (ParseIPLiteralToNumber(info.hostname(), &ip_number)) | 189 else if (ParseIPLiteralToNumber(info.hostname(), &ip_number)) |
| 170 rv = ResolveAsIp(info, ip_number, addresses); | 190 rv = ResolveAsIp(info, ip_number, addresses); |
| 171 else if (!DNSDomainFromDot(info.hostname(), &dns_name)) | 191 else if (!DNSDomainFromDot(info.hostname(), &dns_name)) |
| 172 rv = ERR_NAME_NOT_RESOLVED; | 192 rv = ERR_NAME_NOT_RESOLVED; |
| 173 else if (info.only_use_cached_response()) // TODO(agayev): support caching | |
| 174 rv = ERR_NAME_NOT_RESOLVED; | |
| 175 | 193 |
| 176 Request* request = CreateNewRequest( | 194 Request* request = CreateNewRequest( |
| 177 info, dns_name, callback, addresses, source_net_log); | 195 info, dns_name, callback, addresses, source_net_log); |
| 178 | 196 |
| 179 OnStart(request); | 197 OnStart(request); |
| 198 if (rv == ERR_UNEXPECTED) { | |
| 199 if (ServeFromCache(request)) | |
| 200 rv = OK; | |
| 201 else if (info.only_use_cached_response()) | |
| 202 rv = ERR_NAME_NOT_RESOLVED; | |
| 203 } | |
| 204 | |
| 180 if (rv != ERR_UNEXPECTED) { | 205 if (rv != ERR_UNEXPECTED) { |
| 181 OnFinish(request, rv); | 206 OnFinish(request, rv); |
| 182 delete request; | 207 delete request; |
| 183 return rv; | 208 return rv; // Synchronous resolution ends here. |
| 184 } | 209 } |
| 185 | 210 |
| 186 if (out_req) | 211 if (out_req) |
| 187 *out_req = reinterpret_cast<RequestHandle>(request); | 212 *out_req = reinterpret_cast<RequestHandle>(request); |
| 188 | |
| 189 if (AttachToRequestList(request)) | 213 if (AttachToRequestList(request)) |
| 190 return ERR_IO_PENDING; | 214 return ERR_IO_PENDING; |
| 191 if (transactions_.size() < max_transactions_) | 215 if (transactions_.size() < max_transactions_) |
| 192 return StartNewTransactionFor(request); | 216 return StartNewTransactionFor(request); |
| 193 return Enqueue(request); | 217 return Enqueue(request); |
| 194 } | 218 } |
| 195 | 219 |
| 196 void AsyncHostResolver::OnStart(Request* request) { | 220 void AsyncHostResolver::OnStart(Request* request) { |
| 197 DCHECK(request); | 221 DCHECK(request); |
| 198 | 222 |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 272 } | 296 } |
| 273 | 297 |
| 274 HostResolverImpl* AsyncHostResolver::GetAsHostResolverImpl() { | 298 HostResolverImpl* AsyncHostResolver::GetAsHostResolverImpl() { |
| 275 return NULL; | 299 return NULL; |
| 276 } | 300 } |
| 277 | 301 |
| 278 void AsyncHostResolver::OnTransactionComplete( | 302 void AsyncHostResolver::OnTransactionComplete( |
| 279 int result, | 303 int result, |
| 280 const DnsTransaction* transaction, | 304 const DnsTransaction* transaction, |
| 281 const IPAddressList& ip_addresses) { | 305 const IPAddressList& ip_addresses) { |
| 282 | |
| 283 DCHECK(std::find(transactions_.begin(), transactions_.end(), transaction) | 306 DCHECK(std::find(transactions_.begin(), transactions_.end(), transaction) |
| 284 != transactions_.end()); | 307 != transactions_.end()); |
| 285 DCHECK(requestlist_map_.find(transaction->key()) != requestlist_map_.end()); | 308 DCHECK(requestlist_map_.find(transaction->key()) != requestlist_map_.end()); |
| 286 | 309 |
| 287 // Run callback of every request that was depending on this transaction, | 310 // Run callback of every request that was depending on this transaction, |
| 288 // also notify observers. | 311 // also notify observers. |
| 289 RequestList& requests = requestlist_map_[transaction->key()]; | 312 RequestList& requests = requestlist_map_[transaction->key()]; |
| 290 for (RequestList::iterator it = requests.begin(); it != requests.end(); | 313 for (RequestList::iterator it = requests.begin(); it != requests.end(); |
| 291 ++it) { | 314 ++it) { |
| 292 Request* request = *it; | 315 Request* request = *it; |
| 293 OnFinish(request, result); | 316 OnFinish(request, result); |
| 294 request->OnComplete(result, ip_addresses); | 317 request->OnComplete(result, ip_addresses); |
| 295 } | 318 } |
| 296 | 319 |
| 320 // It is possible that the requests that caused |transaction| to be | |
| 321 // created are cancelled by the time |transaction| completes. In that | |
| 322 // case |requests| would be empty. We are knowingly throwing away the | |
| 323 // result of a DNS resolution in that case, because (a) if there are no | |
| 324 // requests, we do not have info to obtain a key from, (b) DnsTransaction | |
| 325 // does not have info(), adding one into it just temporarily doesn't make | |
| 326 // sense, since HostCache will be replaced with RR cache soon, (c) | |
| 327 // recreating info from DnsTransaction::Key adds a lot of temporary | |
|
cbentzel
2011/07/21 15:31:10
It seems like it should still be possible to cache
agayev
2011/07/21 17:48:03
Well, it doesn't have host_resolver_flags, whose u
cbentzel
2011/07/21 18:22:15
Yes, I agree that's how it would be done. I think
| |
| 328 // code/functions (like converting back from qtype to AddressFamily.) | |
| 329 // Also, we only cache positive results. All of this will change when RR | |
| 330 // cache is added. | |
| 331 if (result == OK && cache_.get() && !requests.empty()) { | |
| 332 Request* request = requests.front(); | |
| 333 HostResolver::RequestInfo info = request->info(); | |
| 334 HostCache::Key key( | |
| 335 info.hostname(), info.address_family(), info.host_resolver_flags()); | |
| 336 AddressList addrlist = | |
| 337 AddressList::CreateFromIPAddressList(ip_addresses, info.port()); | |
| 338 cache_->Set(key, result, addrlist, base::TimeTicks::Now()); | |
| 339 } | |
| 340 | |
| 297 // Cleanup requests. | 341 // Cleanup requests. |
| 298 STLDeleteElements(&requests); | 342 STLDeleteElements(&requests); |
| 299 requestlist_map_.erase(transaction->key()); | 343 requestlist_map_.erase(transaction->key()); |
| 300 | 344 |
| 301 // Cleanup transaction and start a new one if there are pending requests. | 345 // Cleanup transaction and start a new one if there are pending requests. |
| 302 delete transaction; | 346 delete transaction; |
| 303 transactions_.remove(transaction); | 347 transactions_.remove(transaction); |
| 304 ProcessPending(); | 348 ProcessPending(); |
| 305 } | 349 } |
| 306 | 350 |
| 351 bool AsyncHostResolver::ServeFromCache(Request* request) const { | |
| 352 // Sanity check -- it shouldn't be the case that allow_cached_response is | |
| 353 // false while only_use_cached_response is true. | |
| 354 DCHECK(request->info().allow_cached_response() || | |
| 355 !request->info().only_use_cached_response()); | |
| 356 | |
| 357 if (!cache_.get() || !request->info().allow_cached_response()) | |
| 358 return false; | |
| 359 | |
| 360 HostResolver::RequestInfo info = request->info(); | |
| 361 HostCache::Key key(info.hostname(), info.address_family(), | |
| 362 info.host_resolver_flags()); | |
| 363 const HostCache::Entry* cache_entry = cache_->Lookup( | |
| 364 key, base::TimeTicks::Now()); | |
| 365 if (cache_entry) { | |
| 366 request->request_net_log().AddEvent( | |
| 367 NetLog::TYPE_ASYNC_HOST_RESOLVER_CACHE_HIT, NULL); | |
| 368 DCHECK_EQ(OK, cache_entry->error); | |
|
cbentzel
2011/07/21 15:31:10
Ah - I was going to ask you to handle non-OK error
| |
| 369 request->set_addresses( | |
| 370 CreateAddressListUsingPort(cache_entry->addrlist, info.port())); | |
| 371 return true; | |
| 372 } | |
| 373 return false; | |
| 374 } | |
| 375 | |
| 307 AsyncHostResolver::Request* AsyncHostResolver::CreateNewRequest( | 376 AsyncHostResolver::Request* AsyncHostResolver::CreateNewRequest( |
| 308 const RequestInfo& info, | 377 const RequestInfo& info, |
| 309 const std::string& dns_name, | 378 const std::string& dns_name, |
| 310 CompletionCallback* callback, | 379 CompletionCallback* callback, |
| 311 AddressList* addresses, | 380 AddressList* addresses, |
| 312 const BoundNetLog& source_net_log) { | 381 const BoundNetLog& source_net_log) { |
| 313 | 382 |
| 314 uint16 query_type = QueryTypeFromAddressFamily(info.address_family()); | 383 uint16 query_type = QueryTypeFromAddressFamily(info.address_family()); |
| 315 Key key(dns_name, query_type); | 384 Key key(dns_name, query_type); |
| 316 | 385 |
| 317 BoundNetLog request_net_log = BoundNetLog::Make(net_log_, | 386 BoundNetLog request_net_log = BoundNetLog::Make(net_log_, |
| 318 NetLog::SOURCE_ASYNC_HOST_RESOLVER_REQUEST); | 387 NetLog::SOURCE_ASYNC_HOST_RESOLVER_REQUEST); |
| 319 | 388 |
| 320 int id = next_request_id_++; | 389 int id = next_request_id_++; |
| 321 Request* request = new Request( | 390 return new Request( |
| 322 source_net_log, request_net_log, id, info, key, callback, addresses); | 391 source_net_log, request_net_log, id, info, key, callback, addresses); |
| 323 return request; | |
| 324 } | 392 } |
| 325 | 393 |
| 326 bool AsyncHostResolver::AttachToRequestList(Request* request) { | 394 bool AsyncHostResolver::AttachToRequestList(Request* request) { |
| 327 KeyRequestListMap::iterator it = requestlist_map_.find(request->key()); | 395 KeyRequestListMap::iterator it = requestlist_map_.find(request->key()); |
| 328 if (it == requestlist_map_.end()) | 396 if (it == requestlist_map_.end()) |
| 329 return false; | 397 return false; |
| 330 it->second.push_back(request); | 398 it->second.push_back(request); |
| 331 return true; | 399 return true; |
| 332 } | 400 } |
| 333 | 401 |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 366 AsyncHostResolver::Request* AsyncHostResolver::Insert(Request* request) { | 434 AsyncHostResolver::Request* AsyncHostResolver::Insert(Request* request) { |
| 367 pending_requests_[request->priority()].push_back(request); | 435 pending_requests_[request->priority()].push_back(request); |
| 368 if (GetNumPending() > max_pending_requests_) { | 436 if (GetNumPending() > max_pending_requests_) { |
| 369 Request* req = RemoveLowest(); | 437 Request* req = RemoveLowest(); |
| 370 DCHECK(req); | 438 DCHECK(req); |
| 371 return req; | 439 return req; |
| 372 } | 440 } |
| 373 return NULL; | 441 return NULL; |
| 374 } | 442 } |
| 375 | 443 |
| 376 size_t AsyncHostResolver::GetNumPending() { | 444 size_t AsyncHostResolver::GetNumPending() const { |
| 377 size_t num_pending = 0; | 445 size_t num_pending = 0; |
| 378 for (size_t i = 0; i < arraysize(pending_requests_); ++i) | 446 for (size_t i = 0; i < arraysize(pending_requests_); ++i) |
| 379 num_pending += pending_requests_[i].size(); | 447 num_pending += pending_requests_[i].size(); |
| 380 return num_pending; | 448 return num_pending; |
| 381 } | 449 } |
| 382 | 450 |
| 383 AsyncHostResolver::Request* AsyncHostResolver::RemoveLowest() { | 451 AsyncHostResolver::Request* AsyncHostResolver::RemoveLowest() { |
| 384 for (int i = static_cast<int>(arraysize(pending_requests_)) - 1; | 452 for (int i = static_cast<int>(arraysize(pending_requests_)) - 1; |
| 385 i >= 0; --i) { | 453 i >= 0; --i) { |
| 386 RequestList& requests = pending_requests_[i]; | 454 RequestList& requests = pending_requests_[i]; |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 418 it = requests.erase(it); | 486 it = requests.erase(it); |
| 419 } else { | 487 } else { |
| 420 ++it; | 488 ++it; |
| 421 } | 489 } |
| 422 } | 490 } |
| 423 } | 491 } |
| 424 StartNewTransactionFor(request); | 492 StartNewTransactionFor(request); |
| 425 } | 493 } |
| 426 | 494 |
| 427 } // namespace net | 495 } // namespace net |
| OLD | NEW |