Home | History | Annotate | Download | only in mdns
      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
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/extensions/api/mdns/dns_sd_registry.h"
      6 
      7 #include "base/stl_util.h"
      8 #include "chrome/browser/extensions/api/mdns/dns_sd_device_lister.h"
      9 #include "chrome/browser/local_discovery/service_discovery_shared_client.h"
     10 
     11 using local_discovery::ServiceDiscoveryClient;
     12 using local_discovery::ServiceDiscoverySharedClient;
     13 
     14 namespace extensions {
     15 
     16 namespace {
     17 // Predicate to test if two discovered services have the same service_name.
     18 class IsSameServiceName {
     19  public:
     20   explicit IsSameServiceName(const DnsSdService& service) : service_(service) {}
     21   bool operator()(const DnsSdService& other) const {
     22     return service_.service_name == other.service_name;
     23   }
     24 
     25  private:
     26   const DnsSdService& service_;
     27 };
     28 }  // namespace
     29 
     30 DnsSdRegistry::ServiceTypeData::ServiceTypeData(
     31     scoped_ptr<DnsSdDeviceLister> lister)
     32     : ref_count(1), lister_(lister.Pass()) {}
     33 
     34 DnsSdRegistry::ServiceTypeData::~ServiceTypeData() {}
     35 
     36 void DnsSdRegistry::ServiceTypeData::ListenerAdded() {
     37   ref_count++;
     38 }
     39 
     40 bool DnsSdRegistry::ServiceTypeData::ListenerRemoved() {
     41   return --ref_count == 0;
     42 }
     43 
     44 int DnsSdRegistry::ServiceTypeData::GetListenerCount() {
     45   return ref_count;
     46 }
     47 
     48 bool DnsSdRegistry::ServiceTypeData::UpdateService(
     49       bool added, const DnsSdService& service) {
     50   DnsSdRegistry::DnsSdServiceList::iterator it =
     51       std::find_if(service_list_.begin(),
     52                    service_list_.end(),
     53                    IsSameServiceName(service));
     54   // Set to true when a service is updated in or added to the registry.
     55   bool updated_or_added = added;
     56   bool known = (it != service_list_.end());
     57   if (known) {
     58     // If added == true, but we still found the service in our cache, then just
     59     // update the existing entry, but this should not happen!
     60     DCHECK(!added);
     61     if (*it != service) {
     62       *it = service;
     63       updated_or_added = true;
     64     }
     65   } else if (added) {
     66     service_list_.push_back(service);
     67   }
     68 
     69   VLOG(1) << "UpdateService: " << service.service_name
     70           << ", added: " << added
     71           << ", known: " << known
     72           << ", updated or added: " << updated_or_added;
     73   return updated_or_added;
     74 }
     75 
     76 bool DnsSdRegistry::ServiceTypeData::RemoveService(
     77     const std::string& service_name) {
     78   for (DnsSdRegistry::DnsSdServiceList::iterator it = service_list_.begin();
     79        it != service_list_.end(); ++it) {
     80     if ((*it).service_name == service_name) {
     81       service_list_.erase(it);
     82       return true;
     83     }
     84   }
     85   return false;
     86 }
     87 
     88 bool DnsSdRegistry::ServiceTypeData::ClearServices() {
     89   lister_->Discover(false);
     90 
     91   if (service_list_.empty())
     92     return false;
     93 
     94   service_list_.clear();
     95   return true;
     96 }
     97 
     98 const DnsSdRegistry::DnsSdServiceList&
     99 DnsSdRegistry::ServiceTypeData::GetServiceList() {
    100   return service_list_;
    101 }
    102 
    103 DnsSdRegistry::DnsSdRegistry() {
    104 #if defined(ENABLE_SERVICE_DISCOVERY)
    105   service_discovery_client_ = ServiceDiscoverySharedClient::GetInstance();
    106 #endif
    107 }
    108 
    109 DnsSdRegistry::DnsSdRegistry(ServiceDiscoverySharedClient* client) {
    110   service_discovery_client_ = client;
    111 }
    112 
    113 DnsSdRegistry::~DnsSdRegistry() {}
    114 
    115 void DnsSdRegistry::AddObserver(DnsSdObserver* observer) {
    116   observers_.AddObserver(observer);
    117 }
    118 
    119 void DnsSdRegistry::RemoveObserver(DnsSdObserver* observer) {
    120   observers_.RemoveObserver(observer);
    121 }
    122 
    123 DnsSdDeviceLister* DnsSdRegistry::CreateDnsSdDeviceLister(
    124     DnsSdDelegate* delegate,
    125     const std::string& service_type,
    126     local_discovery::ServiceDiscoverySharedClient* discovery_client) {
    127   return new DnsSdDeviceLister(discovery_client, delegate, service_type);
    128 }
    129 
    130 void DnsSdRegistry::RegisterDnsSdListener(std::string service_type) {
    131   VLOG(1) << "RegisterDnsSdListener: " << service_type
    132           << ", registered: " << IsRegistered(service_type);
    133   if (service_type.empty())
    134     return;
    135 
    136   if (IsRegistered(service_type)) {
    137     service_data_map_[service_type]->ListenerAdded();
    138     DispatchApiEvent(service_type);
    139     return;
    140   }
    141 
    142   scoped_ptr<DnsSdDeviceLister> dns_sd_device_lister(CreateDnsSdDeviceLister(
    143       this, service_type, service_discovery_client_.get()));
    144   dns_sd_device_lister->Discover(false);
    145   linked_ptr<ServiceTypeData> service_type_data(
    146       new ServiceTypeData(dns_sd_device_lister.Pass()));
    147   service_data_map_[service_type] = service_type_data;
    148   DispatchApiEvent(service_type);
    149 }
    150 
    151 void DnsSdRegistry::UnregisterDnsSdListener(std::string service_type) {
    152   VLOG(1) << "UnregisterDnsSdListener: " << service_type;
    153   DnsSdRegistry::DnsSdServiceTypeDataMap::iterator it =
    154       service_data_map_.find(service_type);
    155   if (it == service_data_map_.end())
    156     return;
    157 
    158   if (service_data_map_[service_type]->ListenerRemoved())
    159     service_data_map_.erase(it);
    160 }
    161 
    162 void DnsSdRegistry::ServiceChanged(const std::string& service_type,
    163                                    bool added,
    164                                    const DnsSdService& service) {
    165   VLOG(1) << "ServiceChanged: service_type: " << service_type
    166           << ", known: " << IsRegistered(service_type)
    167           << ", service: " << service.service_name
    168           << ", added: " << added;
    169   if (!IsRegistered(service_type)) {
    170     return;
    171   }
    172 
    173   bool is_updated =
    174       service_data_map_[service_type]->UpdateService(added, service);
    175   VLOG(1) << "ServiceChanged: is_updated: " << is_updated;
    176 
    177   if (is_updated) {
    178     DispatchApiEvent(service_type);
    179   }
    180 }
    181 
    182 void DnsSdRegistry::ServiceRemoved(const std::string& service_type,
    183                                    const std::string& service_name) {
    184   VLOG(1) << "ServiceRemoved: service_type: " << service_type
    185           << ", known: " << IsRegistered(service_type)
    186           << ", service: " << service_name;
    187   if (!IsRegistered(service_type)) {
    188     return;
    189   }
    190 
    191   bool is_removed =
    192       service_data_map_[service_type]->RemoveService(service_name);
    193   VLOG(1) << "ServiceRemoved: is_removed: " << is_removed;
    194 
    195   if (is_removed)
    196     DispatchApiEvent(service_type);
    197 }
    198 
    199 void DnsSdRegistry::ServicesFlushed(const std::string& service_type) {
    200   VLOG(1) << "ServicesFlushed: service_type: " << service_type
    201           << ", known: " << IsRegistered(service_type);
    202   if (!IsRegistered(service_type)) {
    203     return;
    204   }
    205 
    206   bool is_cleared = service_data_map_[service_type]->ClearServices();
    207   VLOG(1) << "ServicesFlushed: is_cleared: " << is_cleared;
    208 
    209   if (is_cleared)
    210     DispatchApiEvent(service_type);
    211 }
    212 
    213 void DnsSdRegistry::DispatchApiEvent(const std::string& service_type) {
    214   // TODO(justinlin): Make this MaybeDispatchApiEvent instead and dispatch if a
    215   // dirty bit is set.
    216   VLOG(1) << "DispatchApiEvent: service_type: " << service_type;
    217   FOR_EACH_OBSERVER(DnsSdObserver, observers_, OnDnsSdEvent(
    218       service_type, service_data_map_[service_type]->GetServiceList()));
    219 }
    220 
    221 bool DnsSdRegistry::IsRegistered(const std::string& service_type) {
    222   return service_data_map_.find(service_type) != service_data_map_.end();
    223 }
    224 
    225 }  // namespace extensions
    226