OLD | NEW |
---|---|
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/dns/mdns_client_impl.h" | 5 #include "net/dns/mdns_client_impl.h" |
6 | 6 |
7 #include <algorithm> | |
7 #include <queue> | 8 #include <queue> |
8 | 9 |
9 #include "base/bind.h" | 10 #include "base/bind.h" |
10 #include "base/message_loop/message_loop_proxy.h" | 11 #include "base/message_loop/message_loop_proxy.h" |
11 #include "base/stl_util.h" | 12 #include "base/stl_util.h" |
13 #include "base/time/clock.h" | |
12 #include "base/time/default_clock.h" | 14 #include "base/time/default_clock.h" |
13 #include "base/time/time.h" | 15 #include "base/time/time.h" |
16 #include "base/timer/timer.h" | |
14 #include "net/base/dns_util.h" | 17 #include "net/base/dns_util.h" |
15 #include "net/base/net_errors.h" | 18 #include "net/base/net_errors.h" |
16 #include "net/base/net_log.h" | 19 #include "net/base/net_log.h" |
17 #include "net/base/rand_callback.h" | 20 #include "net/base/rand_callback.h" |
18 #include "net/dns/dns_protocol.h" | 21 #include "net/dns/dns_protocol.h" |
19 #include "net/dns/record_rdata.h" | 22 #include "net/dns/record_rdata.h" |
20 #include "net/udp/datagram_socket.h" | 23 #include "net/udp/datagram_socket.h" |
21 | 24 |
22 // TODO(gene): Remove this temporary method of disabling NSEC support once it | 25 // TODO(gene): Remove this temporary method of disabling NSEC support once it |
23 // becomes clear whether this feature should be | 26 // becomes clear whether this feature should be |
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
188 | 191 |
189 void MDnsConnection::OnDatagramReceived( | 192 void MDnsConnection::OnDatagramReceived( |
190 DnsResponse* response, | 193 DnsResponse* response, |
191 const IPEndPoint& recv_addr, | 194 const IPEndPoint& recv_addr, |
192 int bytes_read) { | 195 int bytes_read) { |
193 // TODO(noamsml): More sophisticated error handling. | 196 // TODO(noamsml): More sophisticated error handling. |
194 DCHECK_GT(bytes_read, 0); | 197 DCHECK_GT(bytes_read, 0); |
195 delegate_->HandlePacket(response, bytes_read); | 198 delegate_->HandlePacket(response, bytes_read); |
196 } | 199 } |
197 | 200 |
198 MDnsClientImpl::Core::Core() : connection_(new MDnsConnection(this)) { | 201 MDnsClientImpl::Core::Core() |
202 : clock_(new base::DefaultClock), | |
203 cleanup_timer_(new base::Timer(false, false)), | |
204 connection_(new MDnsConnection(this)) { | |
199 } | 205 } |
200 | 206 |
201 MDnsClientImpl::Core::~Core() { | 207 MDnsClientImpl::Core::~Core() { |
202 STLDeleteValues(&listeners_); | 208 STLDeleteValues(&listeners_); |
203 } | 209 } |
204 | 210 |
205 bool MDnsClientImpl::Core::Init(MDnsSocketFactory* socket_factory) { | 211 bool MDnsClientImpl::Core::Init(MDnsSocketFactory* socket_factory) { |
206 return connection_->Init(socket_factory); | 212 return connection_->Init(socket_factory); |
207 } | 213 } |
208 | 214 |
(...skipping 25 matching lines...) Expand all Loading... | |
234 // TODO(noamsml): duplicate query suppression. | 240 // TODO(noamsml): duplicate query suppression. |
235 if (!(response->flags() & dns_protocol::kFlagResponse)) | 241 if (!(response->flags() & dns_protocol::kFlagResponse)) |
236 return; // Message is a query. ignore it. | 242 return; // Message is a query. ignore it. |
237 | 243 |
238 DnsRecordParser parser = response->Parser(); | 244 DnsRecordParser parser = response->Parser(); |
239 unsigned answer_count = response->answer_count() + | 245 unsigned answer_count = response->answer_count() + |
240 response->additional_answer_count(); | 246 response->additional_answer_count(); |
241 | 247 |
242 for (unsigned i = 0; i < answer_count; i++) { | 248 for (unsigned i = 0; i < answer_count; i++) { |
243 offset = parser.GetOffset(); | 249 offset = parser.GetOffset(); |
244 scoped_ptr<const RecordParsed> record = RecordParsed::CreateFrom( | 250 scoped_ptr<const RecordParsed> record = |
245 &parser, base::Time::Now()); | 251 RecordParsed::CreateFrom(&parser, clock_->Now()); |
246 | 252 |
247 if (!record) { | 253 if (!record) { |
248 DVLOG(1) << "Could not understand an mDNS record."; | 254 DVLOG(1) << "Could not understand an mDNS record."; |
249 | 255 |
250 if (offset == parser.GetOffset()) { | 256 if (offset == parser.GetOffset()) { |
251 DVLOG(1) << "Abandoned parsing the rest of the packet."; | 257 DVLOG(1) << "Abandoned parsing the rest of the packet."; |
252 return; // The parser did not advance, abort reading the packet. | 258 return; // The parser did not advance, abort reading the packet. |
253 } else { | 259 } else { |
254 continue; // We may be able to extract other records from the packet. | 260 continue; // We may be able to extract other records from the packet. |
255 } | 261 } |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
288 } | 294 } |
289 | 295 |
290 void MDnsClientImpl::Core::NotifyNsecRecord(const RecordParsed* record) { | 296 void MDnsClientImpl::Core::NotifyNsecRecord(const RecordParsed* record) { |
291 DCHECK_EQ(dns_protocol::kTypeNSEC, record->type()); | 297 DCHECK_EQ(dns_protocol::kTypeNSEC, record->type()); |
292 const NsecRecordRdata* rdata = record->rdata<NsecRecordRdata>(); | 298 const NsecRecordRdata* rdata = record->rdata<NsecRecordRdata>(); |
293 DCHECK(rdata); | 299 DCHECK(rdata); |
294 | 300 |
295 // Remove all cached records matching the nonexistent RR types. | 301 // Remove all cached records matching the nonexistent RR types. |
296 std::vector<const RecordParsed*> records_to_remove; | 302 std::vector<const RecordParsed*> records_to_remove; |
297 | 303 |
298 cache_.FindDnsRecords(0, record->name(), &records_to_remove, | 304 cache_.FindDnsRecords(0, record->name(), &records_to_remove, clock_->Now()); |
299 base::Time::Now()); | |
300 | 305 |
301 for (std::vector<const RecordParsed*>::iterator i = records_to_remove.begin(); | 306 for (std::vector<const RecordParsed*>::iterator i = records_to_remove.begin(); |
302 i != records_to_remove.end(); i++) { | 307 i != records_to_remove.end(); i++) { |
303 if ((*i)->type() == dns_protocol::kTypeNSEC) | 308 if ((*i)->type() == dns_protocol::kTypeNSEC) |
304 continue; | 309 continue; |
305 if (!rdata->GetBit((*i)->type())) { | 310 if (!rdata->GetBit((*i)->type())) { |
306 scoped_ptr<const RecordParsed> record_removed = cache_.RemoveRecord((*i)); | 311 scoped_ptr<const RecordParsed> record_removed = cache_.RemoveRecord((*i)); |
307 DCHECK(record_removed); | 312 DCHECK(record_removed); |
308 OnRecordRemoved(record_removed.get()); | 313 OnRecordRemoved(record_removed.get()); |
309 } | 314 } |
310 } | 315 } |
311 | 316 |
312 // Alert all listeners waiting for the nonexistent RR types. | 317 // Alert all listeners waiting for the nonexistent RR types. |
313 ListenerMap::iterator i = | 318 ListenerMap::iterator i = |
314 listeners_.upper_bound(ListenerKey(record->name(), 0)); | 319 listeners_.upper_bound(ListenerKey(record->name(), 0)); |
315 for (; i != listeners_.end() && i->first.first == record->name(); i++) { | 320 for (; i != listeners_.end() && i->first.first == record->name(); i++) { |
316 if (!rdata->GetBit(i->first.second)) { | 321 if (!rdata->GetBit(i->first.second)) { |
317 FOR_EACH_OBSERVER(MDnsListenerImpl, *i->second, AlertNsecRecord()); | 322 FOR_EACH_OBSERVER(MDnsListenerImpl, *i->second, AlertNsecRecord()); |
318 } | 323 } |
319 } | 324 } |
320 } | 325 } |
321 | 326 |
322 void MDnsClientImpl::Core::OnConnectionError(int error) { | 327 void MDnsClientImpl::Core::OnConnectionError(int error) { |
323 // TODO(noamsml): On connection error, recreate connection and flush cache. | 328 // TODO(noamsml): On connection error, recreate connection and flush cache. |
324 } | 329 } |
325 | 330 |
331 void MDnsClientImpl::Core::set_cleanup_timer_for_test( | |
332 scoped_ptr<base::Timer> timer) { | |
333 cleanup_timer_ = timer.Pass(); | |
334 } | |
335 | |
336 void MDnsClientImpl::Core::set_clock_for_test(scoped_ptr<base::Clock> clock) { | |
337 clock_ = clock.Pass(); | |
338 } | |
339 | |
326 void MDnsClientImpl::Core::AlertListeners( | 340 void MDnsClientImpl::Core::AlertListeners( |
327 MDnsCache::UpdateType update_type, | 341 MDnsCache::UpdateType update_type, |
328 const ListenerKey& key, | 342 const ListenerKey& key, |
329 const RecordParsed* record) { | 343 const RecordParsed* record) { |
330 ListenerMap::iterator listener_map_iterator = listeners_.find(key); | 344 ListenerMap::iterator listener_map_iterator = listeners_.find(key); |
331 if (listener_map_iterator == listeners_.end()) return; | 345 if (listener_map_iterator == listeners_.end()) return; |
332 | 346 |
333 FOR_EACH_OBSERVER(MDnsListenerImpl, *listener_map_iterator->second, | 347 FOR_EACH_OBSERVER(MDnsListenerImpl, *listener_map_iterator->second, |
334 HandleRecordUpdate(update_type, record)); | 348 HandleRecordUpdate(update_type, record)); |
335 } | 349 } |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
373 void MDnsClientImpl::Core::CleanupObserverList(const ListenerKey& key) { | 387 void MDnsClientImpl::Core::CleanupObserverList(const ListenerKey& key) { |
374 ListenerMap::iterator found = listeners_.find(key); | 388 ListenerMap::iterator found = listeners_.find(key); |
375 if (found != listeners_.end() && !found->second->might_have_observers()) { | 389 if (found != listeners_.end() && !found->second->might_have_observers()) { |
376 delete found->second; | 390 delete found->second; |
377 listeners_.erase(found); | 391 listeners_.erase(found); |
378 } | 392 } |
379 } | 393 } |
380 | 394 |
381 void MDnsClientImpl::Core::ScheduleCleanup(base::Time cleanup) { | 395 void MDnsClientImpl::Core::ScheduleCleanup(base::Time cleanup) { |
382 // Cleanup is already scheduled, no need to do anything. | 396 // Cleanup is already scheduled, no need to do anything. |
383 if (cleanup == scheduled_cleanup_) return; | 397 if (cleanup == scheduled_cleanup_) { |
398 return; | |
399 } | |
384 scheduled_cleanup_ = cleanup; | 400 scheduled_cleanup_ = cleanup; |
385 | 401 |
386 // This cancels the previously scheduled cleanup. | 402 // This cancels the previously scheduled cleanup. |
387 cleanup_callback_.Reset(base::Bind( | 403 cleanup_timer_->Stop(); |
388 &MDnsClientImpl::Core::DoCleanup, base::Unretained(this))); | |
389 | 404 |
390 // If |cleanup| is empty, then no cleanup necessary. | 405 // If |cleanup| is empty, then no cleanup necessary. |
391 if (cleanup != base::Time()) { | 406 if (cleanup != base::Time()) { |
392 base::MessageLoop::current()->PostDelayedTask( | 407 cleanup_timer_->Start( |
393 FROM_HERE, | 408 FROM_HERE, std::max(base::TimeDelta(), cleanup - clock_->Now()), |
394 cleanup_callback_.callback(), | 409 base::Bind(&MDnsClientImpl::Core::DoCleanup, base::Unretained(this))); |
395 cleanup - base::Time::Now()); | |
396 } | 410 } |
397 } | 411 } |
398 | 412 |
399 void MDnsClientImpl::Core::DoCleanup() { | 413 void MDnsClientImpl::Core::DoCleanup() { |
400 cache_.CleanupRecords(base::Time::Now(), base::Bind( | 414 cache_.CleanupRecords(clock_->Now(), |
401 &MDnsClientImpl::Core::OnRecordRemoved, base::Unretained(this))); | 415 base::Bind(&MDnsClientImpl::Core::OnRecordRemoved, |
mark a. foltz
2015/02/25 21:44:07
What cancels this callback when MDnsClientImpl is
Kevin M
2015/02/26 01:04:40
DoCleanup() can't be called if the MdnsClientImpl
mark a. foltz
2015/02/26 01:18:03
Acknowledged.
| |
416 base::Unretained(this))); | |
402 | 417 |
403 ScheduleCleanup(cache_.next_expiration()); | 418 ScheduleCleanup(cache_.next_expiration()); |
404 } | 419 } |
405 | 420 |
406 void MDnsClientImpl::Core::OnRecordRemoved( | 421 void MDnsClientImpl::Core::OnRecordRemoved( |
407 const RecordParsed* record) { | 422 const RecordParsed* record) { |
408 AlertListeners(MDnsCache::RecordRemoved, | 423 AlertListeners(MDnsCache::RecordRemoved, |
409 ListenerKey(record->name(), record->type()), record); | 424 ListenerKey(record->name(), record->type()), record); |
410 } | 425 } |
411 | 426 |
412 void MDnsClientImpl::Core::QueryCache( | 427 void MDnsClientImpl::Core::QueryCache( |
413 uint16 rrtype, const std::string& name, | 428 uint16 rrtype, const std::string& name, |
414 std::vector<const RecordParsed*>* records) const { | 429 std::vector<const RecordParsed*>* records) const { |
415 cache_.FindDnsRecords(rrtype, name, records, base::Time::Now()); | 430 cache_.FindDnsRecords(rrtype, name, records, clock_->Now()); |
416 } | 431 } |
417 | 432 |
418 MDnsClientImpl::MDnsClientImpl() { | 433 MDnsClientImpl::MDnsClientImpl() { |
419 } | 434 } |
420 | 435 |
421 MDnsClientImpl::~MDnsClientImpl() { | 436 MDnsClientImpl::~MDnsClientImpl() { |
422 } | 437 } |
423 | 438 |
424 bool MDnsClientImpl::StartListening(MDnsSocketFactory* socket_factory) { | 439 bool MDnsClientImpl::StartListening(MDnsSocketFactory* socket_factory) { |
425 DCHECK(!core_.get()); | 440 DCHECK(!core_.get()); |
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
566 static_cast<int>(base::Time::kMillisecondsPerSecond * | 581 static_cast<int>(base::Time::kMillisecondsPerSecond * |
567 kListenerRefreshRatio1 * ttl_)); | 582 kListenerRefreshRatio1 * ttl_)); |
568 | 583 |
569 base::Time next_refresh2 = last_update_ + base::TimeDelta::FromMilliseconds( | 584 base::Time next_refresh2 = last_update_ + base::TimeDelta::FromMilliseconds( |
570 static_cast<int>(base::Time::kMillisecondsPerSecond * | 585 static_cast<int>(base::Time::kMillisecondsPerSecond * |
571 kListenerRefreshRatio2 * ttl_)); | 586 kListenerRefreshRatio2 * ttl_)); |
572 | 587 |
573 base::MessageLoop::current()->PostDelayedTask( | 588 base::MessageLoop::current()->PostDelayedTask( |
574 FROM_HERE, | 589 FROM_HERE, |
575 next_refresh_.callback(), | 590 next_refresh_.callback(), |
576 next_refresh1 - base::Time::Now()); | 591 next_refresh1 - base::Time::Now()); |
mark a. foltz
2015/02/25 21:44:06
If we are converting this class to use base::Clock
Kevin M
2015/02/26 01:04:40
This required a bit of plumbing to route the Clock
| |
577 | 592 |
578 base::MessageLoop::current()->PostDelayedTask( | 593 base::MessageLoop::current()->PostDelayedTask( |
579 FROM_HERE, | 594 FROM_HERE, |
580 next_refresh_.callback(), | 595 next_refresh_.callback(), |
581 next_refresh2 - base::Time::Now()); | 596 next_refresh2 - base::Time::Now()); |
mark a. foltz
2015/02/25 21:44:07
Ditto.
Kevin M
2015/02/26 01:04:40
Done.
| |
582 } | 597 } |
583 | 598 |
584 void MDnsListenerImpl::DoRefresh() { | 599 void MDnsListenerImpl::DoRefresh() { |
585 client_->core()->SendQuery(rrtype_, name_); | 600 client_->core()->SendQuery(rrtype_, name_); |
586 } | 601 } |
587 | 602 |
588 MDnsTransactionImpl::MDnsTransactionImpl( | 603 MDnsTransactionImpl::MDnsTransactionImpl( |
589 uint16 rrtype, | 604 uint16 rrtype, |
590 const std::string& name, | 605 const std::string& name, |
591 int flags, | 606 int flags, |
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
726 | 741 |
727 void MDnsTransactionImpl::OnNsecRecord(const std::string& name, unsigned type) { | 742 void MDnsTransactionImpl::OnNsecRecord(const std::string& name, unsigned type) { |
728 TriggerCallback(RESULT_NSEC, NULL); | 743 TriggerCallback(RESULT_NSEC, NULL); |
729 } | 744 } |
730 | 745 |
731 void MDnsTransactionImpl::OnCachePurged() { | 746 void MDnsTransactionImpl::OnCachePurged() { |
732 // TODO(noamsml): Cache purge situations not yet implemented | 747 // TODO(noamsml): Cache purge situations not yet implemented |
733 } | 748 } |
734 | 749 |
735 } // namespace net | 750 } // namespace net |
OLD | NEW |