- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / local_discovery / service_discovery_host_client.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/local_discovery/service_discovery_host_client.h"
6
7 #include "chrome/common/local_discovery/local_discovery_messages.h"
8 #include "content/public/browser/browser_thread.h"
9 #include "content/public/browser/utility_process_host.h"
10 #include "net/socket/socket_descriptor.h"
11
12 #if defined(OS_POSIX)
13 #include "base/file_descriptor_posix.h"
14 #endif  // OS_POSIX
15
16 namespace local_discovery {
17
18 using content::BrowserThread;
19 using content::UtilityProcessHost;
20
21 class ServiceDiscoveryHostClient::ServiceWatcherProxy : public ServiceWatcher {
22  public:
23   ServiceWatcherProxy(ServiceDiscoveryHostClient* host,
24                       const std::string& service_type,
25                       const ServiceWatcher::UpdatedCallback& callback)
26       : host_(host),
27         service_type_(service_type),
28         id_(host_->RegisterWatcherCallback(callback)),
29         started_(false) {
30   }
31
32   virtual ~ServiceWatcherProxy() {
33     DVLOG(1) << "~ServiceWatcherProxy with id " << id_;
34     host_->UnregisterWatcherCallback(id_);
35     if (started_)
36       host_->Send(new LocalDiscoveryMsg_DestroyWatcher(id_));
37   }
38
39   virtual void Start() OVERRIDE {
40     DVLOG(1) << "ServiceWatcher::Start with id " << id_;
41     DCHECK(!started_);
42     host_->Send(new LocalDiscoveryMsg_StartWatcher(id_, service_type_));
43     started_ = true;
44   }
45
46   virtual void DiscoverNewServices(bool force_update) OVERRIDE {
47     DVLOG(1) << "ServiceWatcher::DiscoverNewServices with id " << id_;
48     DCHECK(started_);
49     host_->Send(new LocalDiscoveryMsg_DiscoverServices(id_, force_update));
50   }
51
52   virtual std::string GetServiceType() const OVERRIDE {
53     return service_type_;
54   }
55
56  private:
57   scoped_refptr<ServiceDiscoveryHostClient> host_;
58   const std::string service_type_;
59   const uint64 id_;
60   bool started_;
61 };
62
63 class ServiceDiscoveryHostClient::ServiceResolverProxy
64     : public ServiceResolver {
65  public:
66   ServiceResolverProxy(ServiceDiscoveryHostClient* host,
67                        const std::string& service_name,
68                        const ServiceResolver::ResolveCompleteCallback& callback)
69       : host_(host),
70         service_name_(service_name),
71         id_(host->RegisterResolverCallback(callback)),
72         started_(false) {
73   }
74
75   virtual ~ServiceResolverProxy() {
76     DVLOG(1) << "~ServiceResolverProxy with id " << id_;
77     host_->UnregisterResolverCallback(id_);
78     if (started_)
79       host_->Send(new LocalDiscoveryMsg_DestroyResolver(id_));
80   }
81
82   virtual void StartResolving() OVERRIDE {
83     DVLOG(1) << "ServiceResolverProxy::StartResolving with id " << id_;
84     DCHECK(!started_);
85     host_->Send(new LocalDiscoveryMsg_ResolveService(id_, service_name_));
86     started_ = true;
87   }
88
89   virtual std::string GetName() const OVERRIDE {
90     return service_name_;
91   }
92
93  private:
94   scoped_refptr<ServiceDiscoveryHostClient> host_;
95   const std::string service_name_;
96   const uint64 id_;
97   bool started_;
98 };
99
100 class ServiceDiscoveryHostClient::LocalDomainResolverProxy
101     : public LocalDomainResolver {
102  public:
103   LocalDomainResolverProxy(ServiceDiscoveryHostClient* host,
104                        const std::string& domain,
105                        net::AddressFamily address_family,
106                        const LocalDomainResolver::IPAddressCallback& callback)
107       : host_(host),
108         domain_(domain),
109         address_family_(address_family),
110         id_(host->RegisterLocalDomainResolverCallback(callback)),
111         started_(false) {
112   }
113
114   virtual ~LocalDomainResolverProxy() {
115     DVLOG(1) << "~LocalDomainResolverProxy with id " << id_;
116     host_->UnregisterLocalDomainResolverCallback(id_);
117     if (started_)
118       host_->Send(new LocalDiscoveryMsg_DestroyLocalDomainResolver(id_));
119   }
120
121   virtual void Start() OVERRIDE {
122     DVLOG(1) << "LocalDomainResolverProxy::Start with id " << id_;
123     DCHECK(!started_);
124     host_->Send(new LocalDiscoveryMsg_ResolveLocalDomain(id_, domain_,
125                                                          address_family_));
126     started_ = true;
127   }
128
129  private:
130   scoped_refptr<ServiceDiscoveryHostClient> host_;
131   std::string domain_;
132   net::AddressFamily address_family_;
133   const uint64 id_;
134   bool started_;
135 };
136
137 ServiceDiscoveryHostClient::ServiceDiscoveryHostClient() : current_id_(0) {
138   callback_runner_ = base::MessageLoop::current()->message_loop_proxy();
139   io_runner_ = BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
140 }
141
142 ServiceDiscoveryHostClient::~ServiceDiscoveryHostClient() {
143   DCHECK(service_watcher_callbacks_.empty());
144   DCHECK(service_resolver_callbacks_.empty());
145   DCHECK(domain_resolver_callbacks_.empty());
146 }
147
148 scoped_ptr<ServiceWatcher> ServiceDiscoveryHostClient::CreateServiceWatcher(
149     const std::string& service_type,
150     const ServiceWatcher::UpdatedCallback& callback) {
151   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
152   return scoped_ptr<ServiceWatcher>(
153       new ServiceWatcherProxy(this, service_type, callback));
154 }
155
156 scoped_ptr<ServiceResolver> ServiceDiscoveryHostClient::CreateServiceResolver(
157     const std::string& service_name,
158     const ServiceResolver::ResolveCompleteCallback& callback) {
159   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
160   return scoped_ptr<ServiceResolver>(
161       new ServiceResolverProxy(this, service_name, callback));
162 }
163
164 scoped_ptr<LocalDomainResolver>
165 ServiceDiscoveryHostClient::CreateLocalDomainResolver(
166     const std::string& domain,
167     net::AddressFamily address_family,
168     const LocalDomainResolver::IPAddressCallback& callback) {
169   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
170   return scoped_ptr<LocalDomainResolver>(new LocalDomainResolverProxy(
171       this, domain, address_family, callback));
172 }
173
174 uint64 ServiceDiscoveryHostClient::RegisterWatcherCallback(
175     const ServiceWatcher::UpdatedCallback& callback) {
176   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
177   DCHECK(!ContainsKey(service_watcher_callbacks_, current_id_ + 1));
178   service_watcher_callbacks_[++current_id_] = callback;
179   return current_id_;
180 }
181
182 uint64 ServiceDiscoveryHostClient::RegisterResolverCallback(
183     const ServiceResolver::ResolveCompleteCallback& callback) {
184   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
185   DCHECK(!ContainsKey(service_resolver_callbacks_, current_id_ + 1));
186   service_resolver_callbacks_[++current_id_] = callback;
187   return current_id_;
188 }
189
190 uint64 ServiceDiscoveryHostClient::RegisterLocalDomainResolverCallback(
191     const LocalDomainResolver::IPAddressCallback& callback) {
192   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
193   DCHECK(!ContainsKey(domain_resolver_callbacks_, current_id_ + 1));
194   domain_resolver_callbacks_[++current_id_] = callback;
195   return current_id_;
196 }
197
198 void ServiceDiscoveryHostClient::UnregisterWatcherCallback(uint64 id) {
199   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
200   service_watcher_callbacks_.erase(id);
201 }
202
203 void ServiceDiscoveryHostClient::UnregisterResolverCallback(uint64 id) {
204   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
205   service_resolver_callbacks_.erase(id);
206 }
207
208 void ServiceDiscoveryHostClient::UnregisterLocalDomainResolverCallback(
209     uint64 id) {
210   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
211   domain_resolver_callbacks_.erase(id);
212 }
213
214 void ServiceDiscoveryHostClient::Start(
215     const base::Closure& error_callback) {
216   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
217   DCHECK(!utility_host_);
218   DCHECK(error_callback_.is_null());
219   error_callback_ = error_callback;
220   io_runner_->PostTask(
221       FROM_HERE,
222       base::Bind(&ServiceDiscoveryHostClient::StartOnIOThread, this));
223 }
224
225 void ServiceDiscoveryHostClient::Shutdown() {
226   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
227   io_runner_->PostTask(
228       FROM_HERE,
229       base::Bind(&ServiceDiscoveryHostClient::ShutdownOnIOThread, this));
230 }
231
232 void ServiceDiscoveryHostClient::StartOnIOThread() {
233   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
234   DCHECK(!utility_host_);
235   utility_host_ = UtilityProcessHost::Create(
236       this, base::MessageLoopProxy::current().get())->AsWeakPtr();
237   if (utility_host_) {
238     utility_host_->EnableZygote();
239     utility_host_->EnableMDns();
240     utility_host_->StartBatchMode();
241
242 #if defined(OS_POSIX)
243     base::FileDescriptor v4(net::CreatePlatformSocket(AF_INET, SOCK_DGRAM, 0),
244                             true);
245     base::FileDescriptor v6(net::CreatePlatformSocket(AF_INET6, SOCK_DGRAM, 0),
246                             true);
247     LOG_IF(ERROR, v4.fd == net::kInvalidSocket) << "Can't create IPv4 socket.";
248     LOG_IF(ERROR, v6.fd == net::kInvalidSocket) << "Can't create IPv6 socket.";
249     if (v4.fd == net::kInvalidSocket &&
250         v6.fd == net::kInvalidSocket) {
251       ShutdownOnIOThread();
252     } else {
253       utility_host_->Send(new LocalDiscoveryMsg_SetSockets(v4, v6));
254     }
255 #endif  // OS_POSIX
256   }
257 }
258
259 void ServiceDiscoveryHostClient::ShutdownOnIOThread() {
260   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
261   if (utility_host_) {
262     utility_host_->Send(new LocalDiscoveryMsg_ShutdownLocalDiscovery);
263     utility_host_->EndBatchMode();
264     utility_host_.reset();
265   }
266   error_callback_ = base::Closure();
267 }
268
269 void ServiceDiscoveryHostClient::Send(IPC::Message* msg) {
270   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
271   io_runner_->PostTask(
272       FROM_HERE,
273       base::Bind(&ServiceDiscoveryHostClient::SendOnIOThread, this, msg));
274 }
275
276 void ServiceDiscoveryHostClient::SendOnIOThread(IPC::Message* msg) {
277   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
278   if (utility_host_) {
279     utility_host_->Send(msg);
280   } else {
281     delete msg;
282   }
283 }
284
285 void ServiceDiscoveryHostClient::OnProcessCrashed(int exit_code) {
286   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
287   DCHECK(!utility_host_);
288   OnError();
289 }
290
291 bool ServiceDiscoveryHostClient::OnMessageReceived(
292     const IPC::Message& message) {
293   bool handled = true;
294   IPC_BEGIN_MESSAGE_MAP(ServiceDiscoveryHostClient, message)
295     IPC_MESSAGE_HANDLER(LocalDiscoveryHostMsg_Error, OnError)
296     IPC_MESSAGE_HANDLER(LocalDiscoveryHostMsg_WatcherCallback,
297                         OnWatcherCallback)
298     IPC_MESSAGE_HANDLER(LocalDiscoveryHostMsg_ResolverCallback,
299                         OnResolverCallback)
300     IPC_MESSAGE_HANDLER(LocalDiscoveryHostMsg_LocalDomainResolverCallback,
301                         OnLocalDomainResolverCallback)
302     IPC_MESSAGE_UNHANDLED(handled = false)
303   IPC_END_MESSAGE_MAP()
304   return handled;
305 }
306
307 void ServiceDiscoveryHostClient::InvalidateWatchers() {
308   WatcherCallbacks service_watcher_callbacks;
309   service_watcher_callbacks_.swap(service_watcher_callbacks);
310   service_resolver_callbacks_.clear();
311   domain_resolver_callbacks_.clear();
312
313   for (WatcherCallbacks::iterator i = service_watcher_callbacks.begin();
314        i != service_watcher_callbacks.end(); i++) {
315     if (!i->second.is_null()) {
316       i->second.Run(ServiceWatcher::UPDATE_INVALIDATED, "");
317     }
318   }
319 }
320
321 void ServiceDiscoveryHostClient::OnError() {
322   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
323   if (!error_callback_.is_null())
324     callback_runner_->PostTask(FROM_HERE, error_callback_);
325 }
326
327 void ServiceDiscoveryHostClient::OnWatcherCallback(
328     uint64 id,
329     ServiceWatcher::UpdateType update,
330     const std::string& service_name) {
331   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
332   callback_runner_->PostTask(
333       FROM_HERE,
334       base::Bind(&ServiceDiscoveryHostClient::RunWatcherCallback, this, id,
335                  update, service_name));
336 }
337
338 void ServiceDiscoveryHostClient::OnResolverCallback(
339     uint64 id,
340     ServiceResolver::RequestStatus status,
341     const ServiceDescription& description) {
342   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
343   callback_runner_->PostTask(
344       FROM_HERE,
345       base::Bind(&ServiceDiscoveryHostClient::RunResolverCallback, this, id,
346                  status, description));
347 }
348
349 void ServiceDiscoveryHostClient::OnLocalDomainResolverCallback(
350     uint64 id,
351     bool success,
352     const net::IPAddressNumber& ip_address_ipv4,
353     const net::IPAddressNumber& ip_address_ipv6) {
354   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
355   callback_runner_->PostTask(
356       FROM_HERE,
357       base::Bind(&ServiceDiscoveryHostClient::RunLocalDomainResolverCallback,
358                  this, id, success, ip_address_ipv4, ip_address_ipv6));
359 }
360
361 void ServiceDiscoveryHostClient::RunWatcherCallback(
362     uint64 id,
363     ServiceWatcher::UpdateType update,
364     const std::string& service_name) {
365   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
366   WatcherCallbacks::iterator it = service_watcher_callbacks_.find(id);
367   if (it != service_watcher_callbacks_.end() && !it->second.is_null())
368     it->second.Run(update, service_name);
369 }
370
371 void ServiceDiscoveryHostClient::RunResolverCallback(
372     uint64 id,
373     ServiceResolver::RequestStatus status,
374     const ServiceDescription& description) {
375   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
376   ResolverCallbacks::iterator it = service_resolver_callbacks_.find(id);
377   if (it != service_resolver_callbacks_.end() && !it->second.is_null())
378     it->second.Run(status, description);
379 }
380
381 void ServiceDiscoveryHostClient::RunLocalDomainResolverCallback(
382     uint64 id,
383     bool success,
384     const net::IPAddressNumber& ip_address_ipv4,
385     const net::IPAddressNumber& ip_address_ipv6) {
386   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
387   DomainResolverCallbacks::iterator it = domain_resolver_callbacks_.find(id);
388   if (it != domain_resolver_callbacks_.end() && !it->second.is_null())
389     it->second.Run(success, ip_address_ipv4, ip_address_ipv6);
390 }
391
392 }  // namespace local_discovery