Add ICU message format support
[chromium-blink-merge.git] / chrome / browser / local_discovery / service_discovery_host_client.cc
blob9acbb9c3b74b90a538751fc0361169fc060ff711
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.
5 #include "chrome/browser/local_discovery/service_discovery_host_client.h"
7 #include "base/location.h"
8 #include "base/single_thread_task_runner.h"
9 #include "base/thread_task_runner_handle.h"
10 #include "chrome/common/local_discovery/local_discovery_messages.h"
11 #include "chrome/grit/generated_resources.h"
12 #include "content/public/browser/browser_thread.h"
13 #include "content/public/browser/utility_process_host.h"
14 #include "net/dns/mdns_client.h"
15 #include "net/socket/socket_descriptor.h"
16 #include "ui/base/l10n/l10n_util.h"
18 #if defined(OS_POSIX)
19 #include <netinet/in.h>
20 #include "base/file_descriptor_posix.h"
21 #endif // OS_POSIX
23 namespace local_discovery {
25 using content::BrowserThread;
26 using content::UtilityProcessHost;
28 namespace {
30 #if defined(OS_POSIX)
31 SocketInfoList GetSocketsOnFileThread() {
32 net::InterfaceIndexFamilyList interfaces(net::GetMDnsInterfacesToBind());
33 SocketInfoList sockets;
34 for (size_t i = 0; i < interfaces.size(); ++i) {
35 DCHECK(interfaces[i].second == net::ADDRESS_FAMILY_IPV4 ||
36 interfaces[i].second == net::ADDRESS_FAMILY_IPV6);
37 base::FileDescriptor socket_descriptor(
38 net::CreatePlatformSocket(
39 net::ConvertAddressFamily(interfaces[i].second), SOCK_DGRAM,
40 IPPROTO_UDP),
41 true);
42 LOG_IF(ERROR, socket_descriptor.fd == net::kInvalidSocket)
43 << "Can't create socket, family=" << interfaces[i].second;
44 if (socket_descriptor.fd != net::kInvalidSocket) {
45 LocalDiscoveryMsg_SocketInfo socket;
46 socket.descriptor = socket_descriptor;
47 socket.interface_index = interfaces[i].first;
48 socket.address_family = interfaces[i].second;
49 sockets.push_back(socket);
53 return sockets;
55 #endif // OS_POSIX
57 } // namespace
59 class ServiceDiscoveryHostClient::ServiceWatcherProxy : public ServiceWatcher {
60 public:
61 ServiceWatcherProxy(ServiceDiscoveryHostClient* host,
62 const std::string& service_type,
63 const ServiceWatcher::UpdatedCallback& callback)
64 : host_(host),
65 service_type_(service_type),
66 id_(host_->RegisterWatcherCallback(callback)),
67 started_(false) {
70 ~ServiceWatcherProxy() override {
71 DVLOG(1) << "~ServiceWatcherProxy with id " << id_;
72 host_->UnregisterWatcherCallback(id_);
73 if (started_)
74 host_->Send(new LocalDiscoveryMsg_DestroyWatcher(id_));
77 void Start() override {
78 DVLOG(1) << "ServiceWatcher::Start with id " << id_;
79 DCHECK(!started_);
80 host_->Send(new LocalDiscoveryMsg_StartWatcher(id_, service_type_));
81 started_ = true;
84 void DiscoverNewServices(bool force_update) override {
85 DVLOG(1) << "ServiceWatcher::DiscoverNewServices with id " << id_;
86 DCHECK(started_);
87 host_->Send(new LocalDiscoveryMsg_DiscoverServices(id_, force_update));
90 void SetActivelyRefreshServices(bool actively_refresh_services) override {
91 DVLOG(1) << "ServiceWatcher::SetActivelyRefreshServices with id " << id_;
92 DCHECK(started_);
93 host_->Send(new LocalDiscoveryMsg_SetActivelyRefreshServices(
94 id_, actively_refresh_services));
97 std::string GetServiceType() const override { return service_type_; }
99 private:
100 scoped_refptr<ServiceDiscoveryHostClient> host_;
101 const std::string service_type_;
102 const uint64 id_;
103 bool started_;
106 class ServiceDiscoveryHostClient::ServiceResolverProxy
107 : public ServiceResolver {
108 public:
109 ServiceResolverProxy(ServiceDiscoveryHostClient* host,
110 const std::string& service_name,
111 const ServiceResolver::ResolveCompleteCallback& callback)
112 : host_(host),
113 service_name_(service_name),
114 id_(host->RegisterResolverCallback(callback)),
115 started_(false) {
118 ~ServiceResolverProxy() override {
119 DVLOG(1) << "~ServiceResolverProxy with id " << id_;
120 host_->UnregisterResolverCallback(id_);
121 if (started_)
122 host_->Send(new LocalDiscoveryMsg_DestroyResolver(id_));
125 void StartResolving() override {
126 DVLOG(1) << "ServiceResolverProxy::StartResolving with id " << id_;
127 DCHECK(!started_);
128 host_->Send(new LocalDiscoveryMsg_ResolveService(id_, service_name_));
129 started_ = true;
132 std::string GetName() const override { return service_name_; }
134 private:
135 scoped_refptr<ServiceDiscoveryHostClient> host_;
136 const std::string service_name_;
137 const uint64 id_;
138 bool started_;
141 class ServiceDiscoveryHostClient::LocalDomainResolverProxy
142 : public LocalDomainResolver {
143 public:
144 LocalDomainResolverProxy(ServiceDiscoveryHostClient* host,
145 const std::string& domain,
146 net::AddressFamily address_family,
147 const LocalDomainResolver::IPAddressCallback& callback)
148 : host_(host),
149 domain_(domain),
150 address_family_(address_family),
151 id_(host->RegisterLocalDomainResolverCallback(callback)),
152 started_(false) {
155 ~LocalDomainResolverProxy() override {
156 DVLOG(1) << "~LocalDomainResolverProxy with id " << id_;
157 host_->UnregisterLocalDomainResolverCallback(id_);
158 if (started_)
159 host_->Send(new LocalDiscoveryMsg_DestroyLocalDomainResolver(id_));
162 void Start() override {
163 DVLOG(1) << "LocalDomainResolverProxy::Start with id " << id_;
164 DCHECK(!started_);
165 host_->Send(new LocalDiscoveryMsg_ResolveLocalDomain(id_, domain_,
166 address_family_));
167 started_ = true;
170 private:
171 scoped_refptr<ServiceDiscoveryHostClient> host_;
172 std::string domain_;
173 net::AddressFamily address_family_;
174 const uint64 id_;
175 bool started_;
178 ServiceDiscoveryHostClient::ServiceDiscoveryHostClient() : current_id_(0) {
179 callback_runner_ = base::MessageLoop::current()->task_runner();
180 io_runner_ = BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
183 ServiceDiscoveryHostClient::~ServiceDiscoveryHostClient() {
184 DCHECK(service_watcher_callbacks_.empty());
185 DCHECK(service_resolver_callbacks_.empty());
186 DCHECK(domain_resolver_callbacks_.empty());
189 scoped_ptr<ServiceWatcher> ServiceDiscoveryHostClient::CreateServiceWatcher(
190 const std::string& service_type,
191 const ServiceWatcher::UpdatedCallback& callback) {
192 DCHECK_CURRENTLY_ON(BrowserThread::UI);
193 return scoped_ptr<ServiceWatcher>(
194 new ServiceWatcherProxy(this, service_type, callback));
197 scoped_ptr<ServiceResolver> ServiceDiscoveryHostClient::CreateServiceResolver(
198 const std::string& service_name,
199 const ServiceResolver::ResolveCompleteCallback& callback) {
200 DCHECK_CURRENTLY_ON(BrowserThread::UI);
201 return scoped_ptr<ServiceResolver>(
202 new ServiceResolverProxy(this, service_name, callback));
205 scoped_ptr<LocalDomainResolver>
206 ServiceDiscoveryHostClient::CreateLocalDomainResolver(
207 const std::string& domain,
208 net::AddressFamily address_family,
209 const LocalDomainResolver::IPAddressCallback& callback) {
210 DCHECK_CURRENTLY_ON(BrowserThread::UI);
211 return scoped_ptr<LocalDomainResolver>(new LocalDomainResolverProxy(
212 this, domain, address_family, callback));
215 uint64 ServiceDiscoveryHostClient::RegisterWatcherCallback(
216 const ServiceWatcher::UpdatedCallback& callback) {
217 DCHECK_CURRENTLY_ON(BrowserThread::UI);
218 DCHECK(!ContainsKey(service_watcher_callbacks_, current_id_ + 1));
219 service_watcher_callbacks_[++current_id_] = callback;
220 return current_id_;
223 uint64 ServiceDiscoveryHostClient::RegisterResolverCallback(
224 const ServiceResolver::ResolveCompleteCallback& callback) {
225 DCHECK_CURRENTLY_ON(BrowserThread::UI);
226 DCHECK(!ContainsKey(service_resolver_callbacks_, current_id_ + 1));
227 service_resolver_callbacks_[++current_id_] = callback;
228 return current_id_;
231 uint64 ServiceDiscoveryHostClient::RegisterLocalDomainResolverCallback(
232 const LocalDomainResolver::IPAddressCallback& callback) {
233 DCHECK_CURRENTLY_ON(BrowserThread::UI);
234 DCHECK(!ContainsKey(domain_resolver_callbacks_, current_id_ + 1));
235 domain_resolver_callbacks_[++current_id_] = callback;
236 return current_id_;
239 void ServiceDiscoveryHostClient::UnregisterWatcherCallback(uint64 id) {
240 DCHECK_CURRENTLY_ON(BrowserThread::UI);
241 service_watcher_callbacks_.erase(id);
244 void ServiceDiscoveryHostClient::UnregisterResolverCallback(uint64 id) {
245 DCHECK_CURRENTLY_ON(BrowserThread::UI);
246 service_resolver_callbacks_.erase(id);
249 void ServiceDiscoveryHostClient::UnregisterLocalDomainResolverCallback(
250 uint64 id) {
251 DCHECK_CURRENTLY_ON(BrowserThread::UI);
252 domain_resolver_callbacks_.erase(id);
255 void ServiceDiscoveryHostClient::Start(
256 const base::Closure& error_callback) {
257 DCHECK_CURRENTLY_ON(BrowserThread::UI);
258 DCHECK(!utility_host_);
259 DCHECK(error_callback_.is_null());
260 error_callback_ = error_callback;
261 io_runner_->PostTask(
262 FROM_HERE,
263 base::Bind(&ServiceDiscoveryHostClient::StartOnIOThread, this));
266 void ServiceDiscoveryHostClient::Shutdown() {
267 DCHECK_CURRENTLY_ON(BrowserThread::UI);
268 io_runner_->PostTask(
269 FROM_HERE,
270 base::Bind(&ServiceDiscoveryHostClient::ShutdownOnIOThread, this));
273 #if defined(OS_POSIX)
275 void ServiceDiscoveryHostClient::StartOnIOThread() {
276 DCHECK_CURRENTLY_ON(BrowserThread::IO);
277 DCHECK(!utility_host_);
278 BrowserThread::PostTaskAndReplyWithResult(
279 BrowserThread::FILE,
280 FROM_HERE,
281 base::Bind(&GetSocketsOnFileThread),
282 base::Bind(&ServiceDiscoveryHostClient::OnSocketsReady, this));
285 void ServiceDiscoveryHostClient::OnSocketsReady(const SocketInfoList& sockets) {
286 DCHECK_CURRENTLY_ON(BrowserThread::IO);
287 DCHECK(!utility_host_);
288 utility_host_ =
289 UtilityProcessHost::Create(
290 this, base::ThreadTaskRunnerHandle::Get().get())->AsWeakPtr();
291 utility_host_->SetName(l10n_util::GetStringUTF16(
292 IDS_UTILITY_PROCESS_SERVICE_DISCOVERY_HANDLER_NAME));
293 utility_host_->EnableMDns();
294 utility_host_->StartBatchMode();
295 if (sockets.empty()) {
296 ShutdownOnIOThread();
297 return;
299 utility_host_->Send(new LocalDiscoveryMsg_SetSockets(sockets));
300 // Send messages for requests made during network enumeration.
301 for (size_t i = 0; i < delayed_messages_.size(); ++i)
302 utility_host_->Send(delayed_messages_[i]);
303 delayed_messages_.weak_clear();
306 #else // OS_POSIX
308 void ServiceDiscoveryHostClient::StartOnIOThread() {
309 DCHECK_CURRENTLY_ON(BrowserThread::IO);
310 DCHECK(!utility_host_);
311 utility_host_ =
312 UtilityProcessHost::Create(
313 this, base::ThreadTaskRunnerHandle::Get().get())->AsWeakPtr();
314 utility_host_->SetName(l10n_util::GetStringUTF16(
315 IDS_UTILITY_PROCESS_SERVICE_DISCOVERY_HANDLER_NAME));
316 utility_host_->EnableMDns();
317 utility_host_->StartBatchMode();
318 // Windows does not enumerate networks here.
319 DCHECK(delayed_messages_.empty());
322 #endif // OS_POSIX
324 void ServiceDiscoveryHostClient::ShutdownOnIOThread() {
325 DCHECK_CURRENTLY_ON(BrowserThread::IO);
326 if (utility_host_) {
327 utility_host_->Send(new LocalDiscoveryMsg_ShutdownLocalDiscovery);
328 utility_host_->EndBatchMode();
329 utility_host_.reset();
331 error_callback_ = base::Closure();
334 void ServiceDiscoveryHostClient::Send(IPC::Message* msg) {
335 DCHECK_CURRENTLY_ON(BrowserThread::UI);
336 io_runner_->PostTask(
337 FROM_HERE,
338 base::Bind(&ServiceDiscoveryHostClient::SendOnIOThread, this, msg));
341 void ServiceDiscoveryHostClient::SendOnIOThread(IPC::Message* msg) {
342 DCHECK_CURRENTLY_ON(BrowserThread::IO);
343 if (utility_host_) {
344 utility_host_->Send(msg);
345 } else {
346 delayed_messages_.push_back(msg);
350 void ServiceDiscoveryHostClient::OnProcessCrashed(int exit_code) {
351 DCHECK_CURRENTLY_ON(BrowserThread::IO);
352 DCHECK(!utility_host_);
353 OnError();
356 bool ServiceDiscoveryHostClient::OnMessageReceived(
357 const IPC::Message& message) {
358 bool handled = true;
359 IPC_BEGIN_MESSAGE_MAP(ServiceDiscoveryHostClient, message)
360 IPC_MESSAGE_HANDLER(LocalDiscoveryHostMsg_Error, OnError)
361 IPC_MESSAGE_HANDLER(LocalDiscoveryHostMsg_WatcherCallback,
362 OnWatcherCallback)
363 IPC_MESSAGE_HANDLER(LocalDiscoveryHostMsg_ResolverCallback,
364 OnResolverCallback)
365 IPC_MESSAGE_HANDLER(LocalDiscoveryHostMsg_LocalDomainResolverCallback,
366 OnLocalDomainResolverCallback)
367 IPC_MESSAGE_UNHANDLED(handled = false)
368 IPC_END_MESSAGE_MAP()
369 return handled;
372 void ServiceDiscoveryHostClient::InvalidateWatchers() {
373 WatcherCallbacks service_watcher_callbacks;
374 service_watcher_callbacks_.swap(service_watcher_callbacks);
375 service_resolver_callbacks_.clear();
376 domain_resolver_callbacks_.clear();
378 for (WatcherCallbacks::iterator i = service_watcher_callbacks.begin();
379 i != service_watcher_callbacks.end(); i++) {
380 if (!i->second.is_null()) {
381 i->second.Run(ServiceWatcher::UPDATE_INVALIDATED, "");
386 void ServiceDiscoveryHostClient::OnError() {
387 DCHECK_CURRENTLY_ON(BrowserThread::IO);
388 if (!error_callback_.is_null())
389 callback_runner_->PostTask(FROM_HERE, error_callback_);
392 void ServiceDiscoveryHostClient::OnWatcherCallback(
393 uint64 id,
394 ServiceWatcher::UpdateType update,
395 const std::string& service_name) {
396 DCHECK_CURRENTLY_ON(BrowserThread::IO);
397 callback_runner_->PostTask(
398 FROM_HERE,
399 base::Bind(&ServiceDiscoveryHostClient::RunWatcherCallback, this, id,
400 update, service_name));
403 void ServiceDiscoveryHostClient::OnResolverCallback(
404 uint64 id,
405 ServiceResolver::RequestStatus status,
406 const ServiceDescription& description) {
407 DCHECK_CURRENTLY_ON(BrowserThread::IO);
408 callback_runner_->PostTask(
409 FROM_HERE,
410 base::Bind(&ServiceDiscoveryHostClient::RunResolverCallback, this, id,
411 status, description));
414 void ServiceDiscoveryHostClient::OnLocalDomainResolverCallback(
415 uint64 id,
416 bool success,
417 const net::IPAddressNumber& ip_address_ipv4,
418 const net::IPAddressNumber& ip_address_ipv6) {
419 DCHECK_CURRENTLY_ON(BrowserThread::IO);
420 callback_runner_->PostTask(
421 FROM_HERE,
422 base::Bind(&ServiceDiscoveryHostClient::RunLocalDomainResolverCallback,
423 this, id, success, ip_address_ipv4, ip_address_ipv6));
426 void ServiceDiscoveryHostClient::RunWatcherCallback(
427 uint64 id,
428 ServiceWatcher::UpdateType update,
429 const std::string& service_name) {
430 DCHECK_CURRENTLY_ON(BrowserThread::UI);
431 WatcherCallbacks::iterator it = service_watcher_callbacks_.find(id);
432 if (it != service_watcher_callbacks_.end() && !it->second.is_null())
433 it->second.Run(update, service_name);
436 void ServiceDiscoveryHostClient::RunResolverCallback(
437 uint64 id,
438 ServiceResolver::RequestStatus status,
439 const ServiceDescription& description) {
440 DCHECK_CURRENTLY_ON(BrowserThread::UI);
441 ResolverCallbacks::iterator it = service_resolver_callbacks_.find(id);
442 if (it != service_resolver_callbacks_.end() && !it->second.is_null())
443 it->second.Run(status, description);
446 void ServiceDiscoveryHostClient::RunLocalDomainResolverCallback(
447 uint64 id,
448 bool success,
449 const net::IPAddressNumber& ip_address_ipv4,
450 const net::IPAddressNumber& ip_address_ipv6) {
451 DCHECK_CURRENTLY_ON(BrowserThread::UI);
452 DomainResolverCallbacks::iterator it = domain_resolver_callbacks_.find(id);
453 if (it != domain_resolver_callbacks_.end() && !it->second.is_null())
454 it->second.Run(success, ip_address_ipv4, ip_address_ipv6);
457 } // namespace local_discovery