dnsrr_resolver.cc revision 5bc0d8d0128a8fb64b9b0edfe64b61fa6549baab
1// Copyright (c) 2010 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/base/dnsrr_resolver.h" 6 7#if defined(OS_POSIX) 8#include <resolv.h> 9#endif 10 11#if defined(OS_WIN) 12#include <windns.h> 13#endif 14 15#include "base/message_loop.h" 16#include "base/scoped_ptr.h" 17#include "base/singleton.h" 18#include "base/stl_util-inl.h" 19#include "base/string_piece.h" 20#include "base/synchronization/lock.h" 21#include "base/task.h" 22#include "base/threading/worker_pool.h" 23#include "net/base/dns_reload_timer.h" 24#include "net/base/dns_util.h" 25#include "net/base/net_errors.h" 26 27// Life of a query: 28// 29// DnsRRResolver RRResolverJob RRResolverWorker ... Handle 30// | (origin loop) (worker loop) 31// | 32// Resolve() 33// |---->-------------------<creates> 34// | 35// |---->----<creates> 36// | 37// |---->---------------------------------------------------<creates> 38// | 39// |---->--------------------Start 40// | | 41// | PostTask 42// | 43// | <starts resolving> 44// |---->-----AddHandle | 45// | 46// | 47// | 48// Finish 49// | 50// PostTask 51// 52// | 53// DoReply 54// |----<-----------------------| 55// HandleResult 56// | 57// |---->-----HandleResult 58// | 59// |------>-----------------------------------Post 60// 61// 62// 63// A cache hit: 64// 65// DnsRRResolver Handle 66// | 67// Resolve() 68// |---->------------------------<creates> 69// | 70// | 71// PostTask 72// 73// (MessageLoop cycles) 74// 75// Post 76 77namespace net { 78 79#if defined(OS_WIN) 80// DnsRRIsParsedByWindows returns true if Windows knows how to parse the given 81// RR type. RR data is returned in a DNS_RECORD structure which may be raw (if 82// Windows doesn't parse it) or may be a parse result. It's unclear how this 83// API is intended to evolve in the future. If Windows adds support for new RR 84// types in a future version a client which expected raw data will break. 85// See http://msdn.microsoft.com/en-us/library/ms682082(v=vs.85).aspx 86static bool DnsRRIsParsedByWindows(uint16 rrtype) { 87 // We only cover the types which are defined in dns_util.h 88 switch (rrtype) { 89 case kDNS_CNAME: 90 case kDNS_TXT: 91 case kDNS_DS: 92 case kDNS_RRSIG: 93 case kDNS_DNSKEY: 94 return true; 95 default: 96 return false; 97 } 98} 99#endif 100 101static const uint16 kClassIN = 1; 102// kMaxCacheEntries is the number of RRResponse objects that we'll cache. 103static const unsigned kMaxCacheEntries = 32; 104// kNegativeTTLSecs is the number of seconds for which we'll cache a negative 105// cache entry. 106static const unsigned kNegativeTTLSecs = 60; 107 108RRResponse::RRResponse() 109 : ttl(0), dnssec(false), negative(false) { 110} 111 112RRResponse::~RRResponse() {} 113 114class RRResolverHandle { 115 public: 116 RRResolverHandle(CompletionCallback* callback, RRResponse* response) 117 : callback_(callback), 118 response_(response) { 119 } 120 121 // Cancel ensures that the result callback will never be made. 122 void Cancel() { 123 callback_ = NULL; 124 response_ = NULL; 125 } 126 127 // Post copies the contents of |response| to the caller's RRResponse and 128 // calls the callback. 129 void Post(int rv, const RRResponse* response) { 130 if (callback_) { 131 if (response_ && response) 132 *response_ = *response; 133 callback_->Run(rv); 134 } 135 delete this; 136 } 137 138 private: 139 CompletionCallback* callback_; 140 RRResponse* response_; 141}; 142 143 144// RRResolverWorker runs on a worker thread and takes care of the blocking 145// process of performing the DNS resolution. 146class RRResolverWorker { 147 public: 148 RRResolverWorker(const std::string& name, uint16 rrtype, uint16 flags, 149 DnsRRResolver* dnsrr_resolver) 150 : name_(name), 151 rrtype_(rrtype), 152 flags_(flags), 153 origin_loop_(MessageLoop::current()), 154 dnsrr_resolver_(dnsrr_resolver), 155 canceled_(false), 156 result_(ERR_UNEXPECTED) { 157 } 158 159 bool Start() { 160 DCHECK_EQ(MessageLoop::current(), origin_loop_); 161 162 return base::WorkerPool::PostTask( 163 FROM_HERE, NewRunnableMethod(this, &RRResolverWorker::Run), 164 true /* task is slow */); 165 } 166 167 // Cancel is called from the origin loop when the DnsRRResolver is getting 168 // deleted. 169 void Cancel() { 170 DCHECK_EQ(MessageLoop::current(), origin_loop_); 171 base::AutoLock locked(lock_); 172 canceled_ = true; 173 } 174 175 private: 176 177#if defined(OS_POSIX) && !defined(ANDROID) 178 179 void Run() { 180 // Runs on a worker thread. 181 182 if (HandleTestCases()) { 183 Finish(); 184 return; 185 } 186 187 bool r = true; 188 if ((_res.options & RES_INIT) == 0) { 189 if (res_ninit(&_res) != 0) 190 r = false; 191 } 192 193 if (r) { 194 unsigned long saved_options = _res.options; 195 r = Do(); 196 197#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_OPENBSD) 198 if (!r && DnsReloadTimerHasExpired()) { 199 // When there's no network connection, _res may not be initialized by 200 // getaddrinfo. Therefore, we call res_nclose only when there are ns 201 // entries. 202 if (_res.nscount > 0) 203 res_nclose(&_res); 204 if (res_ninit(&_res) == 0) 205 r = Do(); 206 } 207#endif 208 _res.options = saved_options; 209 } 210 211 response_.fetch_time = base::Time::Now(); 212 213 if (r) { 214 result_ = OK; 215 } else { 216 result_ = ERR_NAME_NOT_RESOLVED; 217 response_.negative = true; 218 response_.ttl = kNegativeTTLSecs; 219 } 220 221 Finish(); 222 } 223 224 bool Do() { 225 // For DNSSEC, a 4K buffer is suggested 226 static const unsigned kMaxDNSPayload = 4096; 227 228#ifndef RES_USE_DNSSEC 229 // Some versions of libresolv don't have support for the DO bit. In this 230 // case, we proceed without it. 231 static const int RES_USE_DNSSEC = 0; 232#endif 233 234#ifndef RES_USE_EDNS0 235 // Some versions of glibc are so old that they don't support EDNS0 either. 236 // http://code.google.com/p/chromium/issues/detail?id=51676 237 static const int RES_USE_EDNS0 = 0; 238#endif 239 240 // We set the options explicitly. Note that this removes several default 241 // options: RES_DEFNAMES and RES_DNSRCH (see res_init(3)). 242 _res.options = RES_INIT | RES_RECURSE | RES_USE_EDNS0 | RES_USE_DNSSEC; 243 uint8 answer[kMaxDNSPayload]; 244 int len = res_search(name_.c_str(), kClassIN, rrtype_, answer, 245 sizeof(answer)); 246 if (len == -1) 247 return false; 248 249 return response_.ParseFromResponse(answer, len, rrtype_); 250 } 251 252#elif defined(ANDROID) 253 254 void Run() { 255 if (HandleTestCases()) { 256 Finish(); 257 return; 258 } 259 260 response_.fetch_time = base::Time::Now(); 261 response_.negative = true; 262 result_ = ERR_NAME_NOT_RESOLVED; 263 Finish(); 264 } 265 266#else // OS_WIN 267 268 void Run() { 269 if (HandleTestCases()) { 270 Finish(); 271 return; 272 } 273 274 // See http://msdn.microsoft.com/en-us/library/ms682016(v=vs.85).aspx 275 PDNS_RECORD record = NULL; 276 DNS_STATUS status = 277 DnsQuery_A(name_.c_str(), rrtype_, DNS_QUERY_STANDARD, 278 NULL /* pExtra (reserved) */, &record, NULL /* pReserved */); 279 response_.fetch_time = base::Time::Now(); 280 response_.name = name_; 281 response_.dnssec = false; 282 response_.ttl = 0; 283 284 if (status != 0) { 285 response_.negative = true; 286 result_ = ERR_NAME_NOT_RESOLVED; 287 } else { 288 response_.negative = false; 289 result_ = OK; 290 for (DNS_RECORD* cur = record; cur; cur = cur->pNext) { 291 if (cur->wType == rrtype_) { 292 response_.ttl = record->dwTtl; 293 // Windows will parse some types of resource records. If we want one 294 // of these types then we have to reserialise the record. 295 switch (rrtype_) { 296 case kDNS_TXT: { 297 // http://msdn.microsoft.com/en-us/library/ms682109(v=vs.85).aspx 298 const DNS_TXT_DATA* txt = &cur->Data.TXT; 299 std::string rrdata; 300 301 for (DWORD i = 0; i < txt->dwStringCount; i++) { 302 // Although the string is typed as a PWSTR, it's actually just 303 // an ASCII byte-string. Also, the string must be < 256 304 // elements because the length in the DNS packet is a single 305 // byte. 306 const char* s = reinterpret_cast<char*>(txt->pStringArray[i]); 307 size_t len = strlen(s); 308 DCHECK_LT(len, 256u); 309 char len8 = static_cast<char>(len); 310 rrdata.push_back(len8); 311 rrdata += s; 312 } 313 response_.rrdatas.push_back(rrdata); 314 break; 315 } 316 default: 317 if (DnsRRIsParsedByWindows(rrtype_)) { 318 // Windows parses this type, but we don't have code to unparse 319 // it. 320 NOTREACHED() << "you need to add code for the RR type here"; 321 response_.negative = true; 322 result_ = ERR_INVALID_ARGUMENT; 323 } else { 324 // This type is given to us raw. 325 response_.rrdatas.push_back( 326 std::string(reinterpret_cast<char*>(&cur->Data), 327 cur->wDataLength)); 328 } 329 } 330 } 331 } 332 } 333 334 DnsRecordListFree(record, DnsFreeRecordList); 335 Finish(); 336 } 337 338#endif // OS_WIN 339 340 // HandleTestCases stuffs in magic test values in the event that the query is 341 // from a unittest. 342 bool HandleTestCases() { 343 if (rrtype_ == kDNS_TESTING) { 344 response_.fetch_time = base::Time::Now(); 345 346 if (name_ == "www.testing.notatld") { 347 response_.ttl = 86400; 348 response_.negative = false; 349 response_.rrdatas.push_back("goats!"); 350 result_ = OK; 351 return true; 352 } else if (name_ == "nx.testing.notatld") { 353 response_.negative = true; 354 result_ = ERR_NAME_NOT_RESOLVED; 355 return true; 356 } 357 } 358 359 return false; 360 } 361 362 // DoReply runs on the origin thread. 363 void DoReply() { 364 DCHECK_EQ(MessageLoop::current(), origin_loop_); 365 { 366 // We lock here because the worker thread could still be in Finished, 367 // after the PostTask, but before unlocking |lock_|. If we do not lock in 368 // this case, we will end up deleting a locked Lock, which can lead to 369 // memory leaks or worse errors. 370 base::AutoLock locked(lock_); 371 if (!canceled_) 372 dnsrr_resolver_->HandleResult(name_, rrtype_, result_, response_); 373 } 374 delete this; 375 } 376 377 void Finish() { 378 // Runs on the worker thread. 379 // We assume that the origin loop outlives the DnsRRResolver. If the 380 // DnsRRResolver is deleted, it will call Cancel on us. If it does so 381 // before the Acquire, we'll delete ourselves and return. If it's trying to 382 // do so concurrently, then it'll block on the lock and we'll call PostTask 383 // while the DnsRRResolver (and therefore the MessageLoop) is still alive. 384 // If it does so after this function, we assume that the MessageLoop will 385 // process pending tasks. In which case we'll notice the |canceled_| flag 386 // in DoReply. 387 388 bool canceled; 389 { 390 base::AutoLock locked(lock_); 391 canceled = canceled_; 392 if (!canceled) { 393 origin_loop_->PostTask( 394 FROM_HERE, NewRunnableMethod(this, &RRResolverWorker::DoReply)); 395 } 396 } 397 398 if (canceled) 399 delete this; 400 } 401 402 const std::string name_; 403 const uint16 rrtype_; 404 const uint16 flags_; 405 MessageLoop* const origin_loop_; 406 DnsRRResolver* const dnsrr_resolver_; 407 408 base::Lock lock_; 409 bool canceled_; 410 411 int result_; 412 RRResponse response_; 413 414 DISALLOW_COPY_AND_ASSIGN(RRResolverWorker); 415}; 416 417 418// A Buffer is used for walking over a DNS packet. 419class Buffer { 420 public: 421 Buffer(const uint8* p, unsigned len) 422 : p_(p), 423 packet_(p), 424 len_(len), 425 packet_len_(len) { 426 } 427 428 bool U8(uint8* v) { 429 if (len_ < 1) 430 return false; 431 *v = *p_; 432 p_++; 433 len_--; 434 return true; 435 } 436 437 bool U16(uint16* v) { 438 if (len_ < 2) 439 return false; 440 *v = static_cast<uint16>(p_[0]) << 8 | 441 static_cast<uint16>(p_[1]); 442 p_ += 2; 443 len_ -= 2; 444 return true; 445 } 446 447 bool U32(uint32* v) { 448 if (len_ < 4) 449 return false; 450 *v = static_cast<uint32>(p_[0]) << 24 | 451 static_cast<uint32>(p_[1]) << 16 | 452 static_cast<uint32>(p_[2]) << 8 | 453 static_cast<uint32>(p_[3]); 454 p_ += 4; 455 len_ -= 4; 456 return true; 457 } 458 459 bool Skip(unsigned n) { 460 if (len_ < n) 461 return false; 462 p_ += n; 463 len_ -= n; 464 return true; 465 } 466 467 bool Block(base::StringPiece* out, unsigned len) { 468 if (len_ < len) 469 return false; 470 *out = base::StringPiece(reinterpret_cast<const char*>(p_), len); 471 p_ += len; 472 len_ -= len; 473 return true; 474 } 475 476 // DNSName parses a (possibly compressed) DNS name from the packet. If |name| 477 // is not NULL, then the name is written into it. See RFC 1035 section 4.1.4. 478 bool DNSName(std::string* name) { 479 unsigned jumps = 0; 480 const uint8* p = p_; 481 unsigned len = len_; 482 483 if (name) 484 name->clear(); 485 486 for (;;) { 487 if (len < 1) 488 return false; 489 uint8 d = *p; 490 p++; 491 len--; 492 493 // The two couple of bits of the length give the type of the length. It's 494 // either a direct length or a pointer to the remainder of the name. 495 if ((d & 0xc0) == 0xc0) { 496 // This limit matches the depth limit in djbdns. 497 if (jumps > 100) 498 return false; 499 if (len < 1) 500 return false; 501 uint16 offset = static_cast<uint16>(d) << 8 | 502 static_cast<uint16>(p[0]); 503 offset &= 0x3ff; 504 p++; 505 len--; 506 507 if (jumps == 0) { 508 p_ = p; 509 len_ = len; 510 } 511 jumps++; 512 513 if (offset >= packet_len_) 514 return false; 515 p = &packet_[offset]; 516 len = packet_len_ - offset; 517 } else if ((d & 0xc0) == 0) { 518 uint8 label_len = d; 519 if (len < label_len) 520 return false; 521 if (name && label_len) { 522 if (!name->empty()) 523 name->append("."); 524 name->append(reinterpret_cast<const char*>(p), label_len); 525 } 526 p += label_len; 527 len -= label_len; 528 529 if (jumps == 0) { 530 p_ = p; 531 len_ = len; 532 } 533 534 if (label_len == 0) 535 break; 536 } else { 537 return false; 538 } 539 } 540 541 return true; 542 } 543 544 private: 545 const uint8* p_; 546 const uint8* const packet_; 547 unsigned len_; 548 const unsigned packet_len_; 549 550 DISALLOW_COPY_AND_ASSIGN(Buffer); 551}; 552 553bool RRResponse::HasExpired(const base::Time current_time) const { 554 const base::TimeDelta delta(base::TimeDelta::FromSeconds(ttl)); 555 const base::Time expiry = fetch_time + delta; 556 return current_time >= expiry; 557} 558 559bool RRResponse::ParseFromResponse(const uint8* p, unsigned len, 560 uint16 rrtype_requested) { 561#if defined(OS_POSIX) && !defined(ANDROID) 562 name.clear(); 563 ttl = 0; 564 dnssec = false; 565 negative = false; 566 rrdatas.clear(); 567 signatures.clear(); 568 569 // RFC 1035 section 4.4.1 570 uint8 flags2; 571 Buffer buf(p, len); 572 if (!buf.Skip(2) || // skip id 573 !buf.Skip(1) || // skip first flags byte 574 !buf.U8(&flags2)) { 575 return false; 576 } 577 578 // Bit 5 is the Authenticated Data (AD) bit. See 579 // http://tools.ietf.org/html/rfc2535#section-6.1 580 if (flags2 & 32) { 581 // AD flag is set. We'll trust it if it came from a local nameserver. 582 // Currently the resolv structure is IPv4 only, so we can't test for IPv6 583 // loopback addresses. 584 if (_res.nscount == 1 && 585 memcmp(&_res.nsaddr_list[0].sin_addr, 586 "\x7f\x00\x00\x01" /* 127.0.0.1 */, 4) == 0) { 587 dnssec = true; 588 } 589 } 590 591 uint16 query_count, answer_count, authority_count, additional_count; 592 if (!buf.U16(&query_count) || 593 !buf.U16(&answer_count) || 594 !buf.U16(&authority_count) || 595 !buf.U16(&additional_count)) { 596 return false; 597 } 598 599 if (query_count != 1) 600 return false; 601 602 uint16 type, klass; 603 if (!buf.DNSName(NULL) || 604 !buf.U16(&type) || 605 !buf.U16(&klass) || 606 type != rrtype_requested || 607 klass != kClassIN) { 608 return false; 609 } 610 611 if (answer_count < 1) 612 return false; 613 614 for (uint32 i = 0; i < answer_count; i++) { 615 std::string* name = NULL; 616 if (i == 0) 617 name = &this->name; 618 uint32 ttl; 619 uint16 rrdata_len; 620 if (!buf.DNSName(name) || 621 !buf.U16(&type) || 622 !buf.U16(&klass) || 623 !buf.U32(&ttl) || 624 !buf.U16(&rrdata_len)) { 625 return false; 626 } 627 628 base::StringPiece rrdata; 629 if (!buf.Block(&rrdata, rrdata_len)) 630 return false; 631 632 if (klass == kClassIN && type == rrtype_requested) { 633 if (i == 0) 634 this->ttl = ttl; 635 rrdatas.push_back(std::string(rrdata.data(), rrdata.size())); 636 } else if (klass == kClassIN && type == kDNS_RRSIG) { 637 signatures.push_back(std::string(rrdata.data(), rrdata.size())); 638 } 639 } 640#endif // defined(OS_POSIX) 641 642 return true; 643} 644 645 646// An RRResolverJob is a one-to-one counterpart of an RRResolverWorker. It 647// lives only on the DnsRRResolver's origin message loop. 648class RRResolverJob { 649 public: 650 explicit RRResolverJob(RRResolverWorker* worker) 651 : worker_(worker) { 652 } 653 654 ~RRResolverJob() { 655 if (worker_) { 656 worker_->Cancel(); 657 worker_ = NULL; 658 PostAll(ERR_ABORTED, NULL); 659 } 660 } 661 662 void AddHandle(RRResolverHandle* handle) { 663 handles_.push_back(handle); 664 } 665 666 void HandleResult(int result, const RRResponse& response) { 667 worker_ = NULL; 668 PostAll(result, &response); 669 } 670 671 private: 672 void PostAll(int result, const RRResponse* response) { 673 std::vector<RRResolverHandle*> handles; 674 handles_.swap(handles); 675 676 for (std::vector<RRResolverHandle*>::iterator 677 i = handles.begin(); i != handles.end(); i++) { 678 (*i)->Post(result, response); 679 // Post() causes the RRResolverHandle to delete itself. 680 } 681 } 682 683 std::vector<RRResolverHandle*> handles_; 684 RRResolverWorker* worker_; 685}; 686 687 688DnsRRResolver::DnsRRResolver() 689 : requests_(0), 690 cache_hits_(0), 691 inflight_joins_(0), 692 in_destructor_(false) { 693} 694 695DnsRRResolver::~DnsRRResolver() { 696 DCHECK(!in_destructor_); 697 in_destructor_ = true; 698 STLDeleteValues(&inflight_); 699} 700 701intptr_t DnsRRResolver::Resolve(const std::string& name, uint16 rrtype, 702 uint16 flags, CompletionCallback* callback, 703 RRResponse* response, 704 int priority /* ignored */, 705 const BoundNetLog& netlog /* ignored */) { 706 DCHECK(CalledOnValidThread()); 707 DCHECK(!in_destructor_); 708 709 if (!callback || !response || name.empty()) 710 return kInvalidHandle; 711 712 // Don't allow queries of type ANY 713 if (rrtype == kDNS_ANY) 714 return kInvalidHandle; 715 716 requests_++; 717 718 const std::pair<std::string, uint16> key(make_pair(name, rrtype)); 719 // First check the cache. 720 std::map<std::pair<std::string, uint16>, RRResponse>::iterator i; 721 i = cache_.find(key); 722 if (i != cache_.end()) { 723 if (!i->second.HasExpired(base::Time::Now())) { 724 int error; 725 if (i->second.negative) { 726 error = ERR_NAME_NOT_RESOLVED; 727 } else { 728 error = OK; 729 *response = i->second; 730 } 731 RRResolverHandle* handle = new RRResolverHandle( 732 callback, NULL /* no response pointer because we've already filled */ 733 /* it in */); 734 cache_hits_++; 735 // We need a typed NULL pointer in order to make the templates work out. 736 static const RRResponse* kNoResponse = NULL; 737 MessageLoop::current()->PostTask( 738 FROM_HERE, NewRunnableMethod(handle, &RRResolverHandle::Post, error, 739 kNoResponse)); 740 return reinterpret_cast<intptr_t>(handle); 741 } else { 742 // entry has expired. 743 cache_.erase(i); 744 } 745 } 746 747 // No cache hit. See if a request is currently in flight. 748 RRResolverJob* job; 749 std::map<std::pair<std::string, uint16>, RRResolverJob*>::const_iterator j; 750 j = inflight_.find(key); 751 if (j != inflight_.end()) { 752 // The request is in flight already. We'll just attach our callback. 753 inflight_joins_++; 754 job = j->second; 755 } else { 756 // Need to make a new request. 757 RRResolverWorker* worker = new RRResolverWorker(name, rrtype, flags, this); 758 job = new RRResolverJob(worker); 759 inflight_.insert(make_pair(key, job)); 760 if (!worker->Start()) { 761 inflight_.erase(key); 762 delete job; 763 delete worker; 764 return kInvalidHandle; 765 } 766 } 767 768 RRResolverHandle* handle = new RRResolverHandle(callback, response); 769 job->AddHandle(handle); 770 return reinterpret_cast<intptr_t>(handle); 771} 772 773void DnsRRResolver::CancelResolve(intptr_t h) { 774 DCHECK(CalledOnValidThread()); 775 RRResolverHandle* handle = reinterpret_cast<RRResolverHandle*>(h); 776 handle->Cancel(); 777} 778 779void DnsRRResolver::OnIPAddressChanged() { 780 DCHECK(CalledOnValidThread()); 781 DCHECK(!in_destructor_); 782 783 std::map<std::pair<std::string, uint16>, RRResolverJob*> inflight; 784 inflight.swap(inflight_); 785 cache_.clear(); 786 787 STLDeleteValues(&inflight); 788} 789 790// HandleResult is called on the origin message loop. 791void DnsRRResolver::HandleResult(const std::string& name, uint16 rrtype, 792 int result, const RRResponse& response) { 793 DCHECK(CalledOnValidThread()); 794 795 const std::pair<std::string, uint16> key(std::make_pair(name, rrtype)); 796 797 DCHECK_GE(kMaxCacheEntries, 1u); 798 DCHECK_LE(cache_.size(), kMaxCacheEntries); 799 if (cache_.size() == kMaxCacheEntries) { 800 // need to remove an element of the cache. 801 const base::Time current_time(base::Time::Now()); 802 std::map<std::pair<std::string, uint16>, RRResponse>::iterator i, cur; 803 for (i = cache_.begin(); i != cache_.end(); ) { 804 cur = i++; 805 if (cur->second.HasExpired(current_time)) 806 cache_.erase(cur); 807 } 808 } 809 if (cache_.size() == kMaxCacheEntries) { 810 // if we didn't clear out any expired entries, we just remove the first 811 // element. Crummy but simple. 812 cache_.erase(cache_.begin()); 813 } 814 815 cache_.insert(std::make_pair(key, response)); 816 817 std::map<std::pair<std::string, uint16>, RRResolverJob*>::iterator j; 818 j = inflight_.find(key); 819 if (j == inflight_.end()) { 820 NOTREACHED(); 821 return; 822 } 823 RRResolverJob* job = j->second; 824 inflight_.erase(j); 825 826 job->HandleResult(result, response); 827 delete job; 828} 829 830} // namespace net 831 832DISABLE_RUNNABLE_METHOD_REFCOUNT(net::RRResolverHandle); 833DISABLE_RUNNABLE_METHOD_REFCOUNT(net::RRResolverWorker); 834