Home | History | Annotate | Download | only in base
      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
      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/memory/scoped_ptr.h"
     16 #include "base/memory/singleton.h"
     17 #include "base/message_loop.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 
     77 namespace 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
     86 static 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 
    101 static const uint16 kClassIN = 1;
    102 // kMaxCacheEntries is the number of RRResponse objects that we'll cache.
    103 static const unsigned kMaxCacheEntries = 32;
    104 // kNegativeTTLSecs is the number of seconds for which we'll cache a negative
    105 // cache entry.
    106 static const unsigned kNegativeTTLSecs = 60;
    107 
    108 RRResponse::RRResponse()
    109     : ttl(0), dnssec(false), negative(false) {
    110 }
    111 
    112 RRResponse::~RRResponse() {}
    113 
    114 class 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.
    146 class 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.
    419 class 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 
    553 bool 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 
    559 bool 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.
    648 class 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 
    688 DnsRRResolver::DnsRRResolver()
    689     : requests_(0),
    690       cache_hits_(0),
    691       inflight_joins_(0),
    692       in_destructor_(false) {
    693 }
    694 
    695 DnsRRResolver::~DnsRRResolver() {
    696   DCHECK(!in_destructor_);
    697   in_destructor_ = true;
    698   STLDeleteValues(&inflight_);
    699 }
    700 
    701 intptr_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 
    773 void DnsRRResolver::CancelResolve(intptr_t h) {
    774   DCHECK(CalledOnValidThread());
    775   RRResolverHandle* handle = reinterpret_cast<RRResolverHandle*>(h);
    776   handle->Cancel();
    777 }
    778 
    779 void 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.
    791 void 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 
    832 DISABLE_RUNNABLE_METHOD_REFCOUNT(net::RRResolverHandle);
    833 DISABLE_RUNNABLE_METHOD_REFCOUNT(net::RRResolverWorker);
    834