• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
DnsRRIsParsedByWindows(uint16 rrtype)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 
RRResponse()108 RRResponse::RRResponse()
109     : ttl(0), dnssec(false), negative(false) {
110 }
111 
~RRResponse()112 RRResponse::~RRResponse() {}
113 
114 class RRResolverHandle {
115  public:
RRResolverHandle(CompletionCallback * callback,RRResponse * response)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.
Cancel()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.
Post(int rv,const RRResponse * response)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:
RRResolverWorker(const std::string & name,uint16 rrtype,uint16 flags,DnsRRResolver * dnsrr_resolver)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 
Start()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.
Cancel()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 
Run()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 
Do()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.
HandleTestCases()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.
DoReply()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 
Finish()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:
Buffer(const uint8 * p,unsigned len)421   Buffer(const uint8* p, unsigned len)
422       : p_(p),
423         packet_(p),
424         len_(len),
425         packet_len_(len) {
426   }
427 
U8(uint8 * v)428   bool U8(uint8* v) {
429     if (len_ < 1)
430       return false;
431     *v = *p_;
432     p_++;
433     len_--;
434     return true;
435   }
436 
U16(uint16 * v)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 
U32(uint32 * v)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 
Skip(unsigned n)459   bool Skip(unsigned n) {
460     if (len_ < n)
461       return false;
462     p_ += n;
463     len_ -= n;
464     return true;
465   }
466 
Block(base::StringPiece * out,unsigned len)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.
DNSName(std::string * name)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 
HasExpired(const base::Time current_time) const553 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 
ParseFromResponse(const uint8 * p,unsigned len,uint16 rrtype_requested)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:
RRResolverJob(RRResolverWorker * worker)650   explicit RRResolverJob(RRResolverWorker* worker)
651       : worker_(worker) {
652   }
653 
~RRResolverJob()654   ~RRResolverJob() {
655     if (worker_) {
656       worker_->Cancel();
657       worker_ = NULL;
658       PostAll(ERR_ABORTED, NULL);
659     }
660   }
661 
AddHandle(RRResolverHandle * handle)662   void AddHandle(RRResolverHandle* handle) {
663     handles_.push_back(handle);
664   }
665 
HandleResult(int result,const RRResponse & response)666   void HandleResult(int result, const RRResponse& response) {
667     worker_ = NULL;
668     PostAll(result, &response);
669   }
670 
671  private:
PostAll(int result,const RRResponse * response)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 
DnsRRResolver()688 DnsRRResolver::DnsRRResolver()
689     : requests_(0),
690       cache_hits_(0),
691       inflight_joins_(0),
692       in_destructor_(false) {
693 }
694 
~DnsRRResolver()695 DnsRRResolver::~DnsRRResolver() {
696   DCHECK(!in_destructor_);
697   in_destructor_ = true;
698   STLDeleteValues(&inflight_);
699 }
700 
Resolve(const std::string & name,uint16 rrtype,uint16 flags,CompletionCallback * callback,RRResponse * response,int priority,const BoundNetLog & netlog)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 
CancelResolve(intptr_t h)773 void DnsRRResolver::CancelResolve(intptr_t h) {
774   DCHECK(CalledOnValidThread());
775   RRResolverHandle* handle = reinterpret_cast<RRResolverHandle*>(h);
776   handle->Cancel();
777 }
778 
OnIPAddressChanged()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.
HandleResult(const std::string & name,uint16 rrtype,int result,const RRResponse & response)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