#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 {
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) {
}
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
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(
}
bool ServiceDiscoveryMessageHandler::InitializeThread() {
- if (discovery_task_runner_)
+ if (discovery_task_runner_.get())
return true;
if (discovery_thread_)
return false;
base::Bind(&ServiceDiscoveryMessageHandler::InitializeMdns,
base::Unretained(this)));
}
- return discovery_task_runner_ != NULL;
+ return discovery_task_runner_.get() != NULL;
}
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)
#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
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,
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_)
}
void ServiceDiscoveryMessageHandler::ShutdownLocalDiscovery() {
- if (!discovery_task_runner_)
+ if (!discovery_task_runner_.get())
return;
discovery_task_runner_->PostTask(