Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(460)

Side by Side Diff: net/dns/mdns_client_impl.cc

Issue 132693025: Add the ability for MDnsListener to actively refresh records (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 "base/bind.h" 7 #include "base/bind.h"
8 #include "base/message_loop/message_loop_proxy.h" 8 #include "base/message_loop/message_loop_proxy.h"
9 #include "base/stl_util.h" 9 #include "base/stl_util.h"
10 #include "base/time/default_clock.h" 10 #include "base/time/default_clock.h"
11 #include "net/base/dns_util.h" 11 #include "net/base/dns_util.h"
12 #include "net/base/net_errors.h" 12 #include "net/base/net_errors.h"
13 #include "net/base/net_log.h" 13 #include "net/base/net_log.h"
14 #include "net/base/rand_callback.h" 14 #include "net/base/rand_callback.h"
15 #include "net/dns/dns_protocol.h" 15 #include "net/dns/dns_protocol.h"
16 #include "net/dns/record_rdata.h" 16 #include "net/dns/record_rdata.h"
17 #include "net/udp/datagram_socket.h" 17 #include "net/udp/datagram_socket.h"
18 18
19 // TODO(gene): Remove this temporary method of disabling NSEC support once it 19 // TODO(gene): Remove this temporary method of disabling NSEC support once it
20 // becomes clear whether this feature should be 20 // becomes clear whether this feature should be
21 // supported. http://crbug.com/255232 21 // supported. http://crbug.com/255232
22 #define ENABLE_NSEC 22 #define ENABLE_NSEC
23 23
24 namespace net { 24 namespace net {
25 25
26 namespace { 26 namespace {
27 27
28 const unsigned MDnsTransactionTimeoutSeconds = 3; 28 const unsigned MDnsTransactionTimeoutSeconds = 3;
29 // The fractions of the record's original TTL after which an active listener
30 // (one that had |SetActiveRefresh(true)| called) will send a query to refresh
31 // its cache. This happens both at 85% of the original TTL and again at 95% of
32 // the original TTL.
33 const double kListenerRefreshRatio1 = 0.85;
34 const double kListenerRefreshRatio2 = 0.95;
35 const unsigned kMillisecondsPerSecond = 1000;
29 36
30 } // namespace 37 } // namespace
31 38
32 void MDnsSocketFactoryImpl::CreateSockets( 39 void MDnsSocketFactoryImpl::CreateSockets(
33 ScopedVector<DatagramServerSocket>* sockets) { 40 ScopedVector<DatagramServerSocket>* sockets) {
34 InterfaceIndexFamilyList interfaces(GetMDnsInterfacesToBind()); 41 InterfaceIndexFamilyList interfaces(GetMDnsInterfacesToBind());
35 for (size_t i = 0; i < interfaces.size(); ++i) { 42 for (size_t i = 0; i < interfaces.size(); ++i) {
36 DCHECK(interfaces[i].second == net::ADDRESS_FAMILY_IPV4 || 43 DCHECK(interfaces[i].second == net::ADDRESS_FAMILY_IPV4 ||
37 interfaces[i].second == net::ADDRESS_FAMILY_IPV6); 44 interfaces[i].second == net::ADDRESS_FAMILY_IPV6);
38 scoped_ptr<DatagramServerSocket> socket( 45 scoped_ptr<DatagramServerSocket> socket(
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after
185 192
186 return connection_->Send(query.io_buffer(), query.io_buffer()->size()); 193 return connection_->Send(query.io_buffer(), query.io_buffer()->size());
187 } 194 }
188 195
189 void MDnsClientImpl::Core::HandlePacket(DnsResponse* response, 196 void MDnsClientImpl::Core::HandlePacket(DnsResponse* response,
190 int bytes_read) { 197 int bytes_read) {
191 unsigned offset; 198 unsigned offset;
192 // Note: We store cache keys rather than record pointers to avoid 199 // Note: We store cache keys rather than record pointers to avoid
193 // erroneous behavior in case a packet contains multiple exclusive 200 // erroneous behavior in case a packet contains multiple exclusive
194 // records with the same type and name. 201 // records with the same type and name.
195 std::map<MDnsCache::Key, MDnsListener::UpdateType> update_keys; 202 std::map<MDnsCache::Key, MDnsCache::UpdateType> update_keys;
196 203
197 if (!response->InitParseWithoutQuery(bytes_read)) { 204 if (!response->InitParseWithoutQuery(bytes_read)) {
198 LOG(WARNING) << "Could not understand an mDNS packet."; 205 LOG(WARNING) << "Could not understand an mDNS packet.";
199 return; // Message is unreadable. 206 return; // Message is unreadable.
200 } 207 }
201 208
202 // TODO(noamsml): duplicate query suppression. 209 // TODO(noamsml): duplicate query suppression.
203 if (!(response->flags() & dns_protocol::kFlagResponse)) 210 if (!(response->flags() & dns_protocol::kFlagResponse))
204 return; // Message is a query. ignore it. 211 return; // Message is a query. ignore it.
205 212
(...skipping 22 matching lines...) Expand all
228 LOG(WARNING) << "Received an mDNS record with non-IN class. Ignoring."; 235 LOG(WARNING) << "Received an mDNS record with non-IN class. Ignoring.";
229 continue; // Ignore all records not in the IN class. 236 continue; // Ignore all records not in the IN class.
230 } 237 }
231 238
232 MDnsCache::Key update_key = MDnsCache::Key::CreateFor(record.get()); 239 MDnsCache::Key update_key = MDnsCache::Key::CreateFor(record.get());
233 MDnsCache::UpdateType update = cache_.UpdateDnsRecord(record.Pass()); 240 MDnsCache::UpdateType update = cache_.UpdateDnsRecord(record.Pass());
234 241
235 // Cleanup time may have changed. 242 // Cleanup time may have changed.
236 ScheduleCleanup(cache_.next_expiration()); 243 ScheduleCleanup(cache_.next_expiration());
237 244
238 if (update != MDnsCache::NoChange) { 245 update_keys.insert(std::make_pair(update_key, update));
239 MDnsListener::UpdateType update_external;
240
241 switch (update) {
242 case MDnsCache::RecordAdded:
243 update_external = MDnsListener::RECORD_ADDED;
244 break;
245 case MDnsCache::RecordChanged:
246 update_external = MDnsListener::RECORD_CHANGED;
247 break;
248 case MDnsCache::NoChange:
249 default:
250 NOTREACHED();
251 // Dummy assignment to suppress compiler warning.
252 update_external = MDnsListener::RECORD_CHANGED;
253 break;
254 }
255
256 update_keys.insert(std::make_pair(update_key, update_external));
257 }
258 } 246 }
259 247
260 for (std::map<MDnsCache::Key, MDnsListener::UpdateType>::iterator i = 248 for (std::map<MDnsCache::Key, MDnsCache::UpdateType>::iterator i =
261 update_keys.begin(); i != update_keys.end(); i++) { 249 update_keys.begin(); i != update_keys.end(); i++) {
262 const RecordParsed* record = cache_.LookupKey(i->first); 250 const RecordParsed* record = cache_.LookupKey(i->first);
263 if (!record) 251 if (!record)
264 continue; 252 continue;
265 253
266 if (record->type() == dns_protocol::kTypeNSEC) { 254 if (record->type() == dns_protocol::kTypeNSEC) {
267 #if defined(ENABLE_NSEC) 255 #if defined(ENABLE_NSEC)
268 NotifyNsecRecord(record); 256 NotifyNsecRecord(record);
269 #endif 257 #endif
270 } else { 258 } else {
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
304 FOR_EACH_OBSERVER(MDnsListenerImpl, *i->second, AlertNsecRecord()); 292 FOR_EACH_OBSERVER(MDnsListenerImpl, *i->second, AlertNsecRecord());
305 } 293 }
306 } 294 }
307 } 295 }
308 296
309 void MDnsClientImpl::Core::OnConnectionError(int error) { 297 void MDnsClientImpl::Core::OnConnectionError(int error) {
310 // TODO(noamsml): On connection error, recreate connection and flush cache. 298 // TODO(noamsml): On connection error, recreate connection and flush cache.
311 } 299 }
312 300
313 void MDnsClientImpl::Core::AlertListeners( 301 void MDnsClientImpl::Core::AlertListeners(
314 MDnsListener::UpdateType update_type, 302 MDnsCache::UpdateType update_type,
315 const ListenerKey& key, 303 const ListenerKey& key,
316 const RecordParsed* record) { 304 const RecordParsed* record) {
317 ListenerMap::iterator listener_map_iterator = listeners_.find(key); 305 ListenerMap::iterator listener_map_iterator = listeners_.find(key);
318 if (listener_map_iterator == listeners_.end()) return; 306 if (listener_map_iterator == listeners_.end()) return;
319 307
320 FOR_EACH_OBSERVER(MDnsListenerImpl, *listener_map_iterator->second, 308 FOR_EACH_OBSERVER(MDnsListenerImpl, *listener_map_iterator->second,
321 AlertDelegate(update_type, record)); 309 HandleRecordUpdate(update_type, record));
322 } 310 }
323 311
324 void MDnsClientImpl::Core::AddListener( 312 void MDnsClientImpl::Core::AddListener(
325 MDnsListenerImpl* listener) { 313 MDnsListenerImpl* listener) {
326 ListenerKey key(listener->GetName(), listener->GetType()); 314 ListenerKey key(listener->GetName(), listener->GetType());
327 std::pair<ListenerMap::iterator, bool> observer_insert_result = 315 std::pair<ListenerMap::iterator, bool> observer_insert_result =
328 listeners_.insert( 316 listeners_.insert(
329 make_pair(key, static_cast<ObserverList<MDnsListenerImpl>*>(NULL))); 317 make_pair(key, static_cast<ObserverList<MDnsListenerImpl>*>(NULL)));
330 318
331 // If an equivalent key does not exist, actually create the observer list. 319 // If an equivalent key does not exist, actually create the observer list.
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
385 373
386 void MDnsClientImpl::Core::DoCleanup() { 374 void MDnsClientImpl::Core::DoCleanup() {
387 cache_.CleanupRecords(base::Time::Now(), base::Bind( 375 cache_.CleanupRecords(base::Time::Now(), base::Bind(
388 &MDnsClientImpl::Core::OnRecordRemoved, base::Unretained(this))); 376 &MDnsClientImpl::Core::OnRecordRemoved, base::Unretained(this)));
389 377
390 ScheduleCleanup(cache_.next_expiration()); 378 ScheduleCleanup(cache_.next_expiration());
391 } 379 }
392 380
393 void MDnsClientImpl::Core::OnRecordRemoved( 381 void MDnsClientImpl::Core::OnRecordRemoved(
394 const RecordParsed* record) { 382 const RecordParsed* record) {
395 AlertListeners(MDnsListener::RECORD_REMOVED, 383 AlertListeners(MDnsCache::RecordRemoved,
396 ListenerKey(record->name(), record->type()), record); 384 ListenerKey(record->name(), record->type()), record);
397 } 385 }
398 386
399 void MDnsClientImpl::Core::QueryCache( 387 void MDnsClientImpl::Core::QueryCache(
400 uint16 rrtype, const std::string& name, 388 uint16 rrtype, const std::string& name,
401 std::vector<const RecordParsed*>* records) const { 389 std::vector<const RecordParsed*>* records) const {
402 cache_.FindDnsRecords(rrtype, name, records, base::Time::Now()); 390 cache_.FindDnsRecords(rrtype, name, records, base::Time::Now());
403 } 391 }
404 392
405 MDnsClientImpl::MDnsClientImpl() { 393 MDnsClientImpl::MDnsClientImpl() {
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
442 return scoped_ptr<MDnsTransaction>( 430 return scoped_ptr<MDnsTransaction>(
443 new MDnsTransactionImpl(rrtype, name, flags, callback, this)); 431 new MDnsTransactionImpl(rrtype, name, flags, callback, this));
444 } 432 }
445 433
446 MDnsListenerImpl::MDnsListenerImpl( 434 MDnsListenerImpl::MDnsListenerImpl(
447 uint16 rrtype, 435 uint16 rrtype,
448 const std::string& name, 436 const std::string& name,
449 MDnsListener::Delegate* delegate, 437 MDnsListener::Delegate* delegate,
450 MDnsClientImpl* client) 438 MDnsClientImpl* client)
451 : rrtype_(rrtype), name_(name), client_(client), delegate_(delegate), 439 : rrtype_(rrtype), name_(name), client_(client), delegate_(delegate),
452 started_(false) { 440 started_(false), active_refresh_(false) {
441 }
442
443 MDnsListenerImpl::~MDnsListenerImpl() {
444 if (started_) {
445 DCHECK(client_->core());
446 client_->core()->RemoveListener(this);
447 }
453 } 448 }
454 449
455 bool MDnsListenerImpl::Start() { 450 bool MDnsListenerImpl::Start() {
456 DCHECK(!started_); 451 DCHECK(!started_);
457 452
458 started_ = true; 453 started_ = true;
459 454
460 DCHECK(client_->core()); 455 DCHECK(client_->core());
461 client_->core()->AddListener(this); 456 client_->core()->AddListener(this);
462 457
463 return true; 458 return true;
464 } 459 }
465 460
466 MDnsListenerImpl::~MDnsListenerImpl() { 461 void MDnsListenerImpl::SetActiveRefresh(bool active_refresh) {
462 active_refresh_ = active_refresh;
463
467 if (started_) { 464 if (started_) {
468 DCHECK(client_->core()); 465 if (!active_refresh_) {
469 client_->core()->RemoveListener(this); 466 next_refresh_.Cancel();
467 } else if (last_update_ != base::Time()) {
468 ScheduleNextRefresh();
469 }
470 } 470 }
471 } 471 }
472 472
473 const std::string& MDnsListenerImpl::GetName() const { 473 const std::string& MDnsListenerImpl::GetName() const {
474 return name_; 474 return name_;
475 } 475 }
476 476
477 uint16 MDnsListenerImpl::GetType() const { 477 uint16 MDnsListenerImpl::GetType() const {
478 return rrtype_; 478 return rrtype_;
479 } 479 }
480 480
481 void MDnsListenerImpl::AlertDelegate(MDnsListener::UpdateType update_type, 481 void MDnsListenerImpl::HandleRecordUpdate(MDnsCache::UpdateType update_type,
482 const RecordParsed* record) { 482 const RecordParsed* record) {
483 DCHECK(started_); 483 DCHECK(started_);
484 delegate_->OnRecordUpdate(update_type, record); 484
485 if (update_type != MDnsCache::RecordRemoved) {
486 ttl_ = record->ttl();
487 last_update_ = record->time_created();
488
489 ScheduleNextRefresh();
490 }
491
492 if (update_type != MDnsCache::NoChange) {
493 MDnsListener::UpdateType update_external;
494
495 switch (update_type) {
496 case MDnsCache::RecordAdded:
497 update_external = MDnsListener::RECORD_ADDED;
498 break;
499 case MDnsCache::RecordChanged:
500 update_external = MDnsListener::RECORD_CHANGED;
501 break;
502 case MDnsCache::RecordRemoved:
503 update_external = MDnsListener::RECORD_REMOVED;
504 break;
505 case MDnsCache::NoChange:
506 default:
507 NOTREACHED();
508 // Dummy assignment to suppress compiler warning.
509 update_external = MDnsListener::RECORD_CHANGED;
510 break;
511 }
512
513 delegate_->OnRecordUpdate(update_external, record);
514 }
485 } 515 }
486 516
487 void MDnsListenerImpl::AlertNsecRecord() { 517 void MDnsListenerImpl::AlertNsecRecord() {
488 DCHECK(started_); 518 DCHECK(started_);
489 delegate_->OnNsecRecord(name_, rrtype_); 519 delegate_->OnNsecRecord(name_, rrtype_);
490 } 520 }
491 521
522 void MDnsListenerImpl::ScheduleNextRefresh() {
523 DCHECK(last_update_ != base::Time());
524
525 if (!active_refresh_)
526 return;
527
528 // A zero TTL is a goodbye packet and should not be refreshed.
529 if (ttl_ == 0) {
530 next_refresh_.Cancel();
531 return;
532 }
533
534 next_refresh_.Reset(base::Bind(&MDnsListenerImpl::DoRefresh,
535 AsWeakPtr()));
536
537 // Schedule refreshes at both 85% and 95% of the original TTL. These will both
538 // be canceled and rescheduled if the record's TTL is updated due to a
539 // response being received.
540 base::Time next_refresh1 = last_update_ + base::TimeDelta::FromMilliseconds(
541 static_cast<int>(kMillisecondsPerSecond *
542 kListenerRefreshRatio1 * ttl_));
543
544 base::Time next_refresh2 = last_update_ + base::TimeDelta::FromMilliseconds(
545 static_cast<int>(kMillisecondsPerSecond *
546 kListenerRefreshRatio2 * ttl_));
547
548 base::MessageLoop::current()->PostDelayedTask(
549 FROM_HERE,
550 next_refresh_.callback(),
551 next_refresh1 - base::Time::Now());
552
553 base::MessageLoop::current()->PostDelayedTask(
554 FROM_HERE,
555 next_refresh_.callback(),
556 next_refresh2 - base::Time::Now());
557 }
558
559 void MDnsListenerImpl::DoRefresh() {
560 client_->core()->SendQuery(rrtype_, name_);
561 }
562
492 MDnsTransactionImpl::MDnsTransactionImpl( 563 MDnsTransactionImpl::MDnsTransactionImpl(
493 uint16 rrtype, 564 uint16 rrtype,
494 const std::string& name, 565 const std::string& name,
495 int flags, 566 int flags,
496 const MDnsTransaction::ResultCallback& callback, 567 const MDnsTransaction::ResultCallback& callback,
497 MDnsClientImpl* client) 568 MDnsClientImpl* client)
498 : rrtype_(rrtype), name_(name), callback_(callback), client_(client), 569 : rrtype_(rrtype), name_(name), callback_(callback), client_(client),
499 started_(false), flags_(flags) { 570 started_(false), flags_(flags) {
500 DCHECK((flags_ & MDnsTransaction::FLAG_MASK) == flags_); 571 DCHECK((flags_ & MDnsTransaction::FLAG_MASK) == flags_);
501 DCHECK(flags_ & MDnsTransaction::QUERY_CACHE || 572 DCHECK(flags_ & MDnsTransaction::QUERY_CACHE ||
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after
630 701
631 void MDnsTransactionImpl::OnNsecRecord(const std::string& name, unsigned type) { 702 void MDnsTransactionImpl::OnNsecRecord(const std::string& name, unsigned type) {
632 TriggerCallback(RESULT_NSEC, NULL); 703 TriggerCallback(RESULT_NSEC, NULL);
633 } 704 }
634 705
635 void MDnsTransactionImpl::OnCachePurged() { 706 void MDnsTransactionImpl::OnCachePurged() {
636 // TODO(noamsml): Cache purge situations not yet implemented 707 // TODO(noamsml): Cache purge situations not yet implemented
637 } 708 }
638 709
639 } // namespace net 710 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698