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