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