Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / local_discovery / service_discovery_host_client.cc
blob06f491af6aa8681a2626db7fd6c0c0e3f6720b24
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 "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/dns/mdns_client.h"
11 #include "net/socket/socket_descriptor.h"
13 #if defined(OS_POSIX)
14 #include <netinet/in.h>
15 #include "base/file_descriptor_posix.h"
16 #endif // OS_POSIX
18 namespace local_discovery {
20 using content::BrowserThread;
21 using content::UtilityProcessHost;
23 namespace {
25 #if defined(OS_POSIX)
26 SocketInfoList GetSocketsOnFileThread() {
27 net::InterfaceIndexFamilyList interfaces(net::GetMDnsInterfacesToBind());
28 SocketInfoList sockets;
29 for (size_t i = 0; i < interfaces.size(); ++i) {
30 DCHECK(interfaces[i].second == net::ADDRESS_FAMILY_IPV4 ||
31 interfaces[i].second == net::ADDRESS_FAMILY_IPV6);
32 base::FileDescriptor socket_descriptor(
33 net::CreatePlatformSocket(
34 net::ConvertAddressFamily(interfaces[i].second), SOCK_DGRAM,
35 IPPROTO_UDP),
36 true);
37 LOG_IF(ERROR, socket_descriptor.fd == net::kInvalidSocket)
38 << "Can't create socket, family=" << interfaces[i].second;
39 if (socket_descriptor.fd != net::kInvalidSocket) {
40 LocalDiscoveryMsg_SocketInfo socket;
41 socket.descriptor = socket_descriptor;
42 socket.interface_index = interfaces[i].first;
43 socket.address_family = interfaces[i].second;
44 sockets.push_back(socket);
48 return sockets;
50 #endif // OS_POSIX
52 } // namespace
54 class ServiceDiscoveryHostClient::ServiceWatcherProxy : public ServiceWatcher {
55 public:
56 ServiceWatcherProxy(ServiceDiscoveryHostClient* host,
57 const std::string& service_type,
58 const ServiceWatcher::UpdatedCallback& callback)
59 : host_(host),
60 service_type_(service_type),
61 id_(host_->RegisterWatcherCallback(callback)),
62 started_(false) {
65 virtual ~ServiceWatcherProxy() {
66 DVLOG(1) << "~ServiceWatcherProxy with id " << id_;
67 host_->UnregisterWatcherCallback(id_);
68 if (started_)
69 host_->Send(new LocalDiscoveryMsg_DestroyWatcher(id_));
72 virtual void Start() OVERRIDE {
73 DVLOG(1) << "ServiceWatcher::Start with id " << id_;
74 DCHECK(!started_);
75 host_->Send(new LocalDiscoveryMsg_StartWatcher(id_, service_type_));
76 started_ = true;
79 virtual void DiscoverNewServices(bool force_update) OVERRIDE {
80 DVLOG(1) << "ServiceWatcher::DiscoverNewServices with id " << id_;
81 DCHECK(started_);
82 host_->Send(new LocalDiscoveryMsg_DiscoverServices(id_, force_update));
85 virtual std::string GetServiceType() const OVERRIDE {
86 return service_type_;
89 private:
90 scoped_refptr<ServiceDiscoveryHostClient> host_;
91 const std::string service_type_;
92 const uint64 id_;
93 bool started_;
96 class ServiceDiscoveryHostClient::ServiceResolverProxy
97 : public ServiceResolver {
98 public:
99 ServiceResolverProxy(ServiceDiscoveryHostClient* host,
100 const std::string& service_name,
101 const ServiceResolver::ResolveCompleteCallback& callback)
102 : host_(host),
103 service_name_(service_name),
104 id_(host->RegisterResolverCallback(callback)),
105 started_(false) {
108 virtual ~ServiceResolverProxy() {
109 DVLOG(1) << "~ServiceResolverProxy with id " << id_;
110 host_->UnregisterResolverCallback(id_);
111 if (started_)
112 host_->Send(new LocalDiscoveryMsg_DestroyResolver(id_));
115 virtual void StartResolving() OVERRIDE {
116 DVLOG(1) << "ServiceResolverProxy::StartResolving with id " << id_;
117 DCHECK(!started_);
118 host_->Send(new LocalDiscoveryMsg_ResolveService(id_, service_name_));
119 started_ = true;
122 virtual std::string GetName() const OVERRIDE {
123 return service_name_;
126 private:
127 scoped_refptr<ServiceDiscoveryHostClient> host_;
128 const std::string service_name_;
129 const uint64 id_;
130 bool started_;
133 class ServiceDiscoveryHostClient::LocalDomainResolverProxy
134 : public LocalDomainResolver {
135 public:
136 LocalDomainResolverProxy(ServiceDiscoveryHostClient* host,
137 const std::string& domain,
138 net::AddressFamily address_family,
139 const LocalDomainResolver::IPAddressCallback& callback)
140 : host_(host),
141 domain_(domain),
142 address_family_(address_family),
143 id_(host->RegisterLocalDomainResolverCallback(callback)),
144 started_(false) {
147 virtual ~LocalDomainResolverProxy() {
148 DVLOG(1) << "~LocalDomainResolverProxy with id " << id_;
149 host_->UnregisterLocalDomainResolverCallback(id_);
150 if (started_)
151 host_->Send(new LocalDiscoveryMsg_DestroyLocalDomainResolver(id_));
154 virtual void Start() OVERRIDE {
155 DVLOG(1) << "LocalDomainResolverProxy::Start with id " << id_;
156 DCHECK(!started_);
157 host_->Send(new LocalDiscoveryMsg_ResolveLocalDomain(id_, domain_,
158 address_family_));
159 started_ = true;
162 private:
163 scoped_refptr<ServiceDiscoveryHostClient> host_;
164 std::string domain_;
165 net::AddressFamily address_family_;
166 const uint64 id_;
167 bool started_;
170 ServiceDiscoveryHostClient::ServiceDiscoveryHostClient() : current_id_(0) {
171 callback_runner_ = base::MessageLoop::current()->message_loop_proxy();
172 io_runner_ = BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
175 ServiceDiscoveryHostClient::~ServiceDiscoveryHostClient() {
176 DCHECK(service_watcher_callbacks_.empty());
177 DCHECK(service_resolver_callbacks_.empty());
178 DCHECK(domain_resolver_callbacks_.empty());
181 scoped_ptr<ServiceWatcher> ServiceDiscoveryHostClient::CreateServiceWatcher(
182 const std::string& service_type,
183 const ServiceWatcher::UpdatedCallback& callback) {
184 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
185 return scoped_ptr<ServiceWatcher>(
186 new ServiceWatcherProxy(this, service_type, callback));
189 scoped_ptr<ServiceResolver> ServiceDiscoveryHostClient::CreateServiceResolver(
190 const std::string& service_name,
191 const ServiceResolver::ResolveCompleteCallback& callback) {
192 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
193 return scoped_ptr<ServiceResolver>(
194 new ServiceResolverProxy(this, service_name, callback));
197 scoped_ptr<LocalDomainResolver>
198 ServiceDiscoveryHostClient::CreateLocalDomainResolver(
199 const std::string& domain,
200 net::AddressFamily address_family,
201 const LocalDomainResolver::IPAddressCallback& callback) {
202 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
203 return scoped_ptr<LocalDomainResolver>(new LocalDomainResolverProxy(
204 this, domain, address_family, callback));
207 uint64 ServiceDiscoveryHostClient::RegisterWatcherCallback(
208 const ServiceWatcher::UpdatedCallback& callback) {
209 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
210 DCHECK(!ContainsKey(service_watcher_callbacks_, current_id_ + 1));
211 service_watcher_callbacks_[++current_id_] = callback;
212 return current_id_;
215 uint64 ServiceDiscoveryHostClient::RegisterResolverCallback(
216 const ServiceResolver::ResolveCompleteCallback& callback) {
217 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
218 DCHECK(!ContainsKey(service_resolver_callbacks_, current_id_ + 1));
219 service_resolver_callbacks_[++current_id_] = callback;
220 return current_id_;
223 uint64 ServiceDiscoveryHostClient::RegisterLocalDomainResolverCallback(
224 const LocalDomainResolver::IPAddressCallback& callback) {
225 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
226 DCHECK(!ContainsKey(domain_resolver_callbacks_, current_id_ + 1));
227 domain_resolver_callbacks_[++current_id_] = callback;
228 return current_id_;
231 void ServiceDiscoveryHostClient::UnregisterWatcherCallback(uint64 id) {
232 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
233 service_watcher_callbacks_.erase(id);
236 void ServiceDiscoveryHostClient::UnregisterResolverCallback(uint64 id) {
237 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
238 service_resolver_callbacks_.erase(id);
241 void ServiceDiscoveryHostClient::UnregisterLocalDomainResolverCallback(
242 uint64 id) {
243 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
244 domain_resolver_callbacks_.erase(id);
247 void ServiceDiscoveryHostClient::Start(
248 const base::Closure& error_callback) {
249 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
250 DCHECK(!utility_host_);
251 DCHECK(error_callback_.is_null());
252 error_callback_ = error_callback;
253 io_runner_->PostTask(
254 FROM_HERE,
255 base::Bind(&ServiceDiscoveryHostClient::StartOnIOThread, this));
258 void ServiceDiscoveryHostClient::Shutdown() {
259 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
260 io_runner_->PostTask(
261 FROM_HERE,
262 base::Bind(&ServiceDiscoveryHostClient::ShutdownOnIOThread, this));
265 #if defined(OS_POSIX)
267 void ServiceDiscoveryHostClient::StartOnIOThread() {
268 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
269 DCHECK(!utility_host_);
270 BrowserThread::PostTaskAndReplyWithResult(
271 BrowserThread::FILE,
272 FROM_HERE,
273 base::Bind(&GetSocketsOnFileThread),
274 base::Bind(&ServiceDiscoveryHostClient::OnSocketsReady, this));
277 void ServiceDiscoveryHostClient::OnSocketsReady(const SocketInfoList& sockets) {
278 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
279 DCHECK(!utility_host_);
280 utility_host_ = UtilityProcessHost::Create(
281 this, base::MessageLoopProxy::current().get())->AsWeakPtr();
282 if (!utility_host_)
283 return;
284 utility_host_->EnableMDns();
285 utility_host_->StartBatchMode();
286 if (sockets.empty()) {
287 ShutdownOnIOThread();
288 return;
290 utility_host_->Send(new LocalDiscoveryMsg_SetSockets(sockets));
291 // Send messages for requests made during network enumeration.
292 for (size_t i = 0; i < delayed_messages_.size(); ++i)
293 utility_host_->Send(delayed_messages_[i]);
294 delayed_messages_.weak_clear();
297 #else // OS_POSIX
299 void ServiceDiscoveryHostClient::StartOnIOThread() {
300 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
301 DCHECK(!utility_host_);
302 utility_host_ = UtilityProcessHost::Create(
303 this, base::MessageLoopProxy::current().get())->AsWeakPtr();
304 if (!utility_host_)
305 return;
306 utility_host_->EnableMDns();
307 utility_host_->StartBatchMode();
308 // Windows does not enumerate networks here.
309 DCHECK(delayed_messages_.empty());
312 #endif // OS_POSIX
314 void ServiceDiscoveryHostClient::ShutdownOnIOThread() {
315 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
316 if (utility_host_) {
317 utility_host_->Send(new LocalDiscoveryMsg_ShutdownLocalDiscovery);
318 utility_host_->EndBatchMode();
319 utility_host_.reset();
321 error_callback_ = base::Closure();
324 void ServiceDiscoveryHostClient::Send(IPC::Message* msg) {
325 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
326 io_runner_->PostTask(
327 FROM_HERE,
328 base::Bind(&ServiceDiscoveryHostClient::SendOnIOThread, this, msg));
331 void ServiceDiscoveryHostClient::SendOnIOThread(IPC::Message* msg) {
332 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
333 if (utility_host_) {
334 utility_host_->Send(msg);
335 } else {
336 delayed_messages_.push_back(msg);
340 void ServiceDiscoveryHostClient::OnProcessCrashed(int exit_code) {
341 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
342 DCHECK(!utility_host_);
343 OnError();
346 bool ServiceDiscoveryHostClient::OnMessageReceived(
347 const IPC::Message& message) {
348 bool handled = true;
349 IPC_BEGIN_MESSAGE_MAP(ServiceDiscoveryHostClient, message)
350 IPC_MESSAGE_HANDLER(LocalDiscoveryHostMsg_Error, OnError)
351 IPC_MESSAGE_HANDLER(LocalDiscoveryHostMsg_WatcherCallback,
352 OnWatcherCallback)
353 IPC_MESSAGE_HANDLER(LocalDiscoveryHostMsg_ResolverCallback,
354 OnResolverCallback)
355 IPC_MESSAGE_HANDLER(LocalDiscoveryHostMsg_LocalDomainResolverCallback,
356 OnLocalDomainResolverCallback)
357 IPC_MESSAGE_UNHANDLED(handled = false)
358 IPC_END_MESSAGE_MAP()
359 return handled;
362 void ServiceDiscoveryHostClient::InvalidateWatchers() {
363 WatcherCallbacks service_watcher_callbacks;
364 service_watcher_callbacks_.swap(service_watcher_callbacks);
365 service_resolver_callbacks_.clear();
366 domain_resolver_callbacks_.clear();
368 for (WatcherCallbacks::iterator i = service_watcher_callbacks.begin();
369 i != service_watcher_callbacks.end(); i++) {
370 if (!i->second.is_null()) {
371 i->second.Run(ServiceWatcher::UPDATE_INVALIDATED, "");
376 void ServiceDiscoveryHostClient::OnError() {
377 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
378 if (!error_callback_.is_null())
379 callback_runner_->PostTask(FROM_HERE, error_callback_);
382 void ServiceDiscoveryHostClient::OnWatcherCallback(
383 uint64 id,
384 ServiceWatcher::UpdateType update,
385 const std::string& service_name) {
386 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
387 callback_runner_->PostTask(
388 FROM_HERE,
389 base::Bind(&ServiceDiscoveryHostClient::RunWatcherCallback, this, id,
390 update, service_name));
393 void ServiceDiscoveryHostClient::OnResolverCallback(
394 uint64 id,
395 ServiceResolver::RequestStatus status,
396 const ServiceDescription& description) {
397 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
398 callback_runner_->PostTask(
399 FROM_HERE,
400 base::Bind(&ServiceDiscoveryHostClient::RunResolverCallback, this, id,
401 status, description));
404 void ServiceDiscoveryHostClient::OnLocalDomainResolverCallback(
405 uint64 id,
406 bool success,
407 const net::IPAddressNumber& ip_address_ipv4,
408 const net::IPAddressNumber& ip_address_ipv6) {
409 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
410 callback_runner_->PostTask(
411 FROM_HERE,
412 base::Bind(&ServiceDiscoveryHostClient::RunLocalDomainResolverCallback,
413 this, id, success, ip_address_ipv4, ip_address_ipv6));
416 void ServiceDiscoveryHostClient::RunWatcherCallback(
417 uint64 id,
418 ServiceWatcher::UpdateType update,
419 const std::string& service_name) {
420 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
421 WatcherCallbacks::iterator it = service_watcher_callbacks_.find(id);
422 if (it != service_watcher_callbacks_.end() && !it->second.is_null())
423 it->second.Run(update, service_name);
426 void ServiceDiscoveryHostClient::RunResolverCallback(
427 uint64 id,
428 ServiceResolver::RequestStatus status,
429 const ServiceDescription& description) {
430 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
431 ResolverCallbacks::iterator it = service_resolver_callbacks_.find(id);
432 if (it != service_resolver_callbacks_.end() && !it->second.is_null())
433 it->second.Run(status, description);
436 void ServiceDiscoveryHostClient::RunLocalDomainResolverCallback(
437 uint64 id,
438 bool success,
439 const net::IPAddressNumber& ip_address_ipv4,
440 const net::IPAddressNumber& ip_address_ipv6) {
441 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
442 DomainResolverCallbacks::iterator it = domain_resolver_callbacks_.find(id);
443 if (it != domain_resolver_callbacks_.end() && !it->second.is_null())
444 it->second.Run(success, ip_address_ipv4, ip_address_ipv6);
447 } // namespace local_discovery