15c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// Copyright 2014 The Chromium Authors. All rights reserved.
268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)// found in the LICENSE file.
468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "chrome/browser/local_discovery/service_discovery_client_mdns.h"
668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
75c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "base/memory/scoped_vector.h"
84e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/metrics/histogram.h"
95c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "chrome/common/local_discovery/service_discovery_client_impl.h"
1068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "content/public/browser/browser_thread.h"
115c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "net/dns/mdns_client.h"
125c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "net/udp/datagram_server_socket.h"
1368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
1468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)namespace local_discovery {
1568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
1668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)using content::BrowserThread;
1768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// Base class for objects returned by ServiceDiscoveryClient implementation.
195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// Handles interaction of client code on UI thread end net code on mdns thread.
205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuclass ServiceDiscoveryClientMdns::Proxy {
215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu public:
225c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  typedef base::WeakPtr<Proxy> WeakPtr;
235c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
245c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  explicit Proxy(ServiceDiscoveryClientMdns* client)
255c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      : client_(client),
265c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        weak_ptr_factory_(this) {
275c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
28cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    client_->proxies_.AddObserver(this);
295c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
315c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  virtual ~Proxy() {
325c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
33cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    client_->proxies_.RemoveObserver(this);
345c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
355c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
366e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // Returns true if object is not yet shutdown.
376e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  virtual bool IsValid() = 0;
386e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
396e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // Notifies proxies that mDNS layer is going to be destroyed.
405c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  virtual void OnMdnsDestroy() = 0;
415c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
426e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // Notifies proxies that new mDNS instance is ready.
436e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  virtual void OnNewMdnsReady() {
446e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    DCHECK(!client_->need_dalay_mdns_tasks_);
456e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if (IsValid()) {
466e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      for (size_t i = 0; i < delayed_tasks_.size(); ++i)
476e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        client_->mdns_runner_->PostTask(FROM_HERE, delayed_tasks_[i]);
486e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    }
496e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    delayed_tasks_.clear();
506e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
515c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
526e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // Runs callback using this method to abort callback if instance of |Proxy|
535c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // is deleted.
545c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  void RunCallback(const base::Closure& callback) {
555c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
565c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    callback.Run();
575c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
585c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
595c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu protected:
606e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  void PostToMdnsThread(const base::Closure& task) {
616e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    DCHECK(IsValid());
626e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // The first task on IO thread for each |mdns_| instance must be |InitMdns|.
636e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // |OnInterfaceListReady| could be delayed by |GetMDnsInterfacesToBind|
646e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // running on FILE thread, so |PostToMdnsThread| could be called to post
656e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // task for |mdns_| that is not initialized yet.
666e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if (!client_->need_dalay_mdns_tasks_) {
676e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      client_->mdns_runner_->PostTask(FROM_HERE, task);
686e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      return;
696e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    }
706e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    delayed_tasks_.push_back(task);
715c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
725c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
735c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  static bool PostToUIThread(const base::Closure& task) {
745c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    return BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, task);
755c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
765c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
775c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  ServiceDiscoveryClient* client() {
785c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    return client_->client_.get();
795c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
805c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
815c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  WeakPtr GetWeakPtr() {
825c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    return weak_ptr_factory_.GetWeakPtr();
835c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
845c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
855c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  template<class T>
865c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  void DeleteOnMdnsThread(T* t) {
875c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    if (!t)
885c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      return;
895c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    if (!client_->mdns_runner_->DeleteSoon(FROM_HERE, t))
905c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      delete t;
915c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
925c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
935c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu private:
945c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  scoped_refptr<ServiceDiscoveryClientMdns> client_;
955c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  base::WeakPtrFactory<Proxy> weak_ptr_factory_;
966e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // Delayed |mdns_runner_| tasks.
976e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  std::vector<base::Closure> delayed_tasks_;
985c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  DISALLOW_COPY_AND_ASSIGN(Proxy);
995c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu};
1005c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
10168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)namespace {
1025c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
10368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const int kMaxRestartAttempts = 10;
10468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const int kRestartDelayOnNetworkChangeSeconds = 3;
1055c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1065c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liutypedef base::Callback<void(bool)> MdnsInitCallback;
1075c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1085c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuclass SocketFactory : public net::MDnsSocketFactory {
1095c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu public:
1105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  explicit SocketFactory(const net::InterfaceIndexFamilyList& interfaces)
1115c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      : interfaces_(interfaces) {}
1125c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1135c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // net::MDnsSocketFactory implementation:
1145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  virtual void CreateSockets(
1155c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      ScopedVector<net::DatagramServerSocket>* sockets) OVERRIDE {
1165c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    for (size_t i = 0; i < interfaces_.size(); ++i) {
1175c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      DCHECK(interfaces_[i].second == net::ADDRESS_FAMILY_IPV4 ||
1185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu             interfaces_[i].second == net::ADDRESS_FAMILY_IPV6);
1195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      scoped_ptr<net::DatagramServerSocket> socket(
1205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu          CreateAndBindMDnsSocket(interfaces_[i].second, interfaces_[i].first));
1215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      if (socket)
1225c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        sockets->push_back(socket.release());
1235c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    }
1245c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
1255c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1265c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu private:
1275c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  net::InterfaceIndexFamilyList interfaces_;
1285c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu};
1295c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid InitMdns(const MdnsInitCallback& on_initialized,
1315c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu              const net::InterfaceIndexFamilyList& interfaces,
1325c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu              net::MDnsClient* mdns) {
1335c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  SocketFactory socket_factory(interfaces);
1345c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
1355c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                          base::Bind(on_initialized,
1365c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                                     mdns->StartListening(&socket_factory)));
1375c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
1385c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1395c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liutemplate<class T>
1405c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuclass ProxyBase : public ServiceDiscoveryClientMdns::Proxy, public T {
1415c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu public:
1425c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  typedef ProxyBase<T> Base;
1435c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1445c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  explicit ProxyBase(ServiceDiscoveryClientMdns* client)
1455c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      : Proxy(client) {
1465c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
1475c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1485c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  virtual ~ProxyBase() {
1495c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    DeleteOnMdnsThread(implementation_.release());
1505c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
1515c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1526e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  virtual bool IsValid() OVERRIDE {
1536e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    return !!implementation();
1546e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
1556e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1565c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  virtual void OnMdnsDestroy() OVERRIDE {
1575c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    DeleteOnMdnsThread(implementation_.release());
1585c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  };
1595c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1605c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu protected:
1615c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  void set_implementation(scoped_ptr<T> implementation) {
1625c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    implementation_ = implementation.Pass();
1635c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
1645c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1655c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  T* implementation()  const {
1665c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    return implementation_.get();
1675c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
1685c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1695c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu private:
1705c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  scoped_ptr<T> implementation_;
1715c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  DISALLOW_COPY_AND_ASSIGN(ProxyBase);
1725c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu};
1735c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1745c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuclass ServiceWatcherProxy : public ProxyBase<ServiceWatcher> {
1755c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu public:
1765c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  ServiceWatcherProxy(ServiceDiscoveryClientMdns* client_mdns,
1775c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                      const std::string& service_type,
1785c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                      const ServiceWatcher::UpdatedCallback& callback)
1795c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      : ProxyBase(client_mdns),
1805c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        service_type_(service_type),
1815c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        callback_(callback) {
1825c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    // It's safe to call |CreateServiceWatcher| on UI thread, because
1835c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    // |MDnsClient| is not used there. It's simplify implementation.
1845c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    set_implementation(client()->CreateServiceWatcher(
1855c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        service_type,
1865c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        base::Bind(&ServiceWatcherProxy::OnCallback, GetWeakPtr(), callback)));
1875c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
1885c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1895c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // ServiceWatcher methods.
1905c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  virtual void Start() OVERRIDE {
1916e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if (implementation()) {
1925c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      PostToMdnsThread(base::Bind(&ServiceWatcher::Start,
1935c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                                  base::Unretained(implementation())));
1946e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    }
1955c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
1965c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1975c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  virtual void DiscoverNewServices(bool force_update) OVERRIDE {
1986e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if (implementation()) {
1995c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      PostToMdnsThread(base::Bind(&ServiceWatcher::DiscoverNewServices,
2005c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                                  base::Unretained(implementation()),
2015c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                                  force_update));
2026e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    }
2035c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
2045c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
2055c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  virtual void SetActivelyRefreshServices(
2065c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      bool actively_refresh_services) OVERRIDE {
2076e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if (implementation()) {
2085c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      PostToMdnsThread(base::Bind(&ServiceWatcher::SetActivelyRefreshServices,
2095c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                                  base::Unretained(implementation()),
2105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                                  actively_refresh_services));
2116e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    }
2125c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
2135c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
2145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  virtual std::string GetServiceType() const OVERRIDE {
2155c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    return service_type_;
2165c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
2175c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
2185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  virtual void OnNewMdnsReady() OVERRIDE {
2196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    ProxyBase<ServiceWatcher>::OnNewMdnsReady();
2205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    if (!implementation())
2215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      callback_.Run(ServiceWatcher::UPDATE_INVALIDATED, "");
2225c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
2235c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
2245c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu private:
2255c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  static void OnCallback(const WeakPtr& proxy,
2265c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                         const ServiceWatcher::UpdatedCallback& callback,
2275c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                         UpdateType a1,
2285c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                         const std::string& a2) {
2295c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
2305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    PostToUIThread(base::Bind(&Base::RunCallback, proxy,
2315c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                              base::Bind(callback, a1, a2)));
2325c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
2335c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  std::string service_type_;
2345c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  ServiceWatcher::UpdatedCallback callback_;
2355c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  DISALLOW_COPY_AND_ASSIGN(ServiceWatcherProxy);
2365c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu};
2375c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
2385c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuclass ServiceResolverProxy : public ProxyBase<ServiceResolver> {
2395c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu public:
2405c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  ServiceResolverProxy(ServiceDiscoveryClientMdns* client_mdns,
2415c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                       const std::string& service_name,
2425c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                       const ServiceResolver::ResolveCompleteCallback& callback)
2435c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      : ProxyBase(client_mdns),
2445c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        service_name_(service_name) {
2455c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    // It's safe to call |CreateServiceResolver| on UI thread, because
2465c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    // |MDnsClient| is not used there. It's simplify implementation.
2475c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    set_implementation(client()->CreateServiceResolver(
2485c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        service_name,
2495c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        base::Bind(&ServiceResolverProxy::OnCallback, GetWeakPtr(), callback)));
2505c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
2515c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
2525c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // ServiceResolver methods.
2535c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  virtual void StartResolving() OVERRIDE {
2546e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if (implementation()) {
2555c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      PostToMdnsThread(base::Bind(&ServiceResolver::StartResolving,
2565c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                                  base::Unretained(implementation())));
2576e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    }
2585c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  };
2595c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
2605c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  virtual std::string GetName() const OVERRIDE {
2615c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    return service_name_;
2625c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
2635c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
2645c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu private:
2655c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  static void OnCallback(
2665c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      const WeakPtr& proxy,
2675c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      const ServiceResolver::ResolveCompleteCallback& callback,
2685c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      RequestStatus a1,
2695c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      const ServiceDescription& a2) {
2705c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
2715c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    PostToUIThread(base::Bind(&Base::RunCallback, proxy,
2725c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                              base::Bind(callback, a1, a2)));
2735c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
2745c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
2755c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  std::string service_name_;
2765c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  DISALLOW_COPY_AND_ASSIGN(ServiceResolverProxy);
2775c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu};
2785c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
2795c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuclass LocalDomainResolverProxy : public ProxyBase<LocalDomainResolver> {
2805c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu public:
2815c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  LocalDomainResolverProxy(
2825c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      ServiceDiscoveryClientMdns* client_mdns,
2835c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      const std::string& domain,
2845c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      net::AddressFamily address_family,
2855c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      const LocalDomainResolver::IPAddressCallback& callback)
2865c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      : ProxyBase(client_mdns) {
2875c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    // It's safe to call |CreateLocalDomainResolver| on UI thread, because
2885c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    // |MDnsClient| is not used there. It's simplify implementation.
2895c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    set_implementation(client()->CreateLocalDomainResolver(
2905c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        domain,
2915c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        address_family,
2925c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        base::Bind(
2935c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu            &LocalDomainResolverProxy::OnCallback, GetWeakPtr(), callback)));
2945c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
2955c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
2965c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // LocalDomainResolver methods.
2975c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  virtual void Start() OVERRIDE {
2986e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if (implementation()) {
2995c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      PostToMdnsThread(base::Bind(&LocalDomainResolver::Start,
3005c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                                  base::Unretained(implementation())));
3016e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    }
3025c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  };
3035c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
3045c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu private:
3055c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  static void OnCallback(const WeakPtr& proxy,
3065c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                         const LocalDomainResolver::IPAddressCallback& callback,
3075c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                         bool a1,
3085c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                         const net::IPAddressNumber& a2,
3095c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                         const net::IPAddressNumber& a3) {
3105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
3115c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    PostToUIThread(base::Bind(&Base::RunCallback, proxy,
3125c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                              base::Bind(callback, a1, a2, a3)));
3135c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
3145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
3155c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  DISALLOW_COPY_AND_ASSIGN(LocalDomainResolverProxy);
3165c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu};
3175c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
3185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}  // namespace
3195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
3205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuServiceDiscoveryClientMdns::ServiceDiscoveryClientMdns()
3215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    : mdns_runner_(
3225c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu          BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO)),
3235c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      restart_attempts_(0),
3245c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      need_dalay_mdns_tasks_(true),
3255c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      weak_ptr_factory_(this) {
3265c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
3275c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  net::NetworkChangeNotifier::AddNetworkChangeObserver(this);
3285c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  StartNewClient();
32968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
33068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
33168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)scoped_ptr<ServiceWatcher> ServiceDiscoveryClientMdns::CreateServiceWatcher(
33268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const std::string& service_type,
33368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const ServiceWatcher::UpdatedCallback& callback) {
33468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
3355c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  return scoped_ptr<ServiceWatcher>(
3365c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      new ServiceWatcherProxy(this, service_type, callback));
33768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
33868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
33968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)scoped_ptr<ServiceResolver> ServiceDiscoveryClientMdns::CreateServiceResolver(
34068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const std::string& service_name,
34168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const ServiceResolver::ResolveCompleteCallback& callback) {
34268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
3435c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  return scoped_ptr<ServiceResolver>(
3445c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      new ServiceResolverProxy(this, service_name, callback));
34568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
34668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
34768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)scoped_ptr<LocalDomainResolver>
34868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)ServiceDiscoveryClientMdns::CreateLocalDomainResolver(
34968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const std::string& domain,
35068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    net::AddressFamily address_family,
35168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const LocalDomainResolver::IPAddressCallback& callback) {
35268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
3535c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  return scoped_ptr<LocalDomainResolver>(
3545c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      new LocalDomainResolverProxy(this, domain, address_family, callback));
35568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
35668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
35768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)ServiceDiscoveryClientMdns::~ServiceDiscoveryClientMdns() {
35868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
35968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
360cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DestroyMdns();
36168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
36268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
36368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void ServiceDiscoveryClientMdns::OnNetworkChanged(
36468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    net::NetworkChangeNotifier::ConnectionType type) {
36568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
3665c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // Only network changes resets counter.
3675c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  restart_attempts_ = 0;
36868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  ScheduleStartNewClient();
36968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
37068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
37168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void ServiceDiscoveryClientMdns::ScheduleStartNewClient() {
37268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
373cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  OnBeforeMdnsDestroy();
3745c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (restart_attempts_ < kMaxRestartAttempts) {
3754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    base::MessageLoop::current()->PostDelayedTask(
3764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        FROM_HERE,
3775c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        base::Bind(&ServiceDiscoveryClientMdns::StartNewClient,
3784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                   weak_ptr_factory_.GetWeakPtr()),
3795c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        base::TimeDelta::FromSeconds(
3805c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu            kRestartDelayOnNetworkChangeSeconds * (1 << restart_attempts_)));
38168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  } else {
3824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    ReportSuccess();
38368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  }
3845c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
3855c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
3865c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid ServiceDiscoveryClientMdns::StartNewClient() {
3875c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
3885c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  ++restart_attempts_;
389cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DestroyMdns();
3905c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  mdns_.reset(net::MDnsClient::CreateDefault().release());
3915c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  client_.reset(new ServiceDiscoveryClientImpl(mdns_.get()));
3925c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  BrowserThread::PostTaskAndReplyWithResult(
3935c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      BrowserThread::FILE,
3945c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      FROM_HERE,
3955c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      base::Bind(&net::GetMDnsInterfacesToBind),
3965c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      base::Bind(&ServiceDiscoveryClientMdns::OnInterfaceListReady,
3975c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                 weak_ptr_factory_.GetWeakPtr()));
3985c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
3995c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
4005c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid ServiceDiscoveryClientMdns::OnInterfaceListReady(
4015c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    const net::InterfaceIndexFamilyList& interfaces) {
4025c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  mdns_runner_->PostTask(
4035c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      FROM_HERE,
4045c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      base::Bind(&InitMdns,
4055c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                 base::Bind(&ServiceDiscoveryClientMdns::OnMdnsInitialized,
4065c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                            weak_ptr_factory_.GetWeakPtr()),
4075c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                 interfaces,
4085c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                 base::Unretained(mdns_.get())));
4095c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
4105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
4115c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid ServiceDiscoveryClientMdns::OnMdnsInitialized(bool success) {
4125c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
4135c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (!success) {
4145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    ScheduleStartNewClient();
4155c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    return;
4165c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
4175c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  ReportSuccess();
4185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
419cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Initialization is done, no need to delay tasks.
420cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  need_dalay_mdns_tasks_ = false;
421cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  FOR_EACH_OBSERVER(Proxy, proxies_, OnNewMdnsReady());
42268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
42368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
4244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void ServiceDiscoveryClientMdns::ReportSuccess() {
4255c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
4264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  UMA_HISTOGRAM_COUNTS_100("LocalDiscovery.ClientRestartAttempts",
4275c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                           restart_attempts_);
4285c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
4295c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
430cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void ServiceDiscoveryClientMdns::OnBeforeMdnsDestroy() {
4315c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  need_dalay_mdns_tasks_ = true;
4325c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  weak_ptr_factory_.InvalidateWeakPtrs();
433cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  FOR_EACH_OBSERVER(Proxy, proxies_, OnMdnsDestroy());
434cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
4355c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
436cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void ServiceDiscoveryClientMdns::DestroyMdns() {
437cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  OnBeforeMdnsDestroy();
438cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // After calling |Proxy::OnMdnsDestroy| all references to client_ and mdns_
439cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // should be destroyed.
4405c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (client_)
4415c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    mdns_runner_->DeleteSoon(FROM_HERE, client_.release());
4425c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (mdns_)
4435c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    mdns_runner_->DeleteSoon(FROM_HERE, mdns_.release());
4445c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
4455c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
44668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}  // namespace local_discovery
447