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   if (it != service_list_.end()) {
     57     // If added == true, but we still found the service in our cache, then just
     58     // update the existing entry, but this should not happen!
     59     DCHECK(!added);
     60     if (*it != service) {
     61       *it = service;
     62       updated_or_added = true;
     63     }
     64   } else if (added) {
     65     service_list_.push_back(service);
     66   }
     67   return updated_or_added;
     68 };
     69 
     70 bool DnsSdRegistry::ServiceTypeData::RemoveService(
     71     const std::string& service_name) {
     72   for (DnsSdRegistry::DnsSdServiceList::iterator it = service_list_.begin();
     73        it != service_list_.end(); ++it) {
     74     if ((*it).service_name == service_name) {
     75       service_list_.erase(it);
     76       return true;
     77     }
     78   }
     79   return false;
     80 };
     81 
     82 bool DnsSdRegistry::ServiceTypeData::ClearServices() {
     83   if (service_list_.empty())
     84     return false;
     85 
     86   service_list_.clear();
     87   return true;
     88 }
     89 
     90 const DnsSdRegistry::DnsSdServiceList&
     91 DnsSdRegistry::ServiceTypeData::GetServiceList() {
     92   return service_list_;
     93 }
     94 
     95 DnsSdRegistry::DnsSdRegistry() {
     96 #if defined(ENABLE_MDNS) || defined(OS_MACOSX)
     97   service_discovery_client_ = ServiceDiscoverySharedClient::GetInstance();
     98 #endif
     99 }
    100 
    101 DnsSdRegistry::DnsSdRegistry(ServiceDiscoverySharedClient* client) {
    102   service_discovery_client_ = client;
    103 }
    104 
    105 DnsSdRegistry::~DnsSdRegistry() {}
    106 
    107 void DnsSdRegistry::AddObserver(DnsSdObserver* observer) {
    108   observers_.AddObserver(observer);
    109 }
    110 
    111 void DnsSdRegistry::RemoveObserver(DnsSdObserver* observer) {
    112   observers_.RemoveObserver(observer);
    113 }
    114 
    115 DnsSdDeviceLister* DnsSdRegistry::CreateDnsSdDeviceLister(
    116     DnsSdDelegate* delegate,
    117     const std::string& service_type,
    118     local_discovery::ServiceDiscoverySharedClient* discovery_client) {
    119   return new DnsSdDeviceLister(discovery_client, delegate, service_type);
    120 }
    121 
    122 void DnsSdRegistry::RegisterDnsSdListener(std::string service_type) {
    123   if (service_type.empty())
    124     return;
    125 
    126   if (IsRegistered(service_type)) {
    127     service_data_map_[service_type]->ListenerAdded();
    128     DispatchApiEvent(service_type);
    129     return;
    130   }
    131 
    132   scoped_ptr<DnsSdDeviceLister> dns_sd_device_lister(CreateDnsSdDeviceLister(
    133       this, service_type, service_discovery_client_));
    134   dns_sd_device_lister->Discover(false);
    135   linked_ptr<ServiceTypeData> service_type_data(
    136       new ServiceTypeData(dns_sd_device_lister.Pass()));
    137   service_data_map_[service_type] = service_type_data;
    138   DispatchApiEvent(service_type);
    139 }
    140 
    141 void DnsSdRegistry::UnregisterDnsSdListener(std::string service_type) {
    142   DnsSdRegistry::DnsSdServiceTypeDataMap::iterator it =
    143       service_data_map_.find(service_type);
    144   if (it == service_data_map_.end())
    145     return;
    146 
    147   if (service_data_map_[service_type]->ListenerRemoved())
    148     service_data_map_.erase(it);
    149 }
    150 
    151 void DnsSdRegistry::ServiceChanged(const std::string& service_type,
    152                                    bool added,
    153                                    const DnsSdService& service) {
    154   if (!IsRegistered(service_type))
    155     return;
    156 
    157   VLOG(1) << "Service changed: " << service.service_name;
    158   if (service_data_map_[service_type]->UpdateService(added, service)) {
    159     DispatchApiEvent(service_type);
    160   } else {
    161     VLOG(1) << "Failed to find existing service to update: "
    162             << service.service_name;
    163   }
    164 }
    165 
    166 void DnsSdRegistry::ServiceRemoved(const std::string& service_type,
    167                                    const std::string& service_name) {
    168   if (!IsRegistered(service_type))
    169     return;
    170 
    171   VLOG(1) << "Removing service: " << service_name;
    172   if (service_data_map_[service_type]->RemoveService(service_name)) {
    173     DispatchApiEvent(service_type);
    174   } else {
    175     VLOG(1) << "Failed to remove service: " << service_name;
    176   }
    177 }
    178 
    179 void DnsSdRegistry::ServicesFlushed(const std::string& service_type) {
    180   if (!IsRegistered(service_type))
    181     return;
    182 
    183   if (service_data_map_[service_type]->ClearServices())
    184     DispatchApiEvent(service_type);
    185 }
    186 
    187 void DnsSdRegistry::DispatchApiEvent(const std::string& service_type) {
    188   // TODO(justinlin): Make this MaybeDispatchApiEvent instead and dispatch if a
    189   // dirty bit is set.
    190   FOR_EACH_OBSERVER(DnsSdObserver, observers_, OnDnsSdEvent(
    191       service_type, service_data_map_[service_type]->GetServiceList()));
    192 }
    193 
    194 bool DnsSdRegistry::IsRegistered(const std::string& service_type) {
    195   return service_data_map_.find(service_type) != service_data_map_.end();
    196 }
    197 
    198 }  // namespace extensions
    199