Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / chrome / utility / local_discovery / service_discovery_message_handler.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/utility/local_discovery/service_discovery_message_handler.h"
6
7 #include <algorithm>
8
9 #include "base/lazy_instance.h"
10 #include "chrome/common/local_discovery/local_discovery_messages.h"
11 #include "chrome/common/local_discovery/service_discovery_client_impl.h"
12 #include "content/public/utility/utility_thread.h"
13 #include "net/socket/socket_descriptor.h"
14 #include "net/udp/datagram_server_socket.h"
15
16 namespace local_discovery {
17
18 namespace {
19
20 void ClosePlatformSocket(net::SocketDescriptor socket);
21
22 // Sets socket factory used by |net::CreatePlatformSocket|. Implemetation
23 // keeps single socket that will be returned to the first call to
24 // |net::CreatePlatformSocket| during object lifetime.
25 class ScopedSocketFactory : public net::PlatformSocketFactory {
26  public:
27   explicit ScopedSocketFactory(net::SocketDescriptor socket) : socket_(socket) {
28     net::PlatformSocketFactory::SetInstance(this);
29   }
30
31   ~ScopedSocketFactory() override {
32     net::PlatformSocketFactory::SetInstance(NULL);
33     ClosePlatformSocket(socket_);
34     socket_ = net::kInvalidSocket;
35   }
36
37   net::SocketDescriptor CreateSocket(int family,
38                                      int type,
39                                      int protocol) override {
40     DCHECK_EQ(type, SOCK_DGRAM);
41     DCHECK(family == AF_INET || family == AF_INET6);
42     net::SocketDescriptor result = net::kInvalidSocket;
43     std::swap(result, socket_);
44     return result;
45   }
46
47  private:
48   net::SocketDescriptor socket_;
49   DISALLOW_COPY_AND_ASSIGN(ScopedSocketFactory);
50 };
51
52 struct SocketInfo {
53   SocketInfo(net::SocketDescriptor socket,
54              net::AddressFamily address_family,
55              uint32 interface_index)
56       : socket(socket),
57         address_family(address_family),
58         interface_index(interface_index) {
59   }
60   net::SocketDescriptor socket;
61   net::AddressFamily address_family;
62   uint32 interface_index;
63 };
64
65 // Returns list of sockets preallocated before.
66 class PreCreatedMDnsSocketFactory : public net::MDnsSocketFactory {
67  public:
68   PreCreatedMDnsSocketFactory() {}
69   ~PreCreatedMDnsSocketFactory() override {
70     // Not empty if process exits too fast, before starting mDns code. If
71     // happened, destructors may crash accessing destroyed global objects.
72     sockets_.weak_clear();
73   }
74
75   // net::MDnsSocketFactory implementation:
76   void CreateSockets(
77       ScopedVector<net::DatagramServerSocket>* sockets) override {
78     sockets->swap(sockets_);
79     Reset();
80   }
81
82   void AddSocket(const SocketInfo& socket_info) {
83     // Takes ownership of socket_info.socket;
84     ScopedSocketFactory platform_factory(socket_info.socket);
85     scoped_ptr<net::DatagramServerSocket> socket(
86         net::CreateAndBindMDnsSocket(socket_info.address_family,
87                                      socket_info.interface_index));
88     if (socket) {
89       socket->DetachFromThread();
90       sockets_.push_back(socket.release());
91     }
92   }
93
94   void Reset() {
95     sockets_.clear();
96   }
97
98  private:
99   ScopedVector<net::DatagramServerSocket> sockets_;
100
101   DISALLOW_COPY_AND_ASSIGN(PreCreatedMDnsSocketFactory);
102 };
103
104 base::LazyInstance<PreCreatedMDnsSocketFactory>
105     g_local_discovery_socket_factory = LAZY_INSTANCE_INITIALIZER;
106
107 #if defined(OS_WIN)
108
109 void ClosePlatformSocket(net::SocketDescriptor socket) {
110   ::closesocket(socket);
111 }
112
113 void StaticInitializeSocketFactory() {
114   net::InterfaceIndexFamilyList interfaces(net::GetMDnsInterfacesToBind());
115   for (size_t i = 0; i < interfaces.size(); ++i) {
116     DCHECK(interfaces[i].second == net::ADDRESS_FAMILY_IPV4 ||
117            interfaces[i].second == net::ADDRESS_FAMILY_IPV6);
118     net::SocketDescriptor descriptor =
119         net::CreatePlatformSocket(
120             net::ConvertAddressFamily(interfaces[i].second), SOCK_DGRAM,
121                                       IPPROTO_UDP);
122     g_local_discovery_socket_factory.Get().AddSocket(
123         SocketInfo(descriptor, interfaces[i].second, interfaces[i].first));
124   }
125 }
126
127 #else  // OS_WIN
128
129 void ClosePlatformSocket(net::SocketDescriptor socket) {
130   ::close(socket);
131 }
132
133 void StaticInitializeSocketFactory() {
134 }
135
136 #endif  // OS_WIN
137
138 void SendHostMessageOnUtilityThread(IPC::Message* msg) {
139   content::UtilityThread::Get()->Send(msg);
140 }
141
142 std::string WatcherUpdateToString(ServiceWatcher::UpdateType update) {
143   switch (update) {
144     case ServiceWatcher::UPDATE_ADDED:
145       return "UPDATE_ADDED";
146     case ServiceWatcher::UPDATE_CHANGED:
147       return "UPDATE_CHANGED";
148     case ServiceWatcher::UPDATE_REMOVED:
149       return "UPDATE_REMOVED";
150     case ServiceWatcher::UPDATE_INVALIDATED:
151       return "UPDATE_INVALIDATED";
152   }
153   return "Unknown Update";
154 }
155
156 std::string ResolverStatusToString(ServiceResolver::RequestStatus status) {
157   switch (status) {
158     case ServiceResolver::STATUS_SUCCESS:
159       return "STATUS_SUCESS";
160     case ServiceResolver::STATUS_REQUEST_TIMEOUT:
161       return "STATUS_REQUEST_TIMEOUT";
162     case ServiceResolver::STATUS_KNOWN_NONEXISTENT:
163       return "STATUS_KNOWN_NONEXISTENT";
164   }
165   return "Unknown Status";
166 }
167
168 }  // namespace
169
170 ServiceDiscoveryMessageHandler::ServiceDiscoveryMessageHandler() {
171 }
172
173 ServiceDiscoveryMessageHandler::~ServiceDiscoveryMessageHandler() {
174   DCHECK(!discovery_thread_);
175 }
176
177 void ServiceDiscoveryMessageHandler::PreSandboxStartup() {
178   StaticInitializeSocketFactory();
179 }
180
181 void ServiceDiscoveryMessageHandler::InitializeMdns() {
182   if (service_discovery_client_ || mdns_client_)
183     return;
184
185   mdns_client_ = net::MDnsClient::CreateDefault();
186   bool result =
187       mdns_client_->StartListening(g_local_discovery_socket_factory.Pointer());
188   // Close unused sockets.
189   g_local_discovery_socket_factory.Get().Reset();
190   if (!result) {
191     VLOG(1) << "Failed to start MDnsClient";
192     Send(new LocalDiscoveryHostMsg_Error());
193     return;
194   }
195
196   service_discovery_client_.reset(
197       new local_discovery::ServiceDiscoveryClientImpl(mdns_client_.get()));
198 }
199
200 bool ServiceDiscoveryMessageHandler::InitializeThread() {
201   if (discovery_task_runner_.get())
202     return true;
203   if (discovery_thread_)
204     return false;
205   utility_task_runner_ = base::MessageLoop::current()->message_loop_proxy();
206   discovery_thread_.reset(new base::Thread("ServiceDiscoveryThread"));
207   base::Thread::Options thread_options(base::MessageLoop::TYPE_IO, 0);
208   if (discovery_thread_->StartWithOptions(thread_options)) {
209     discovery_task_runner_ = discovery_thread_->message_loop_proxy();
210     discovery_task_runner_->PostTask(FROM_HERE,
211         base::Bind(&ServiceDiscoveryMessageHandler::InitializeMdns,
212                     base::Unretained(this)));
213   }
214   return discovery_task_runner_.get() != NULL;
215 }
216
217 bool ServiceDiscoveryMessageHandler::OnMessageReceived(
218     const IPC::Message& message) {
219   bool handled = true;
220   IPC_BEGIN_MESSAGE_MAP(ServiceDiscoveryMessageHandler, message)
221 #if defined(OS_POSIX)
222     IPC_MESSAGE_HANDLER(LocalDiscoveryMsg_SetSockets, OnSetSockets)
223 #endif  // OS_POSIX
224     IPC_MESSAGE_HANDLER(LocalDiscoveryMsg_StartWatcher, OnStartWatcher)
225     IPC_MESSAGE_HANDLER(LocalDiscoveryMsg_DiscoverServices, OnDiscoverServices)
226     IPC_MESSAGE_HANDLER(LocalDiscoveryMsg_SetActivelyRefreshServices,
227                         OnSetActivelyRefreshServices)
228     IPC_MESSAGE_HANDLER(LocalDiscoveryMsg_DestroyWatcher, OnDestroyWatcher)
229     IPC_MESSAGE_HANDLER(LocalDiscoveryMsg_ResolveService, OnResolveService)
230     IPC_MESSAGE_HANDLER(LocalDiscoveryMsg_DestroyResolver, OnDestroyResolver)
231     IPC_MESSAGE_HANDLER(LocalDiscoveryMsg_ResolveLocalDomain,
232                         OnResolveLocalDomain)
233     IPC_MESSAGE_HANDLER(LocalDiscoveryMsg_DestroyLocalDomainResolver,
234                         OnDestroyLocalDomainResolver)
235     IPC_MESSAGE_HANDLER(LocalDiscoveryMsg_ShutdownLocalDiscovery,
236                         ShutdownLocalDiscovery)
237     IPC_MESSAGE_UNHANDLED(handled = false)
238   IPC_END_MESSAGE_MAP()
239   return handled;
240 }
241
242 void ServiceDiscoveryMessageHandler::PostTask(
243     const tracked_objects::Location& from_here,
244     const base::Closure& task) {
245   if (!InitializeThread())
246     return;
247   discovery_task_runner_->PostTask(from_here, task);
248 }
249
250 #if defined(OS_POSIX)
251 void ServiceDiscoveryMessageHandler::OnSetSockets(
252     const std::vector<LocalDiscoveryMsg_SocketInfo>& sockets) {
253   for (size_t i = 0; i < sockets.size(); ++i) {
254     g_local_discovery_socket_factory.Get().AddSocket(
255         SocketInfo(sockets[i].descriptor.fd, sockets[i].address_family,
256                    sockets[i].interface_index));
257   }
258 }
259 #endif  // OS_POSIX
260
261 void ServiceDiscoveryMessageHandler::OnStartWatcher(
262     uint64 id,
263     const std::string& service_type) {
264   PostTask(FROM_HERE,
265            base::Bind(&ServiceDiscoveryMessageHandler::StartWatcher,
266                       base::Unretained(this), id, service_type));
267 }
268
269 void ServiceDiscoveryMessageHandler::OnDiscoverServices(uint64 id,
270                                                         bool force_update) {
271   PostTask(FROM_HERE,
272            base::Bind(&ServiceDiscoveryMessageHandler::DiscoverServices,
273                       base::Unretained(this), id, force_update));
274 }
275
276 void ServiceDiscoveryMessageHandler::OnSetActivelyRefreshServices(
277     uint64 id, bool actively_refresh_services) {
278   PostTask(FROM_HERE,
279            base::Bind(
280                &ServiceDiscoveryMessageHandler::SetActivelyRefreshServices,
281                base::Unretained(this), id, actively_refresh_services));
282 }
283
284 void ServiceDiscoveryMessageHandler::OnDestroyWatcher(uint64 id) {
285   PostTask(FROM_HERE,
286            base::Bind(&ServiceDiscoveryMessageHandler::DestroyWatcher,
287                       base::Unretained(this), id));
288 }
289
290 void ServiceDiscoveryMessageHandler::OnResolveService(
291     uint64 id,
292     const std::string& service_name) {
293   PostTask(FROM_HERE,
294            base::Bind(&ServiceDiscoveryMessageHandler::ResolveService,
295                       base::Unretained(this), id, service_name));
296 }
297
298 void ServiceDiscoveryMessageHandler::OnDestroyResolver(uint64 id) {
299   PostTask(FROM_HERE,
300            base::Bind(&ServiceDiscoveryMessageHandler::DestroyResolver,
301                       base::Unretained(this), id));
302 }
303
304 void ServiceDiscoveryMessageHandler::OnResolveLocalDomain(
305     uint64 id, const std::string& domain,
306     net::AddressFamily address_family) {
307     PostTask(FROM_HERE,
308            base::Bind(&ServiceDiscoveryMessageHandler::ResolveLocalDomain,
309                       base::Unretained(this), id, domain, address_family));
310 }
311
312 void ServiceDiscoveryMessageHandler::OnDestroyLocalDomainResolver(uint64 id) {
313   PostTask(FROM_HERE,
314            base::Bind(
315                &ServiceDiscoveryMessageHandler::DestroyLocalDomainResolver,
316                base::Unretained(this), id));
317 }
318
319 void ServiceDiscoveryMessageHandler::StartWatcher(
320     uint64 id,
321     const std::string& service_type) {
322   VLOG(1) << "StartWatcher, id=" << id << ", type=" << service_type;
323   if (!service_discovery_client_)
324     return;
325   DCHECK(!ContainsKey(service_watchers_, id));
326   scoped_ptr<ServiceWatcher> watcher(
327       service_discovery_client_->CreateServiceWatcher(
328           service_type,
329           base::Bind(&ServiceDiscoveryMessageHandler::OnServiceUpdated,
330                      base::Unretained(this), id)));
331   watcher->Start();
332   service_watchers_[id].reset(watcher.release());
333 }
334
335 void ServiceDiscoveryMessageHandler::DiscoverServices(uint64 id,
336                                                       bool force_update) {
337   VLOG(1) << "DiscoverServices, id=" << id;
338   if (!service_discovery_client_)
339     return;
340   DCHECK(ContainsKey(service_watchers_, id));
341   service_watchers_[id]->DiscoverNewServices(force_update);
342 }
343
344 void ServiceDiscoveryMessageHandler::SetActivelyRefreshServices(
345     uint64 id,
346     bool actively_refresh_services) {
347   VLOG(1) << "ActivelyRefreshServices, id=" << id;
348   if (!service_discovery_client_)
349     return;
350   DCHECK(ContainsKey(service_watchers_, id));
351   service_watchers_[id]->SetActivelyRefreshServices(actively_refresh_services);
352 }
353
354 void ServiceDiscoveryMessageHandler::DestroyWatcher(uint64 id) {
355   VLOG(1) << "DestoryWatcher, id=" << id;
356   if (!service_discovery_client_)
357     return;
358   service_watchers_.erase(id);
359 }
360
361 void ServiceDiscoveryMessageHandler::ResolveService(
362     uint64 id,
363     const std::string& service_name) {
364   VLOG(1) << "ResolveService, id=" << id << ", name=" << service_name;
365   if (!service_discovery_client_)
366     return;
367   DCHECK(!ContainsKey(service_resolvers_, id));
368   scoped_ptr<ServiceResolver> resolver(
369       service_discovery_client_->CreateServiceResolver(
370           service_name,
371           base::Bind(&ServiceDiscoveryMessageHandler::OnServiceResolved,
372                      base::Unretained(this), id)));
373   resolver->StartResolving();
374   service_resolvers_[id].reset(resolver.release());
375 }
376
377 void ServiceDiscoveryMessageHandler::DestroyResolver(uint64 id) {
378   VLOG(1) << "DestroyResolver, id=" << id;
379   if (!service_discovery_client_)
380     return;
381   service_resolvers_.erase(id);
382 }
383
384 void ServiceDiscoveryMessageHandler::ResolveLocalDomain(
385     uint64 id,
386     const std::string& domain,
387     net::AddressFamily address_family) {
388   VLOG(1) << "ResolveLocalDomain, id=" << id << ", domain=" << domain;
389   if (!service_discovery_client_)
390     return;
391   DCHECK(!ContainsKey(local_domain_resolvers_, id));
392   scoped_ptr<LocalDomainResolver> resolver(
393       service_discovery_client_->CreateLocalDomainResolver(
394           domain, address_family,
395           base::Bind(&ServiceDiscoveryMessageHandler::OnLocalDomainResolved,
396                      base::Unretained(this), id)));
397   resolver->Start();
398   local_domain_resolvers_[id].reset(resolver.release());
399 }
400
401 void ServiceDiscoveryMessageHandler::DestroyLocalDomainResolver(uint64 id) {
402   VLOG(1) << "DestroyLocalDomainResolver, id=" << id;
403   if (!service_discovery_client_)
404     return;
405   local_domain_resolvers_.erase(id);
406 }
407
408 void ServiceDiscoveryMessageHandler::ShutdownLocalDiscovery() {
409   if (!discovery_task_runner_.get())
410     return;
411
412   discovery_task_runner_->PostTask(
413       FROM_HERE,
414       base::Bind(&ServiceDiscoveryMessageHandler::ShutdownOnIOThread,
415                  base::Unretained(this)));
416
417   // This will wait for message loop to drain, so ShutdownOnIOThread will
418   // definitely be called.
419   discovery_thread_.reset();
420 }
421
422 void ServiceDiscoveryMessageHandler::ShutdownOnIOThread() {
423   VLOG(1) << "ShutdownLocalDiscovery";
424   service_watchers_.clear();
425   service_resolvers_.clear();
426   local_domain_resolvers_.clear();
427   service_discovery_client_.reset();
428   mdns_client_.reset();
429 }
430
431 void ServiceDiscoveryMessageHandler::OnServiceUpdated(
432     uint64 id,
433     ServiceWatcher::UpdateType update,
434     const std::string& name) {
435   VLOG(1) << "OnServiceUpdated, id=" << id
436           << ", status=" << WatcherUpdateToString(update) << ", name=" << name;
437   DCHECK(service_discovery_client_);
438
439   Send(new LocalDiscoveryHostMsg_WatcherCallback(id, update, name));
440 }
441
442 void ServiceDiscoveryMessageHandler::OnServiceResolved(
443     uint64 id,
444     ServiceResolver::RequestStatus status,
445     const ServiceDescription& description) {
446   VLOG(1) << "OnServiceResolved, id=" << id
447           << ", status=" << ResolverStatusToString(status)
448           << ", name=" << description.service_name;
449
450   DCHECK(service_discovery_client_);
451   Send(new LocalDiscoveryHostMsg_ResolverCallback(id, status, description));
452 }
453
454 void ServiceDiscoveryMessageHandler::OnLocalDomainResolved(
455     uint64 id,
456     bool success,
457     const net::IPAddressNumber& address_ipv4,
458     const net::IPAddressNumber& address_ipv6) {
459   VLOG(1) << "OnLocalDomainResolved, id=" << id
460           << ", IPv4=" << (address_ipv4.empty() ? "" :
461                            net::IPAddressToString(address_ipv4))
462           << ", IPv6=" << (address_ipv6.empty() ? "" :
463                            net::IPAddressToString(address_ipv6));
464
465   DCHECK(service_discovery_client_);
466   Send(new LocalDiscoveryHostMsg_LocalDomainResolverCallback(
467           id, success, address_ipv4, address_ipv6));
468 }
469
470 void ServiceDiscoveryMessageHandler::Send(IPC::Message* msg) {
471   utility_task_runner_->PostTask(FROM_HERE,
472                                  base::Bind(&SendHostMessageOnUtilityThread,
473                                             msg));
474 }
475
476 }  // namespace local_discovery