OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2013 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/dns/mdns_cache.h" | |
6 | |
7 #include <utility> | |
8 | |
9 #include "base/stl_util.h" | |
10 #include "base/strings/string_number_conversions.h" | |
11 #include "net/dns/dns_protocol.h" | |
12 #include "net/dns/record_parsed.h" | |
13 #include "net/dns/record_rdata.h" | |
14 | |
15 // TODO(noamsml): Recursive CNAME closure (backwards and forwards). | |
16 | |
17 namespace net { | |
18 | |
19 // The effective TTL given to records with a nominal zero TTL. | |
20 // Allows time for hosts to send updated records, as detailed in RFC 6762 | |
21 // Section 10.1. | |
22 static const unsigned kZeroTTLSeconds = 1; | |
23 | |
24 MDnsCache::DnsRecordCacheKey::DnsRecordCacheKey(unsigned type, | |
25 const std::string& name, | |
26 const std::string& optional) | |
27 : type_(type), name_(name), optional_(optional) { | |
28 } | |
29 | |
30 MDnsCache::DnsRecordCacheKey::DnsRecordCacheKey( | |
31 const MDnsCache::DnsRecordCacheKey& other) | |
32 : type_(other.type_), name_(other.name_), optional_(other.optional_) { | |
33 } | |
34 | |
35 | |
36 MDnsCache::DnsRecordCacheKey& MDnsCache::DnsRecordCacheKey::operator=( | |
37 const MDnsCache::DnsRecordCacheKey& other) { | |
38 type_ = other.type_; | |
39 name_ = other.name_; | |
40 optional_ = other.optional_; | |
41 return *this; | |
42 } | |
43 | |
44 MDnsCache::DnsRecordCacheKey::~DnsRecordCacheKey() { | |
45 } | |
46 | |
47 bool MDnsCache::DnsRecordCacheKey::operator<( | |
48 const MDnsCache::DnsRecordCacheKey& key) const { | |
49 if (type_ != key.type_) | |
50 return type_ < key.type_; | |
51 | |
52 if (name_ != key.name_) | |
53 return name_ < key.name_; | |
54 | |
55 if (optional_ != key.optional_) | |
56 return optional_ < key.optional_; | |
57 return false; // keys are equal | |
58 } | |
59 | |
60 bool MDnsCache::DnsRecordCacheKey::operator==( | |
61 const MDnsCache::DnsRecordCacheKey& key) const { | |
62 return type_ == key.type_ && name_ == key.name_ && optional_ == key.optional_; | |
63 } | |
64 | |
65 MDnsCache::MDnsCache() { | |
66 } | |
67 | |
68 MDnsCache::~MDnsCache() { | |
69 Clear(); | |
70 } | |
71 | |
72 void MDnsCache::Clear() { | |
73 next_expiration_ = base::Time(); | |
74 STLDeleteValues(&mdns_cache_); | |
75 } | |
76 | |
77 MDnsCache::UpdateType MDnsCache::UpdateDnsRecord( | |
78 scoped_ptr<const RecordParsed> record) { | |
79 UpdateType type = NoChange; | |
80 | |
81 MDnsCache::DnsRecordCacheKey cache_key = MDnsCache::DnsRecordCacheKey( | |
82 record->type(), | |
83 record->name(), | |
84 GetOptionalFieldForRecord(record.get())); | |
85 | |
86 base::Time expiration = GetEffectiveExpiration(record.get()); | |
87 if (next_expiration_ == base::Time() || expiration < next_expiration_) { | |
88 next_expiration_ = expiration; | |
89 } | |
90 | |
91 std::pair<MDnsCacheMap::iterator, bool> insert_result = | |
92 mdns_cache_.insert(std::make_pair(cache_key, (const RecordParsed*)NULL)); | |
93 | |
94 if (insert_result.second) { | |
95 type = RecordAdded; | |
96 insert_result.first->second = record.release(); | |
97 } else { | |
98 const RecordParsed* other_record = insert_result.first->second; | |
99 | |
100 if (!record->IsEqual(other_record, true)) { | |
101 type = RecordChanged; | |
102 } | |
103 delete other_record; | |
104 insert_result.first->second = record.release(); | |
105 } | |
106 | |
107 return type; | |
108 } | |
109 | |
110 void MDnsCache::CleanupRecords( | |
111 base::Time now, | |
112 const RecordRemovedCallback& record_removed_callback) { | |
113 base::Time next_expiration; | |
114 | |
115 // We are guaranteed that |next_expiration_| will be at or before the next | |
116 // expiration. This allows clients to eagrely call CleanupRecords with | |
117 // impunity. | |
118 if (now < next_expiration_) return; | |
119 | |
120 for (MDnsCacheMap::iterator i = mdns_cache_.begin(); | |
121 i != mdns_cache_.end(); ) { | |
122 base::Time expiration = GetEffectiveExpiration(i->second); | |
123 if (now >= expiration) { | |
124 record_removed_callback.Run(i->second); | |
125 delete i->second; | |
126 mdns_cache_.erase(i++); | |
127 } else { | |
128 if (next_expiration == base::Time() || expiration < next_expiration) { | |
129 next_expiration = expiration; | |
130 } | |
131 ++i; | |
132 } | |
133 } | |
134 | |
135 next_expiration_ = next_expiration; | |
136 } | |
137 | |
138 void MDnsCache::FindDnsRecords(unsigned type, | |
139 const std::string& name, | |
140 std::vector<const RecordParsed*>* results, | |
141 base::Time now) { | |
142 DCHECK(results); | |
143 results->clear(); | |
144 | |
145 MDnsCacheMap::iterator i = | |
146 mdns_cache_.lower_bound(DnsRecordCacheKey(type, name, "")); | |
147 for (; i != mdns_cache_.end(); ++i) { | |
148 if (i->first.type() != type || | |
149 (!name.empty() && i->first.name() != name)) { | |
150 break; | |
151 } | |
152 | |
153 const RecordParsed* record = i->second; | |
154 | |
155 // Records are deleted only upon request to make this op idempotent | |
szym
2013/05/20 19:35:15
The op would still be idempotent (same result) if
Noam Samuel
2013/05/20 21:07:02
Fixed comment.
On 2013/05/20 19:35:15, szym wrot
| |
156 if (now >= GetEffectiveExpiration(record)) continue; | |
157 | |
158 results->push_back(record); | |
159 } | |
160 } | |
161 | |
162 std::string MDnsCache::GetOptionalFieldForRecord(const RecordParsed* record) { | |
szym
2013/05/20 19:35:15
Mark const.
Noam Samuel
2013/05/20 21:07:02
Done.
| |
163 switch (record->type()) { | |
164 case PtrRecordRdata::kType: { | |
165 const PtrRecordRdata* rdata = record->rdata<PtrRecordRdata>(); | |
166 return rdata->ptrdomain(); | |
167 } | |
168 default: // Most records are considered unique for our purposes | |
169 return ""; | |
170 } | |
171 } | |
172 | |
173 base::Time MDnsCache::GetEffectiveExpiration(const RecordParsed* record) { | |
szym
2013/05/20 19:35:15
Mark const.
Noam Samuel
2013/05/20 21:07:02
Done.
| |
174 base::TimeDelta ttl; | |
175 | |
176 if (record->ttl()) { | |
177 ttl = base::TimeDelta::FromSeconds(record->ttl()); | |
178 } else { | |
179 ttl = base::TimeDelta::FromSeconds(kZeroTTLSeconds); | |
180 } | |
181 | |
182 return record->time_created() + ttl; | |
183 } | |
184 | |
185 } // namespace net | |
OLD | NEW |