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

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 const double kListenerRefreshPercentage1 = 0.85;
szym 2014/01/23 11:24:03 Percentage suggests that this is divided by 100, i
Noam Samuel 2014/01/23 17:50:42 The time is relative to the record's original TTL,
30 const double kListenerRefreshPercentage2 = 0.95;
31 const unsigned kMillisecondsPerSecond = 1000;
29 32
30 } // namespace 33 } // namespace
31 34
32 void MDnsSocketFactoryImpl::CreateSockets( 35 void MDnsSocketFactoryImpl::CreateSockets(
33 ScopedVector<DatagramServerSocket>* sockets) { 36 ScopedVector<DatagramServerSocket>* sockets) {
34 InterfaceIndexFamilyList interfaces(GetMDnsInterfacesToBind()); 37 InterfaceIndexFamilyList interfaces(GetMDnsInterfacesToBind());
35 for (size_t i = 0; i < interfaces.size(); ++i) { 38 for (size_t i = 0; i < interfaces.size(); ++i) {
36 DCHECK(interfaces[i].second == net::ADDRESS_FAMILY_IPV4 || 39 DCHECK(interfaces[i].second == net::ADDRESS_FAMILY_IPV4 ||
37 interfaces[i].second == net::ADDRESS_FAMILY_IPV6); 40 interfaces[i].second == net::ADDRESS_FAMILY_IPV6);
38 scoped_ptr<DatagramServerSocket> socket( 41 scoped_ptr<DatagramServerSocket> socket(
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after
185 188
186 return connection_->Send(query.io_buffer(), query.io_buffer()->size()); 189 return connection_->Send(query.io_buffer(), query.io_buffer()->size());
187 } 190 }
188 191
189 void MDnsClientImpl::Core::HandlePacket(DnsResponse* response, 192 void MDnsClientImpl::Core::HandlePacket(DnsResponse* response,
190 int bytes_read) { 193 int bytes_read) {
191 unsigned offset; 194 unsigned offset;
192 // Note: We store cache keys rather than record pointers to avoid 195 // Note: We store cache keys rather than record pointers to avoid
193 // erroneous behavior in case a packet contains multiple exclusive 196 // erroneous behavior in case a packet contains multiple exclusive
194 // records with the same type and name. 197 // records with the same type and name.
195 std::map<MDnsCache::Key, MDnsListener::UpdateType> update_keys; 198 std::map<MDnsCache::Key, MDnsCache::UpdateType> update_keys;
196 199
197 if (!response->InitParseWithoutQuery(bytes_read)) { 200 if (!response->InitParseWithoutQuery(bytes_read)) {
198 LOG(WARNING) << "Could not understand an mDNS packet."; 201 LOG(WARNING) << "Could not understand an mDNS packet.";
199 return; // Message is unreadable. 202 return; // Message is unreadable.
200 } 203 }
201 204
202 // TODO(noamsml): duplicate query suppression. 205 // TODO(noamsml): duplicate query suppression.
203 if (!(response->flags() & dns_protocol::kFlagResponse)) 206 if (!(response->flags() & dns_protocol::kFlagResponse))
204 return; // Message is a query. ignore it. 207 return; // Message is a query. ignore it.
205 208
(...skipping 22 matching lines...) Expand all
228 LOG(WARNING) << "Received an mDNS record with non-IN class. Ignoring."; 231 LOG(WARNING) << "Received an mDNS record with non-IN class. Ignoring.";
229 continue; // Ignore all records not in the IN class. 232 continue; // Ignore all records not in the IN class.
230 } 233 }
231 234
232 MDnsCache::Key update_key = MDnsCache::Key::CreateFor(record.get()); 235 MDnsCache::Key update_key = MDnsCache::Key::CreateFor(record.get());
233 MDnsCache::UpdateType update = cache_.UpdateDnsRecord(record.Pass()); 236 MDnsCache::UpdateType update = cache_.UpdateDnsRecord(record.Pass());
234 237
235 // Cleanup time may have changed. 238 // Cleanup time may have changed.
236 ScheduleCleanup(cache_.next_expiration()); 239 ScheduleCleanup(cache_.next_expiration());
237 240
238 if (update != MDnsCache::NoChange) { 241 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 } 242 }
259 243
260 for (std::map<MDnsCache::Key, MDnsListener::UpdateType>::iterator i = 244 for (std::map<MDnsCache::Key, MDnsCache::UpdateType>::iterator i =
261 update_keys.begin(); i != update_keys.end(); i++) { 245 update_keys.begin(); i != update_keys.end(); i++) {
262 const RecordParsed* record = cache_.LookupKey(i->first); 246 const RecordParsed* record = cache_.LookupKey(i->first);
263 if (!record) 247 if (!record)
264 continue; 248 continue;
265 249
266 if (record->type() == dns_protocol::kTypeNSEC) { 250 if (record->type() == dns_protocol::kTypeNSEC) {
267 #if defined(ENABLE_NSEC) 251 #if defined(ENABLE_NSEC)
268 NotifyNsecRecord(record); 252 NotifyNsecRecord(record);
269 #endif 253 #endif
270 } else { 254 } else {
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
304 FOR_EACH_OBSERVER(MDnsListenerImpl, *i->second, AlertNsecRecord()); 288 FOR_EACH_OBSERVER(MDnsListenerImpl, *i->second, AlertNsecRecord());
305 } 289 }
306 } 290 }
307 } 291 }
308 292
309 void MDnsClientImpl::Core::OnConnectionError(int error) { 293 void MDnsClientImpl::Core::OnConnectionError(int error) {
310 // TODO(noamsml): On connection error, recreate connection and flush cache. 294 // TODO(noamsml): On connection error, recreate connection and flush cache.
311 } 295 }
312 296
313 void MDnsClientImpl::Core::AlertListeners( 297 void MDnsClientImpl::Core::AlertListeners(
314 MDnsListener::UpdateType update_type, 298 MDnsCache::UpdateType update_type,
315 const ListenerKey& key, 299 const ListenerKey& key,
316 const RecordParsed* record) { 300 const RecordParsed* record) {
317 ListenerMap::iterator listener_map_iterator = listeners_.find(key); 301 ListenerMap::iterator listener_map_iterator = listeners_.find(key);
318 if (listener_map_iterator == listeners_.end()) return; 302 if (listener_map_iterator == listeners_.end()) return;
319 303
320 FOR_EACH_OBSERVER(MDnsListenerImpl, *listener_map_iterator->second, 304 FOR_EACH_OBSERVER(MDnsListenerImpl, *listener_map_iterator->second,
321 AlertDelegate(update_type, record)); 305 HandleRecordUpdate(update_type, record));
322 } 306 }
323 307
324 void MDnsClientImpl::Core::AddListener( 308 void MDnsClientImpl::Core::AddListener(
325 MDnsListenerImpl* listener) { 309 MDnsListenerImpl* listener) {
326 ListenerKey key(listener->GetName(), listener->GetType()); 310 ListenerKey key(listener->GetName(), listener->GetType());
327 std::pair<ListenerMap::iterator, bool> observer_insert_result = 311 std::pair<ListenerMap::iterator, bool> observer_insert_result =
328 listeners_.insert( 312 listeners_.insert(
329 make_pair(key, static_cast<ObserverList<MDnsListenerImpl>*>(NULL))); 313 make_pair(key, static_cast<ObserverList<MDnsListenerImpl>*>(NULL)));
330 314
331 // If an equivalent key does not exist, actually create the observer list. 315 // 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 369
386 void MDnsClientImpl::Core::DoCleanup() { 370 void MDnsClientImpl::Core::DoCleanup() {
387 cache_.CleanupRecords(base::Time::Now(), base::Bind( 371 cache_.CleanupRecords(base::Time::Now(), base::Bind(
388 &MDnsClientImpl::Core::OnRecordRemoved, base::Unretained(this))); 372 &MDnsClientImpl::Core::OnRecordRemoved, base::Unretained(this)));
389 373
390 ScheduleCleanup(cache_.next_expiration()); 374 ScheduleCleanup(cache_.next_expiration());
391 } 375 }
392 376
393 void MDnsClientImpl::Core::OnRecordRemoved( 377 void MDnsClientImpl::Core::OnRecordRemoved(
394 const RecordParsed* record) { 378 const RecordParsed* record) {
395 AlertListeners(MDnsListener::RECORD_REMOVED, 379 AlertListeners(MDnsCache::RecordRemoved,
396 ListenerKey(record->name(), record->type()), record); 380 ListenerKey(record->name(), record->type()), record);
397 } 381 }
398 382
399 void MDnsClientImpl::Core::QueryCache( 383 void MDnsClientImpl::Core::QueryCache(
400 uint16 rrtype, const std::string& name, 384 uint16 rrtype, const std::string& name,
401 std::vector<const RecordParsed*>* records) const { 385 std::vector<const RecordParsed*>* records) const {
402 cache_.FindDnsRecords(rrtype, name, records, base::Time::Now()); 386 cache_.FindDnsRecords(rrtype, name, records, base::Time::Now());
403 } 387 }
404 388
405 MDnsClientImpl::MDnsClientImpl() { 389 MDnsClientImpl::MDnsClientImpl() {
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
442 return scoped_ptr<MDnsTransaction>( 426 return scoped_ptr<MDnsTransaction>(
443 new MDnsTransactionImpl(rrtype, name, flags, callback, this)); 427 new MDnsTransactionImpl(rrtype, name, flags, callback, this));
444 } 428 }
445 429
446 MDnsListenerImpl::MDnsListenerImpl( 430 MDnsListenerImpl::MDnsListenerImpl(
447 uint16 rrtype, 431 uint16 rrtype,
448 const std::string& name, 432 const std::string& name,
449 MDnsListener::Delegate* delegate, 433 MDnsListener::Delegate* delegate,
450 MDnsClientImpl* client) 434 MDnsClientImpl* client)
451 : rrtype_(rrtype), name_(name), client_(client), delegate_(delegate), 435 : rrtype_(rrtype), name_(name), client_(client), delegate_(delegate),
452 started_(false) { 436 started_(false), active_refresh_(false) {
437 }
438
439 MDnsListenerImpl::~MDnsListenerImpl() {
440 if (started_) {
441 DCHECK(client_->core());
442 client_->core()->RemoveListener(this);
443 }
453 } 444 }
454 445
455 bool MDnsListenerImpl::Start() { 446 bool MDnsListenerImpl::Start() {
456 DCHECK(!started_); 447 DCHECK(!started_);
457 448
458 started_ = true; 449 started_ = true;
459 450
460 DCHECK(client_->core()); 451 DCHECK(client_->core());
461 client_->core()->AddListener(this); 452 client_->core()->AddListener(this);
462 453
463 return true; 454 return true;
464 } 455 }
465 456
466 MDnsListenerImpl::~MDnsListenerImpl() { 457 void MDnsListenerImpl::SetActiveRefresh(bool active_refresh) {
458 active_refresh_ = active_refresh;
459
467 if (started_) { 460 if (started_) {
468 DCHECK(client_->core()); 461 if (!active_refresh_) {
469 client_->core()->RemoveListener(this); 462 next_refresh_.Cancel();
463 } else if (last_update_ != base::Time()) {
464 ScheduleNextRefresh();
465 }
470 } 466 }
471 } 467 }
472 468
473 const std::string& MDnsListenerImpl::GetName() const { 469 const std::string& MDnsListenerImpl::GetName() const {
474 return name_; 470 return name_;
475 } 471 }
476 472
477 uint16 MDnsListenerImpl::GetType() const { 473 uint16 MDnsListenerImpl::GetType() const {
478 return rrtype_; 474 return rrtype_;
479 } 475 }
480 476
481 void MDnsListenerImpl::AlertDelegate(MDnsListener::UpdateType update_type, 477 void MDnsListenerImpl::HandleRecordUpdate(MDnsCache::UpdateType update_type,
482 const RecordParsed* record) { 478 const RecordParsed* record) {
483 DCHECK(started_); 479 DCHECK(started_);
484 delegate_->OnRecordUpdate(update_type, record); 480
481 if (update_type != MDnsCache::RecordRemoved) {
482 ttl_ = record->ttl();
483 last_update_ = base::Time::Now();
484
485 ScheduleNextRefresh();
486 }
487
488 if (update_type != MDnsCache::NoChange) {
489 MDnsListener::UpdateType update_external;
490
491 switch (update_type) {
492 case MDnsCache::RecordAdded:
493 update_external = MDnsListener::RECORD_ADDED;
494 break;
495 case MDnsCache::RecordChanged:
496 update_external = MDnsListener::RECORD_CHANGED;
497 break;
498 case MDnsCache::RecordRemoved:
499 update_external = MDnsListener::RECORD_REMOVED;
500 break;
501 case MDnsCache::NoChange:
502 default:
503 NOTREACHED();
504 // Dummy assignment to suppress compiler warning.
505 update_external = MDnsListener::RECORD_CHANGED;
506 break;
507 }
508
509 delegate_->OnRecordUpdate(update_external, record);
510 }
485 } 511 }
486 512
487 void MDnsListenerImpl::AlertNsecRecord() { 513 void MDnsListenerImpl::AlertNsecRecord() {
488 DCHECK(started_); 514 DCHECK(started_);
489 delegate_->OnNsecRecord(name_, rrtype_); 515 delegate_->OnNsecRecord(name_, rrtype_);
490 } 516 }
491 517
518 void MDnsListenerImpl::ScheduleNextRefresh() {
szym 2014/01/23 11:24:03 This function silently assumes that if active_refr
Noam Samuel 2014/01/23 17:50:42 Done.
519 if (active_refresh_) {
szym 2014/01/23 11:24:03 By convention this should be: if (!active_refresh_
Noam Samuel 2014/01/23 17:50:42 Done.
520 // A zero TTL is a goodbye packet and should not be refreshed.
521 if (ttl_ == 0) {
522 next_refresh_.Cancel();
523 return;
524 }
525
526 next_refresh_.Reset(base::Bind(&MDnsListenerImpl::DoRefresh,
527 AsWeakPtr()));
528
529 base::Time next_refresh1 = last_update_ + base::TimeDelta::FromMilliseconds(
530 static_cast<int>(kMillisecondsPerSecond *
531 kListenerRefreshPercentage1 * ttl_));
532
533 base::Time next_refresh2 = last_update_ + base::TimeDelta::FromMilliseconds(
szym 2014/01/23 11:24:03 You need a comment somewhere why two refresh tasks
Noam Samuel 2014/01/23 17:50:42 Done.
534 static_cast<int>(kMillisecondsPerSecond *
535 kListenerRefreshPercentage2 * ttl_));
536
537 base::MessageLoop::current()->PostDelayedTask(
538 FROM_HERE,
539 next_refresh_.callback(),
540 next_refresh1 - base::Time::Now());
541
542 base::MessageLoop::current()->PostDelayedTask(
543 FROM_HERE,
544 next_refresh_.callback(),
545 next_refresh2 - base::Time::Now());
546 }
547 }
548
549 void MDnsListenerImpl::DoRefresh() {
550 client_->core()->SendQuery(rrtype_, name_);
551 }
552
492 MDnsTransactionImpl::MDnsTransactionImpl( 553 MDnsTransactionImpl::MDnsTransactionImpl(
493 uint16 rrtype, 554 uint16 rrtype,
494 const std::string& name, 555 const std::string& name,
495 int flags, 556 int flags,
496 const MDnsTransaction::ResultCallback& callback, 557 const MDnsTransaction::ResultCallback& callback,
497 MDnsClientImpl* client) 558 MDnsClientImpl* client)
498 : rrtype_(rrtype), name_(name), callback_(callback), client_(client), 559 : rrtype_(rrtype), name_(name), callback_(callback), client_(client),
499 started_(false), flags_(flags) { 560 started_(false), flags_(flags) {
500 DCHECK((flags_ & MDnsTransaction::FLAG_MASK) == flags_); 561 DCHECK((flags_ & MDnsTransaction::FLAG_MASK) == flags_);
501 DCHECK(flags_ & MDnsTransaction::QUERY_CACHE || 562 DCHECK(flags_ & MDnsTransaction::QUERY_CACHE ||
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after
630 691
631 void MDnsTransactionImpl::OnNsecRecord(const std::string& name, unsigned type) { 692 void MDnsTransactionImpl::OnNsecRecord(const std::string& name, unsigned type) {
632 TriggerCallback(RESULT_NSEC, NULL); 693 TriggerCallback(RESULT_NSEC, NULL);
633 } 694 }
634 695
635 void MDnsTransactionImpl::OnCachePurged() { 696 void MDnsTransactionImpl::OnCachePurged() {
636 // TODO(noamsml): Cache purge situations not yet implemented 697 // TODO(noamsml): Cache purge situations not yet implemented
637 } 698 }
638 699
639 } // namespace net 700 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698