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