service_discovery_host_client.cc revision a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/local_discovery/service_discovery_host_client.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/local_discovery/local_discovery_messages.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/browser_thread.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/utility_process_host.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/dns/mdns_client.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/socket/socket_descriptor.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_POSIX)
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <netinet/in.h>
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/file_descriptor_posix.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // OS_POSIX
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace local_discovery {
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::BrowserThread;
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::UtilityProcessHost;
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_POSIX)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SocketInfoList GetSocketsOnFileThread() {
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  net::InterfaceIndexFamilyList interfaces(net::GetMDnsInterfacesToBind());
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SocketInfoList sockets;
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < interfaces.size(); ++i) {
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(interfaces[i].second == net::ADDRESS_FAMILY_IPV4 ||
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           interfaces[i].second == net::ADDRESS_FAMILY_IPV6);
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::FileDescriptor socket_descriptor(
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        net::CreatePlatformSocket(
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            net::ConvertAddressFamily(interfaces[i].second), SOCK_DGRAM,
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      IPPROTO_UDP),
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        true);
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG_IF(ERROR, socket_descriptor.fd == net::kInvalidSocket)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        << "Can't create socket, family=" << interfaces[i].second;
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (socket_descriptor.fd != net::kInvalidSocket) {
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LocalDiscoveryMsg_SocketInfo socket;
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      socket.descriptor = socket_descriptor;
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      socket.interface_index = interfaces[i].first;
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      socket.address_family = interfaces[i].second;
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sockets.push_back(socket);
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return sockets;
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // OS_POSIX
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ServiceDiscoveryHostClient::ServiceWatcherProxy : public ServiceWatcher {
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ServiceWatcherProxy(ServiceDiscoveryHostClient* host,
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      const std::string& service_type,
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      const ServiceWatcher::UpdatedCallback& callback)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : host_(host),
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        service_type_(service_type),
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        id_(host_->RegisterWatcherCallback(callback)),
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        started_(false) {
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~ServiceWatcherProxy() {
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DVLOG(1) << "~ServiceWatcherProxy with id " << id_;
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    host_->UnregisterWatcherCallback(id_);
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (started_)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      host_->Send(new LocalDiscoveryMsg_DestroyWatcher(id_));
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void Start() OVERRIDE {
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DVLOG(1) << "ServiceWatcher::Start with id " << id_;
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!started_);
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    host_->Send(new LocalDiscoveryMsg_StartWatcher(id_, service_type_));
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    started_ = true;
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void DiscoverNewServices(bool force_update) OVERRIDE {
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DVLOG(1) << "ServiceWatcher::DiscoverNewServices with id " << id_;
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(started_);
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    host_->Send(new LocalDiscoveryMsg_DiscoverServices(id_, force_update));
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual std::string GetServiceType() const OVERRIDE {
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return service_type_;
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<ServiceDiscoveryHostClient> host_;
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const std::string service_type_;
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const uint64 id_;
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool started_;
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ServiceDiscoveryHostClient::ServiceResolverProxy
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : public ServiceResolver {
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ServiceResolverProxy(ServiceDiscoveryHostClient* host,
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       const std::string& service_name,
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       const ServiceResolver::ResolveCompleteCallback& callback)
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : host_(host),
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        service_name_(service_name),
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        id_(host->RegisterResolverCallback(callback)),
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        started_(false) {
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~ServiceResolverProxy() {
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DVLOG(1) << "~ServiceResolverProxy with id " << id_;
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    host_->UnregisterResolverCallback(id_);
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (started_)
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      host_->Send(new LocalDiscoveryMsg_DestroyResolver(id_));
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void StartResolving() OVERRIDE {
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DVLOG(1) << "ServiceResolverProxy::StartResolving with id " << id_;
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!started_);
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    host_->Send(new LocalDiscoveryMsg_ResolveService(id_, service_name_));
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    started_ = true;
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual std::string GetName() const OVERRIDE {
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return service_name_;
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<ServiceDiscoveryHostClient> host_;
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const std::string service_name_;
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const uint64 id_;
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool started_;
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ServiceDiscoveryHostClient::LocalDomainResolverProxy
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : public LocalDomainResolver {
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LocalDomainResolverProxy(ServiceDiscoveryHostClient* host,
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       const std::string& domain,
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       net::AddressFamily address_family,
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       const LocalDomainResolver::IPAddressCallback& callback)
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : host_(host),
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        domain_(domain),
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        address_family_(address_family),
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        id_(host->RegisterLocalDomainResolverCallback(callback)),
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        started_(false) {
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~LocalDomainResolverProxy() {
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DVLOG(1) << "~LocalDomainResolverProxy with id " << id_;
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    host_->UnregisterLocalDomainResolverCallback(id_);
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (started_)
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      host_->Send(new LocalDiscoveryMsg_DestroyLocalDomainResolver(id_));
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void Start() OVERRIDE {
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DVLOG(1) << "LocalDomainResolverProxy::Start with id " << id_;
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!started_);
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    host_->Send(new LocalDiscoveryMsg_ResolveLocalDomain(id_, domain_,
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                         address_family_));
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    started_ = true;
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<ServiceDiscoveryHostClient> host_;
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string domain_;
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  net::AddressFamily address_family_;
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const uint64 id_;
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool started_;
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ServiceDiscoveryHostClient::ServiceDiscoveryHostClient() : current_id_(0) {
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  callback_runner_ = base::MessageLoop::current()->message_loop_proxy();
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  io_runner_ = BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ServiceDiscoveryHostClient::~ServiceDiscoveryHostClient() {
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(service_watcher_callbacks_.empty());
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(service_resolver_callbacks_.empty());
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(domain_resolver_callbacks_.empty());
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)scoped_ptr<ServiceWatcher> ServiceDiscoveryHostClient::CreateServiceWatcher(
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& service_type,
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ServiceWatcher::UpdatedCallback& callback) {
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return scoped_ptr<ServiceWatcher>(
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      new ServiceWatcherProxy(this, service_type, callback));
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)scoped_ptr<ServiceResolver> ServiceDiscoveryHostClient::CreateServiceResolver(
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& service_name,
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ServiceResolver::ResolveCompleteCallback& callback) {
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return scoped_ptr<ServiceResolver>(
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      new ServiceResolverProxy(this, service_name, callback));
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)scoped_ptr<LocalDomainResolver>
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ServiceDiscoveryHostClient::CreateLocalDomainResolver(
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& domain,
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    net::AddressFamily address_family,
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const LocalDomainResolver::IPAddressCallback& callback) {
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return scoped_ptr<LocalDomainResolver>(new LocalDomainResolverProxy(
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this, domain, address_family, callback));
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)uint64 ServiceDiscoveryHostClient::RegisterWatcherCallback(
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ServiceWatcher::UpdatedCallback& callback) {
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!ContainsKey(service_watcher_callbacks_, current_id_ + 1));
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  service_watcher_callbacks_[++current_id_] = callback;
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return current_id_;
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)uint64 ServiceDiscoveryHostClient::RegisterResolverCallback(
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ServiceResolver::ResolveCompleteCallback& callback) {
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!ContainsKey(service_resolver_callbacks_, current_id_ + 1));
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  service_resolver_callbacks_[++current_id_] = callback;
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return current_id_;
221}
222
223uint64 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_;
229}
230
231void ServiceDiscoveryHostClient::UnregisterWatcherCallback(uint64 id) {
232  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
233  service_watcher_callbacks_.erase(id);
234}
235
236void ServiceDiscoveryHostClient::UnregisterResolverCallback(uint64 id) {
237  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
238  service_resolver_callbacks_.erase(id);
239}
240
241void ServiceDiscoveryHostClient::UnregisterLocalDomainResolverCallback(
242    uint64 id) {
243  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
244  domain_resolver_callbacks_.erase(id);
245}
246
247void 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));
256}
257
258void ServiceDiscoveryHostClient::Shutdown() {
259  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
260  io_runner_->PostTask(
261      FROM_HERE,
262      base::Bind(&ServiceDiscoveryHostClient::ShutdownOnIOThread, this));
263}
264
265#if defined(OS_POSIX)
266
267void 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));
275}
276
277void 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;
289  }
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();
295}
296
297#else  // OS_POSIX
298
299void 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());
310}
311
312#endif  // OS_POSIX
313
314void 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();
320  }
321  error_callback_ = base::Closure();
322}
323
324void 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));
329}
330
331void 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);
337  }
338}
339
340void ServiceDiscoveryHostClient::OnProcessCrashed(int exit_code) {
341  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
342  DCHECK(!utility_host_);
343  OnError();
344}
345
346bool 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;
360}
361
362void 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();
367
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, "");
372    }
373  }
374}
375
376void ServiceDiscoveryHostClient::OnError() {
377  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
378  if (!error_callback_.is_null())
379    callback_runner_->PostTask(FROM_HERE, error_callback_);
380}
381
382void 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));
391}
392
393void 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));
402}
403
404void 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));
414}
415
416void 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);
424}
425
426void 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);
434}
435
436void 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);
445}
446
447}  // namespace local_discovery
448