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