Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / chrome / utility / local_discovery / service_discovery_message_handler.cc
index e03853f..3110c94 100644 (file)
@@ -8,9 +8,10 @@
 
 #include "base/lazy_instance.h"
 #include "chrome/common/local_discovery/local_discovery_messages.h"
-#include "chrome/utility/local_discovery/service_discovery_client_impl.h"
+#include "chrome/common/local_discovery/service_discovery_client_impl.h"
 #include "content/public/utility/utility_thread.h"
 #include "net/socket/socket_descriptor.h"
+#include "net/udp/datagram_server_socket.h"
 
 namespace local_discovery {
 
@@ -18,76 +19,91 @@ namespace {
 
 void ClosePlatformSocket(net::SocketDescriptor socket);
 
-class SocketFactory : public net::PlatformSocketFactory {
+// Sets socket factory used by |net::CreatePlatformSocket|. Implemetation
+// keeps single socket that will be returned to the first call to
+// |net::CreatePlatformSocket| during object lifetime.
+class ScopedSocketFactory : public net::PlatformSocketFactory {
  public:
-  SocketFactory()
-      : socket_v4_(net::kInvalidSocket),
-        socket_v6_(net::kInvalidSocket) {
+  explicit ScopedSocketFactory(net::SocketDescriptor socket) : socket_(socket) {
+    net::PlatformSocketFactory::SetInstance(this);
   }
 
-  void SetSockets(net::SocketDescriptor socket_v4,
-                  net::SocketDescriptor socket_v6) {
-    Reset();
-    socket_v4_ = socket_v4;
-    socket_v6_ = socket_v6;
-    VLOG(1) << "SetSockets: " << socket_v4_ << " " << socket_v6_;
-  }
-
-  void Reset() {
-    if (socket_v4_ != net::kInvalidSocket) {
-      ClosePlatformSocket(socket_v4_);
-      socket_v4_ = net::kInvalidSocket;
-    }
-    if (socket_v6_ != net::kInvalidSocket) {
-      ClosePlatformSocket(socket_v6_);
-      socket_v6_ = net::kInvalidSocket;
-    }
-  }
-
-  virtual ~SocketFactory() {
-    Reset();
+  ~ScopedSocketFactory() override {
+    net::PlatformSocketFactory::SetInstance(NULL);
+    ClosePlatformSocket(socket_);
+    socket_ = net::kInvalidSocket;
   }
 
- protected:
-  virtual net::SocketDescriptor CreateSocket(int family, int type,
-                                             int protocol) OVERRIDE {
+  net::SocketDescriptor CreateSocket(int family,
+                                     int type,
+                                     int protocol) override {
+    DCHECK_EQ(type, SOCK_DGRAM);
+    DCHECK(family == AF_INET || family == AF_INET6);
     net::SocketDescriptor result = net::kInvalidSocket;
-    if (type != SOCK_DGRAM) {
-      NOTREACHED();
-    } else if (family == AF_INET) {
-      std::swap(result, socket_v4_);
-    } else if (family == AF_INET6) {
-      std::swap(result, socket_v6_);
-    }
+    std::swap(result, socket_);
     return result;
   }
 
  private:
-  net::SocketDescriptor socket_v4_;
-  net::SocketDescriptor socket_v6_;
-
-  DISALLOW_COPY_AND_ASSIGN(SocketFactory);
+  net::SocketDescriptor socket_;
+  DISALLOW_COPY_AND_ASSIGN(ScopedSocketFactory);
 };
 
-base::LazyInstance<SocketFactory>
-    g_local_discovery_socket_factory = LAZY_INSTANCE_INITIALIZER;
+struct SocketInfo {
+  SocketInfo(net::SocketDescriptor socket,
+             net::AddressFamily address_family,
+             uint32 interface_index)
+      : socket(socket),
+        address_family(address_family),
+        interface_index(interface_index) {
+  }
+  net::SocketDescriptor socket;
+  net::AddressFamily address_family;
+  uint32 interface_index;
+};
 
-class ScopedSocketFactorySetter {
+// Returns list of sockets preallocated before.
+class PreCreatedMDnsSocketFactory : public net::MDnsSocketFactory {
  public:
-  ScopedSocketFactorySetter() {
-    net::PlatformSocketFactory::SetInstance(
-        &g_local_discovery_socket_factory.Get());
+  PreCreatedMDnsSocketFactory() {}
+  ~PreCreatedMDnsSocketFactory() override {
+    // Not empty if process exits too fast, before starting mDns code. If
+    // happened, destructors may crash accessing destroyed global objects.
+    sockets_.weak_clear();
   }
 
-  ~ScopedSocketFactorySetter() {
-    net::PlatformSocketFactory::SetInstance(NULL);
-    g_local_discovery_socket_factory.Get().Reset();
+  // net::MDnsSocketFactory implementation:
+  void CreateSockets(
+      ScopedVector<net::DatagramServerSocket>* sockets) override {
+    sockets->swap(sockets_);
+    Reset();
+  }
+
+  void AddSocket(const SocketInfo& socket_info) {
+    // Takes ownership of socket_info.socket;
+    ScopedSocketFactory platform_factory(socket_info.socket);
+    scoped_ptr<net::DatagramServerSocket> socket(
+        net::CreateAndBindMDnsSocket(socket_info.address_family,
+                                     socket_info.interface_index));
+    if (socket) {
+      socket->DetachFromThread();
+      sockets_.push_back(socket.release());
+    }
+  }
+
+  void Reset() {
+    sockets_.clear();
   }
 
  private:
-  DISALLOW_COPY_AND_ASSIGN(ScopedSocketFactorySetter);
+  ScopedVector<net::DatagramServerSocket> sockets_;
+
+  DISALLOW_COPY_AND_ASSIGN(PreCreatedMDnsSocketFactory);
 };
 
+base::LazyInstance<PreCreatedMDnsSocketFactory>
+    g_local_discovery_socket_factory = LAZY_INSTANCE_INITIALIZER;
+
 #if defined(OS_WIN)
 
 void ClosePlatformSocket(net::SocketDescriptor socket) {
@@ -95,9 +111,17 @@ void ClosePlatformSocket(net::SocketDescriptor socket) {
 }
 
 void StaticInitializeSocketFactory() {
-  g_local_discovery_socket_factory.Get().SetSockets(
-      net::CreatePlatformSocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP),
-      net::CreatePlatformSocket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP));
+  net::InterfaceIndexFamilyList interfaces(net::GetMDnsInterfacesToBind());
+  for (size_t i = 0; i < interfaces.size(); ++i) {
+    DCHECK(interfaces[i].second == net::ADDRESS_FAMILY_IPV4 ||
+           interfaces[i].second == net::ADDRESS_FAMILY_IPV6);
+    net::SocketDescriptor descriptor =
+        net::CreatePlatformSocket(
+            net::ConvertAddressFamily(interfaces[i].second), SOCK_DGRAM,
+                                      IPPROTO_UDP);
+    g_local_discovery_socket_factory.Get().AddSocket(
+        SocketInfo(descriptor, interfaces[i].second, interfaces[i].first));
+  }
 }
 
 #else  // OS_WIN
@@ -159,14 +183,14 @@ void ServiceDiscoveryMessageHandler::InitializeMdns() {
     return;
 
   mdns_client_ = net::MDnsClient::CreateDefault();
-  {
-    // Temporarily redirect network code to use pre-created sockets.
-    ScopedSocketFactorySetter socket_factory_setter;
-    if (!mdns_client_->StartListening()) {
-      VLOG(1) << "Failed to start MDnsClient";
-      Send(new LocalDiscoveryHostMsg_Error());
-      return;
-    }
+  bool result =
+      mdns_client_->StartListening(g_local_discovery_socket_factory.Pointer());
+  // Close unused sockets.
+  g_local_discovery_socket_factory.Get().Reset();
+  if (!result) {
+    VLOG(1) << "Failed to start MDnsClient";
+    Send(new LocalDiscoveryHostMsg_Error());
+    return;
   }
 
   service_discovery_client_.reset(
@@ -174,7 +198,7 @@ void ServiceDiscoveryMessageHandler::InitializeMdns() {
 }
 
 bool ServiceDiscoveryMessageHandler::InitializeThread() {
-  if (discovery_task_runner_)
+  if (discovery_task_runner_.get())
     return true;
   if (discovery_thread_)
     return false;
@@ -187,7 +211,7 @@ bool ServiceDiscoveryMessageHandler::InitializeThread() {
         base::Bind(&ServiceDiscoveryMessageHandler::InitializeMdns,
                     base::Unretained(this)));
   }
-  return discovery_task_runner_ != NULL;
+  return discovery_task_runner_.get() != NULL;
 }
 
 bool ServiceDiscoveryMessageHandler::OnMessageReceived(
@@ -199,6 +223,8 @@ bool ServiceDiscoveryMessageHandler::OnMessageReceived(
 #endif  // OS_POSIX
     IPC_MESSAGE_HANDLER(LocalDiscoveryMsg_StartWatcher, OnStartWatcher)
     IPC_MESSAGE_HANDLER(LocalDiscoveryMsg_DiscoverServices, OnDiscoverServices)
+    IPC_MESSAGE_HANDLER(LocalDiscoveryMsg_SetActivelyRefreshServices,
+                        OnSetActivelyRefreshServices)
     IPC_MESSAGE_HANDLER(LocalDiscoveryMsg_DestroyWatcher, OnDestroyWatcher)
     IPC_MESSAGE_HANDLER(LocalDiscoveryMsg_ResolveService, OnResolveService)
     IPC_MESSAGE_HANDLER(LocalDiscoveryMsg_DestroyResolver, OnDestroyResolver)
@@ -223,9 +249,12 @@ void ServiceDiscoveryMessageHandler::PostTask(
 
 #if defined(OS_POSIX)
 void ServiceDiscoveryMessageHandler::OnSetSockets(
-    const base::FileDescriptor& socket_v4,
-    const base::FileDescriptor& socket_v6) {
-  g_local_discovery_socket_factory.Get().SetSockets(socket_v4.fd, socket_v6.fd);
+    const std::vector<LocalDiscoveryMsg_SocketInfo>& sockets) {
+  for (size_t i = 0; i < sockets.size(); ++i) {
+    g_local_discovery_socket_factory.Get().AddSocket(
+        SocketInfo(sockets[i].descriptor.fd, sockets[i].address_family,
+                   sockets[i].interface_index));
+  }
 }
 #endif  // OS_POSIX
 
@@ -244,6 +273,14 @@ void ServiceDiscoveryMessageHandler::OnDiscoverServices(uint64 id,
                       base::Unretained(this), id, force_update));
 }
 
+void ServiceDiscoveryMessageHandler::OnSetActivelyRefreshServices(
+    uint64 id, bool actively_refresh_services) {
+  PostTask(FROM_HERE,
+           base::Bind(
+               &ServiceDiscoveryMessageHandler::SetActivelyRefreshServices,
+               base::Unretained(this), id, actively_refresh_services));
+}
+
 void ServiceDiscoveryMessageHandler::OnDestroyWatcher(uint64 id) {
   PostTask(FROM_HERE,
            base::Bind(&ServiceDiscoveryMessageHandler::DestroyWatcher,
@@ -304,6 +341,16 @@ void ServiceDiscoveryMessageHandler::DiscoverServices(uint64 id,
   service_watchers_[id]->DiscoverNewServices(force_update);
 }
 
+void ServiceDiscoveryMessageHandler::SetActivelyRefreshServices(
+    uint64 id,
+    bool actively_refresh_services) {
+  VLOG(1) << "ActivelyRefreshServices, id=" << id;
+  if (!service_discovery_client_)
+    return;
+  DCHECK(ContainsKey(service_watchers_, id));
+  service_watchers_[id]->SetActivelyRefreshServices(actively_refresh_services);
+}
+
 void ServiceDiscoveryMessageHandler::DestroyWatcher(uint64 id) {
   VLOG(1) << "DestoryWatcher, id=" << id;
   if (!service_discovery_client_)
@@ -359,7 +406,7 @@ void ServiceDiscoveryMessageHandler::DestroyLocalDomainResolver(uint64 id) {
 }
 
 void ServiceDiscoveryMessageHandler::ShutdownLocalDiscovery() {
-  if (!discovery_task_runner_)
+  if (!discovery_task_runner_.get())
     return;
 
   discovery_task_runner_->PostTask(