Revert 225492 "Revert 225155 "Keep running mdns client even if e..."

> Revert 225155 "Keep running mdns client even if either IPv4 or I..."
> 
> BUG=298768
> 
> > Keep running mdns client even if either IPv4 or IPv6 bind failed.
> > 
> > BUG=297212
> > NOTRY=true
> > 
> > Review URL: https://chromiumcodereview.appspot.com/23498056
> 
> [email protected]
> 
> Review URL: https://codereview.chromium.org/24486005

[email protected]

Review URL: https://codereview.chromium.org/24813006

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@225566 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/net/dns/mdns_client_impl.cc b/net/dns/mdns_client_impl.cc
index 4a304684..1dfc21b 100644
--- a/net/dns/mdns_client_impl.cc
+++ b/net/dns/mdns_client_impl.cc
@@ -95,44 +95,51 @@
   return socket_->JoinGroup(multicast_addr_.address());
 }
 
-MDnsConnection::MDnsConnection(MDnsConnection::SocketFactory* socket_factory,
-                               MDnsConnection::Delegate* delegate)
-    : socket_handler_ipv4_(this, GetMDnsIPEndPoint(ADDRESS_FAMILY_IPV4),
-                           socket_factory),
-      socket_handler_ipv6_(this, GetMDnsIPEndPoint(ADDRESS_FAMILY_IPV6),
-                           socket_factory),
+MDnsConnection::MDnsConnection(MDnsConnection::Delegate* delegate) :
       delegate_(delegate) {
 }
 
 MDnsConnection::~MDnsConnection() {
 }
 
-int MDnsConnection::Init() {
-  int rv = socket_handler_ipv4_.Bind();
-  if (rv != OK) return rv;
-  rv = socket_handler_ipv6_.Bind();
-  if (rv != OK) return rv;
+bool MDnsConnection::Init(MDnsConnection::SocketFactory* socket_factory) {
+  // TODO(vitalybuka): crbug.com/297690 Make socket_factory return list
+  // of initialized sockets.
+  socket_handlers_.push_back(
+      new SocketHandler(this, GetMDnsIPEndPoint(ADDRESS_FAMILY_IPV4),
+                        socket_factory));
+  socket_handlers_.push_back(
+      new SocketHandler(this, GetMDnsIPEndPoint(ADDRESS_FAMILY_IPV6),
+                        socket_factory));
+
+  for (size_t i = 0; i < socket_handlers_.size();) {
+    if (socket_handlers_[i]->Bind() != OK) {
+      socket_handlers_.erase(socket_handlers_.begin() + i);
+    } else {
+      ++i;
+    }
+  }
+
   // All unbound sockets need to be bound before processing untrusted input.
   // This is done for security reasons, so that an attacker can't get an unbound
   // socket.
-  rv = socket_handler_ipv4_.Start();
-  if (rv != OK) return rv;
-  rv = socket_handler_ipv6_.Start();
-  if (rv != OK) return rv;
-
-  return OK;
+  for (size_t i = 0; i < socket_handlers_.size();) {
+    if (socket_handlers_[i]->Start() != OK) {
+      socket_handlers_.erase(socket_handlers_.begin() + i);
+    } else {
+      ++i;
+    }
+  }
+  return !socket_handlers_.empty();
 }
 
-int MDnsConnection::Send(IOBuffer* buffer, unsigned size) {
-  int rv;
-
-  rv = socket_handler_ipv4_.Send(buffer, size);
-  if (rv < OK && rv != ERR_IO_PENDING) return rv;
-
-  rv = socket_handler_ipv6_.Send(buffer, size);
-  if (rv < OK && rv != ERR_IO_PENDING) return rv;
-
-  return OK;
+bool MDnsConnection::Send(IOBuffer* buffer, unsigned size) {
+  bool success = false;
+  for (size_t i = 0; i < socket_handlers_.size(); ++i) {
+    int rv = socket_handlers_[i]->Send(buffer, size);
+    success = success || (rv >= OK || rv == ERR_IO_PENDING);
+  }
+  return success;
 }
 
 void MDnsConnection::OnError(SocketHandler* loop,
@@ -179,17 +186,16 @@
       new MDnsConnectionSocketFactoryImpl);
 }
 
-MDnsClientImpl::Core::Core(MDnsClientImpl* client,
-                           MDnsConnection::SocketFactory* socket_factory)
-    : client_(client), connection_(new MDnsConnection(socket_factory, this)) {
+MDnsClientImpl::Core::Core(MDnsClientImpl* client)
+    : client_(client), connection_(new MDnsConnection(this)) {
 }
 
 MDnsClientImpl::Core::~Core() {
   STLDeleteValues(&listeners_);
 }
 
-bool MDnsClientImpl::Core::Init() {
-  return connection_->Init() == OK;
+bool MDnsClientImpl::Core::Init(MDnsConnection::SocketFactory* socket_factory) {
+  return connection_->Init(socket_factory);
 }
 
 bool MDnsClientImpl::Core::SendQuery(uint16 rrtype, std::string name) {
@@ -200,7 +206,7 @@
   DnsQuery query(0, name_dns, rrtype);
   query.set_flags(0);  // Remove the RD flag from the query. It is unneeded.
 
-  return connection_->Send(query.io_buffer(), query.io_buffer()->size()) == OK;
+  return connection_->Send(query.io_buffer(), query.io_buffer()->size());
 }
 
 void MDnsClientImpl::Core::HandlePacket(DnsResponse* response,
@@ -429,8 +435,8 @@
 
 bool MDnsClientImpl::StartListening() {
   DCHECK(!core_.get());
-  core_.reset(new Core(this, socket_factory_.get()));
-  if (!core_->Init()) {
+  core_.reset(new Core(this));
+  if (!core_->Init(socket_factory_.get())) {
     core_.reset();
     return false;
   }
diff --git a/net/dns/mdns_client_impl.h b/net/dns/mdns_client_impl.h
index cbb9f6d..b69677b 100644
--- a/net/dns/mdns_client_impl.h
+++ b/net/dns/mdns_client_impl.h
@@ -11,6 +11,7 @@
 #include <vector>
 
 #include "base/cancelable_callback.h"
+#include "base/memory/scoped_vector.h"
 #include "base/observer_list.h"
 #include "net/base/io_buffer.h"
 #include "net/base/ip_endpoint.h"
@@ -43,13 +44,13 @@
     virtual ~Delegate() {}
   };
 
-  explicit MDnsConnection(SocketFactory* socket_factory,
-                          MDnsConnection::Delegate* delegate);
+  explicit MDnsConnection(MDnsConnection::Delegate* delegate);
 
   virtual ~MDnsConnection();
 
-  int Init();
-  int Send(IOBuffer* buffer, unsigned size);
+  // Both methods return true if at least one of the socket handlers succeeded.
+  bool Init(MDnsConnection::SocketFactory* socket_factory);
+  bool Send(IOBuffer* buffer, unsigned size);
 
  private:
   class SocketHandler {
@@ -85,8 +86,8 @@
 
   void OnError(SocketHandler* loop, int error);
 
-  SocketHandler socket_handler_ipv4_;
-  SocketHandler socket_handler_ipv6_;
+  // Only socket handlers which successfully bound and started are kept.
+  ScopedVector<SocketHandler> socket_handlers_;
 
   Delegate* delegate_;
 
@@ -103,12 +104,11 @@
   // invalidate the core.
   class Core : public base::SupportsWeakPtr<Core>, MDnsConnection::Delegate {
    public:
-    Core(MDnsClientImpl* client,
-         MDnsConnection::SocketFactory* socket_factory);
+    explicit Core(MDnsClientImpl* client);
     virtual ~Core();
 
     // Initialize the core. Returns true on success.
-    bool Init();
+    bool Init(MDnsConnection::SocketFactory* socket_factory);
 
     // Send a query with a specific rrtype and name. Returns true on success.
     bool SendQuery(uint16 rrtype, std::string name);
diff --git a/net/dns/mdns_client_unittest.cc b/net/dns/mdns_client_unittest.cc
index 324b4df..f524a54 100644
--- a/net/dns/mdns_client_unittest.cc
+++ b/net/dns/mdns_client_unittest.cc
@@ -1025,24 +1025,17 @@
   }
 
   virtual scoped_ptr<DatagramServerSocket> CreateSocket() OVERRIDE {
-    scoped_ptr<MockMDnsDatagramServerSocket> socket(
-        new StrictMock<MockMDnsDatagramServerSocket>);
-    sockets_.push(socket.get());
-    return socket.PassAs<DatagramServerSocket>();
+    MockMDnsDatagramServerSocket* socket = sockets_.back();
+    sockets_.weak_erase(sockets_.end() - 1);
+    return scoped_ptr<DatagramServerSocket>(socket);
   }
 
-  MockMDnsDatagramServerSocket* PopFirstSocket() {
-    MockMDnsDatagramServerSocket* socket = sockets_.front();
-    sockets_.pop();
-    return socket;
-  }
-
-  size_t num_sockets() {
-    return sockets_.size();
+  void PushSocket(MockMDnsDatagramServerSocket* socket) {
+    sockets_.push_back(socket);
   }
 
  private:
-  std::queue<MockMDnsDatagramServerSocket*> sockets_;
+  ScopedVector<MockMDnsDatagramServerSocket> sockets_;
 };
 
 class MockMDnsConnectionDelegate : public MDnsConnection::Delegate {
@@ -1058,16 +1051,16 @@
 
 class MDnsConnectionTest : public ::testing::Test {
  public:
-  MDnsConnectionTest() : connection_(&factory_, &delegate_) {
+  MDnsConnectionTest() : connection_(&delegate_) {
   }
 
  protected:
   // Follow successful connection initialization.
   virtual void SetUp() OVERRIDE {
-    ASSERT_EQ(2u, factory_.num_sockets());
-
-    socket_ipv4_ = factory_.PopFirstSocket();
-    socket_ipv6_ = factory_.PopFirstSocket();
+    socket_ipv4_ = new MockMDnsDatagramServerSocket;
+    socket_ipv6_ = new MockMDnsDatagramServerSocket;
+    factory_.PushSocket(socket_ipv6_);
+    factory_.PushSocket(socket_ipv4_);
   }
 
   bool InitConnection() {
@@ -1087,7 +1080,7 @@
     EXPECT_CALL(*socket_ipv6_, JoinGroupInternal("ff02::fb"))
         .WillOnce(Return(OK));
 
-    return connection_.Init() == OK;
+    return connection_.Init(&factory_);
   }
 
   StrictMock<MockMDnsConnectionDelegate> delegate_;