Initially when the design was to do this experiment in browser, which doesn't have webrtc code, it requires some glue code to bridge the difference between what's available in webrtc::base and browser process. Now since we're moving to renderer process, we could reuse a lot of existing interfaces instead of rolling our own.

BUG=webrtc:4576
R=pthatcher@webrtc.org

Review URL: https://codereview.webrtc.org/1173353002.

Cr-Commit-Position: refs/heads/master@{#9466}
diff --git a/webrtc/base/asyncinvoker.cc b/webrtc/base/asyncinvoker.cc
index 35ce2fb..56f1a19 100644
--- a/webrtc/base/asyncinvoker.cc
+++ b/webrtc/base/asyncinvoker.cc
@@ -64,6 +64,18 @@
   thread->Post(this, id, new ScopedRefMessageData<AsyncClosure>(closure));
 }
 
+void AsyncInvoker::DoInvokeDelayed(Thread* thread,
+                                   const scoped_refptr<AsyncClosure>& closure,
+                                   uint32 delay_ms,
+                                   uint32 id) {
+  if (destroying_) {
+    LOG(LS_WARNING) << "Tried to invoke while destroying the invoker.";
+    return;
+  }
+  thread->PostDelayed(delay_ms, this, id,
+                      new ScopedRefMessageData<AsyncClosure>(closure));
+}
+
 NotifyingAsyncClosureBase::NotifyingAsyncClosureBase(AsyncInvoker* invoker,
                                                      Thread* calling_thread)
     : invoker_(invoker), calling_thread_(calling_thread) {
diff --git a/webrtc/base/asyncinvoker.h b/webrtc/base/asyncinvoker.h
index 6e298e6..fe1506d 100644
--- a/webrtc/base/asyncinvoker.h
+++ b/webrtc/base/asyncinvoker.h
@@ -82,6 +82,18 @@
     DoInvoke(thread, closure, id);
   }
 
+  // Call |functor| asynchronously on |thread| with |delay_ms|, with no callback
+  // upon completion. Returns immediately.
+  template <class ReturnT, class FunctorT>
+  void AsyncInvokeDelayed(Thread* thread,
+                          const FunctorT& functor,
+                          uint32 delay_ms,
+                          uint32 id = 0) {
+    scoped_refptr<AsyncClosure> closure(
+        new RefCountedObject<FireAndForgetAsyncClosure<FunctorT> >(functor));
+    DoInvokeDelayed(thread, closure, delay_ms, id);
+  }
+
   // Call |functor| asynchronously on |thread|, calling |callback| when done.
   template <class ReturnT, class FunctorT, class HostT>
   void AsyncInvoke(Thread* thread,
@@ -123,7 +135,10 @@
   void OnMessage(Message* msg) override;
   void DoInvoke(Thread* thread, const scoped_refptr<AsyncClosure>& closure,
                 uint32 id);
-
+  void DoInvokeDelayed(Thread* thread,
+                       const scoped_refptr<AsyncClosure>& closure,
+                       uint32 delay_ms,
+                       uint32 id);
   bool destroying_;
 
   DISALLOW_COPY_AND_ASSIGN(AsyncInvoker);
diff --git a/webrtc/base/base.gyp b/webrtc/base/base.gyp
index cc1ebf4..66571f8 100644
--- a/webrtc/base/base.gyp
+++ b/webrtc/base/base.gyp
@@ -375,9 +375,6 @@
             '../../boringssl/src/include',
           ],
           'sources!': [
-            'asyncinvoker.cc',
-            'asyncinvoker.h',
-            'asyncinvoker-inl.h',
             'atomicops.h',
             'bandwidthsmoother.cc',
             'bandwidthsmoother.h',
diff --git a/webrtc/p2p/stunprober/main.cc b/webrtc/p2p/stunprober/main.cc
index 99f66ca..076113c 100644
--- a/webrtc/p2p/stunprober/main.cc
+++ b/webrtc/p2p/stunprober/main.cc
@@ -14,29 +14,22 @@
 
 #include <iostream>
 #include <map>
-
 #include "webrtc/base/checks.h"
 #include "webrtc/base/flags.h"
 #include "webrtc/base/helpers.h"
 #include "webrtc/base/nethelpers.h"
+#include "webrtc/base/network.h"
 #include "webrtc/base/logging.h"
 #include "webrtc/base/scoped_ptr.h"
 #include "webrtc/base/ssladapter.h"
 #include "webrtc/base/stringutils.h"
 #include "webrtc/base/thread.h"
 #include "webrtc/base/timeutils.h"
+#include "webrtc/p2p/base/basicpacketsocketfactory.cc"
 #include "webrtc/p2p/stunprober/stunprober.h"
-#include "webrtc/p2p/stunprober/stunprober_dependencies.h"
 
-using stunprober::HostNameResolverInterface;
-using stunprober::TaskRunner;
-using stunprober::SocketFactory;
 using stunprober::StunProber;
 using stunprober::AsyncCallback;
-using stunprober::ClientSocketInterface;
-using stunprober::ServerSocketInterface;
-using stunprober::SocketFactory;
-using stunprober::TaskRunner;
 
 DEFINE_bool(help, false, "Prints this message");
 DEFINE_int(interval, 10, "Interval of consecutive stun pings in milliseconds");
@@ -54,58 +47,6 @@
 
 namespace {
 
-class HostNameResolver : public HostNameResolverInterface,
-                         public sigslot::has_slots<> {
- public:
-  HostNameResolver() {}
-  virtual ~HostNameResolver() {}
-
-  void Resolve(const rtc::SocketAddress& addr,
-               std::vector<rtc::SocketAddress>* addresses,
-               AsyncCallback callback) override {
-    resolver_ = new rtc::AsyncResolver();
-    DCHECK(callback_.empty());
-    addr_ = addr;
-    callback_ = callback;
-    result_ = addresses;
-    resolver_->SignalDone.connect(this, &HostNameResolver::OnResolveResult);
-    resolver_->Start(addr);
-  }
-
-  void OnResolveResult(rtc::AsyncResolverInterface* resolver) {
-    DCHECK(resolver);
-    int rv = resolver_->GetError();
-    LOG(LS_INFO) << "ResolveResult for " << addr_.ToString() << " : " << rv;
-    if (rv == 0 && result_) {
-      for (auto addr : resolver_->addresses()) {
-        rtc::SocketAddress ip(addr, addr_.port());
-        result_->push_back(ip);
-        LOG(LS_INFO) << "\t" << ip.ToString();
-      }
-    }
-    if (!callback_.empty()) {
-      // Need to be the last statement as the object could be deleted by the
-      // callback_ in the failure case.
-      AsyncCallback callback = callback_;
-      callback_ = AsyncCallback();
-
-      // rtc::AsyncResolver inherits from SignalThread which requires explicit
-      // Release().
-      resolver_->Release();
-      resolver_ = nullptr;
-      callback(rv);
-    }
-  }
-
- private:
-  AsyncCallback callback_;
-  rtc::SocketAddress addr_;
-  std::vector<rtc::SocketAddress>* result_;
-
-  // Not using smart ptr here as this requires specific release pattern.
-  rtc::AsyncResolver* resolver_;
-};
-
 const char* PrintNatType(stunprober::NatType type) {
   switch (type) {
     case stunprober::NATTYPE_NONE:
@@ -178,10 +119,17 @@
   rtc::InitializeSSL();
   rtc::InitRandom(rtc::Time());
   rtc::Thread* thread = rtc::ThreadManager::Instance()->WrapCurrentThread();
-  StunProber* prober = new StunProber(new HostNameResolver(),
-                                      new SocketFactory(), new TaskRunner());
-  auto finish_callback =
-      [thread, prober](int result) { StopTrial(thread, prober, result); };
+  rtc::scoped_ptr<rtc::BasicPacketSocketFactory> socket_factory(
+      new rtc::BasicPacketSocketFactory());
+  rtc::scoped_ptr<rtc::BasicNetworkManager> network_manager(
+      new rtc::BasicNetworkManager());
+  rtc::NetworkManager::NetworkList networks;
+  network_manager->GetNetworks(&networks);
+  StunProber* prober =
+      new StunProber(socket_factory.get(), rtc::Thread::Current(), networks);
+  auto finish_callback = [thread](StunProber* prober, int result) {
+    StopTrial(thread, prober, result);
+  };
   prober->Start(server_addresses, FLAG_shared_socket, FLAG_interval,
                 FLAG_pings_per_ip, FLAG_timeout,
                 AsyncCallback(finish_callback));
diff --git a/webrtc/p2p/stunprober/stunprober.cc b/webrtc/p2p/stunprober/stunprober.cc
index 8efe069..4a33444 100644
--- a/webrtc/p2p/stunprober/stunprober.cc
+++ b/webrtc/p2p/stunprober/stunprober.cc
@@ -13,10 +13,15 @@
 #include <set>
 #include <string>
 
+#include "webrtc/base/asyncpacketsocket.h"
+#include "webrtc/base/asyncresolverinterface.h"
 #include "webrtc/base/bind.h"
 #include "webrtc/base/checks.h"
 #include "webrtc/base/helpers.h"
+#include "webrtc/base/logging.h"
 #include "webrtc/base/timeutils.h"
+#include "webrtc/base/thread.h"
+#include "webrtc/p2p/base/packetsocketfactory.h"
 #include "webrtc/p2p/base/stun.h"
 #include "webrtc/p2p/stunprober/stunprober.h"
 
@@ -24,20 +29,18 @@
 
 namespace {
 
+const int thread_wake_up_interval_ms = 5;
+
 template <typename T>
 void IncrementCounterByAddress(std::map<T, int>* counter_per_ip, const T& ip) {
   counter_per_ip->insert(std::make_pair(ip, 0)).first->second++;
 }
 
-bool behind_nat(NatType nat_type) {
-  return nat_type > stunprober::NATTYPE_NONE;
-}
-
 }  // namespace
 
 // A requester tracks the requests and responses from a single socket to many
 // STUN servers
-class StunProber::Requester {
+class StunProber::Requester : public sigslot::has_slots<> {
  public:
   // Each Request maps to a request and response.
   struct Request {
@@ -46,26 +49,20 @@
     // Time the response was received.
     int64 received_time_ms = 0;
 
-    // See whether the observed address returned matches the
-    // local address as in StunProber.local_addr_.
-    bool behind_nat = false;
-
     // Server reflexive address from STUN response for this given request.
     rtc::SocketAddress srflx_addr;
 
     rtc::IPAddress server_addr;
 
     int64 rtt() { return received_time_ms - sent_time_ms; }
-    void ProcessResponse(rtc::ByteBuffer* message,
-                         int buf_len,
-                         const rtc::IPAddress& local_addr);
+    void ProcessResponse(const char* buf, size_t buf_len);
   };
 
   // StunProber provides |server_ips| for Requester to probe. For shared
   // socket mode, it'll be all the resolved IP addresses. For non-shared mode,
   // it'll just be a single address.
   Requester(StunProber* prober,
-            ServerSocketInterface* socket,
+            rtc::AsyncPacketSocket* socket,
             const std::vector<rtc::SocketAddress>& server_ips);
   virtual ~Requester();
 
@@ -74,11 +71,11 @@
   // and move to the next one.
   void SendStunRequest();
 
-  void ReadStunResponse();
-
-  // |result| is the positive return value from RecvFrom when data is
-  // available.
-  void OnStunResponseReceived(int result);
+  void OnStunResponseReceived(rtc::AsyncPacketSocket* socket,
+                              const char* buf,
+                              size_t size,
+                              const rtc::SocketAddress& addr,
+                              const rtc::PacketTime& time);
 
   const std::vector<Request*>& requests() { return requests_; }
 
@@ -93,7 +90,7 @@
   StunProber* prober_;
 
   // The socket for this session.
-  rtc::scoped_ptr<ServerSocketInterface> socket_;
+  rtc::scoped_ptr<rtc::AsyncPacketSocket> socket_;
 
   // Temporary SocketAddress and buffer for RecvFrom.
   rtc::SocketAddress addr_;
@@ -111,13 +108,15 @@
 
 StunProber::Requester::Requester(
     StunProber* prober,
-    ServerSocketInterface* socket,
+    rtc::AsyncPacketSocket* socket,
     const std::vector<rtc::SocketAddress>& server_ips)
     : prober_(prober),
       socket_(socket),
       response_packet_(new rtc::ByteBuffer(nullptr, kMaxUdpBufferSize)),
       server_ips_(server_ips),
       thread_checker_(prober->thread_checker_) {
+  socket_->SignalReadPacket.connect(
+      this, &StunProber::Requester::OnStunResponseReceived);
 }
 
 StunProber::Requester::~Requester() {
@@ -145,7 +144,7 @@
   rtc::scoped_ptr<rtc::ByteBuffer> request_packet(
       new rtc::ByteBuffer(nullptr, kMaxUdpBufferSize));
   if (!message.Write(request_packet.get())) {
-    prober_->End(WRITE_FAILED, 0);
+    prober_->End(WRITE_FAILED);
     return;
   }
 
@@ -155,48 +154,26 @@
   // The write must succeed immediately. Otherwise, the calculating of the STUN
   // request timing could become too complicated. Callback is ignored by passing
   // empty AsyncCallback.
-  int rv = socket_->SendTo(addr, const_cast<char*>(request_packet->Data()),
-                           request_packet->Length(), AsyncCallback());
+  rtc::PacketOptions options;
+  int rv = socket_->SendTo(const_cast<char*>(request_packet->Data()),
+                           request_packet->Length(), addr, options);
   if (rv < 0) {
-    prober_->End(WRITE_FAILED, rv);
+    prober_->End(WRITE_FAILED);
     return;
   }
 
   request.sent_time_ms = rtc::Time();
 
-  // Post a read waiting for response. For share mode, the subsequent read will
-  // be posted inside OnStunResponseReceived.
-  if (num_request_sent_ == 0) {
-    ReadStunResponse();
-  }
-
   num_request_sent_++;
   DCHECK(static_cast<size_t>(num_request_sent_) <= server_ips_.size());
 }
 
-void StunProber::Requester::ReadStunResponse() {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  if (!socket_) {
-    return;
-  }
-
-  int rv = socket_->RecvFrom(
-      response_packet_->ReserveWriteBuffer(kMaxUdpBufferSize),
-      kMaxUdpBufferSize, &addr_,
-      [this](int result) { this->OnStunResponseReceived(result); });
-  if (rv != SocketInterface::IO_PENDING) {
-    OnStunResponseReceived(rv);
-  }
-}
-
-void StunProber::Requester::Request::ProcessResponse(
-    rtc::ByteBuffer* message,
-    int buf_len,
-    const rtc::IPAddress& local_addr) {
+void StunProber::Requester::Request::ProcessResponse(const char* buf,
+                                                     size_t buf_len) {
   int64 now = rtc::Time();
-
+  rtc::ByteBuffer message(buf, buf_len);
   cricket::StunMessage stun_response;
-  if (!stun_response.Read(message)) {
+  if (!stun_response.Read(&message)) {
     // Invalid or incomplete STUN packet.
     received_time_ms = 0;
     return;
@@ -218,40 +195,25 @@
   received_time_ms = now;
 
   srflx_addr = addr_attr->GetAddress();
-
-  // Calculate behind_nat.
-  behind_nat = (srflx_addr.ipaddr() != local_addr);
 }
 
-void StunProber::Requester::OnStunResponseReceived(int result) {
+void StunProber::Requester::OnStunResponseReceived(
+    rtc::AsyncPacketSocket* socket,
+    const char* buf,
+    size_t size,
+    const rtc::SocketAddress& addr,
+    const rtc::PacketTime& time) {
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(socket_);
-
-  if (result < 0) {
-    // Something is wrong, finish the test.
-    prober_->End(READ_FAILED, result);
-    return;
-  }
-
-  Request* request = GetRequestByAddress(addr_.ipaddr());
+  Request* request = GetRequestByAddress(addr.ipaddr());
   if (!request) {
     // Something is wrong, finish the test.
-    prober_->End(GENERIC_FAILURE, result);
+    prober_->End(GENERIC_FAILURE);
     return;
   }
 
   num_response_received_++;
-
-  // Resize will set the end_ to indicate that there are data available in this
-  // ByteBuffer.
-  response_packet_->Resize(result);
-  request->ProcessResponse(response_packet_.get(), result,
-                           prober_->local_addr_);
-
-  if (static_cast<size_t>(num_response_received_) < server_ips_.size()) {
-    // Post another read response.
-    ReadStunResponse();
-  }
+  request->ProcessResponse(buf, size);
 }
 
 StunProber::Requester::Request* StunProber::Requester::GetRequestByAddress(
@@ -266,13 +228,13 @@
   return nullptr;
 }
 
-StunProber::StunProber(HostNameResolverInterface* host_name_resolver,
-                       SocketFactoryInterface* socket_factory,
-                       TaskRunnerInterface* task_runner)
+StunProber::StunProber(rtc::PacketSocketFactory* socket_factory,
+                       rtc::Thread* thread,
+                       const rtc::NetworkManager::NetworkList& networks)
     : interval_ms_(0),
       socket_factory_(socket_factory),
-      resolver_(host_name_resolver),
-      task_runner_(task_runner) {
+      thread_(thread),
+      networks_(networks) {
 }
 
 StunProber::~StunProber() {
@@ -281,6 +243,11 @@
       delete req;
     }
   }
+  for (auto s : sockets_) {
+    if (s) {
+      delete s;
+    }
+  }
 }
 
 bool StunProber::Start(const std::vector<rtc::SocketAddress>& servers,
@@ -301,92 +268,98 @@
   timeout_ms_ = timeout_ms;
   servers_ = servers;
   finished_callback_ = callback;
-  resolver_->Resolve(servers_[0], &resolved_ips_,
-                     [this](int result) { this->OnServerResolved(0, result); });
+  return ResolveServerName(servers_.back());
+}
+
+bool StunProber::ResolveServerName(const rtc::SocketAddress& addr) {
+  rtc::AsyncResolverInterface* resolver =
+      socket_factory_->CreateAsyncResolver();
+  if (!resolver) {
+    return false;
+  }
+  resolver->SignalDone.connect(this, &StunProber::OnServerResolved);
+  resolver->Start(addr);
   return true;
 }
 
-void StunProber::OnServerResolved(int index, int result) {
+void StunProber::OnSocketReady(rtc::AsyncPacketSocket* socket,
+                               const rtc::SocketAddress& addr) {
+  total_ready_sockets_++;
+  if (total_ready_sockets_ == total_socket_required()) {
+    MaybeScheduleStunRequests();
+  }
+}
+
+void StunProber::OnServerResolved(rtc::AsyncResolverInterface* resolver) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
-  if (result == 0) {
-    all_servers_ips_.insert(all_servers_ips_.end(), resolved_ips_.begin(),
-                            resolved_ips_.end());
-    resolved_ips_.clear();
+  if (resolver->GetError() == 0) {
+    rtc::SocketAddress addr(resolver->address().ipaddr(),
+                            resolver->address().port());
+    all_servers_addrs_.push_back(addr);
   }
 
-  index++;
+  // Deletion of AsyncResolverInterface can't be done in OnResolveResult which
+  // handles SignalDone.
+  invoker_.AsyncInvoke<void>(
+      thread_,
+      rtc::Bind(&rtc::AsyncResolverInterface::Destroy, resolver, false));
+  servers_.pop_back();
 
-  if (static_cast<size_t>(index) < servers_.size()) {
-    resolver_->Resolve(
-        servers_[index], &resolved_ips_,
-        [this, index](int result) { this->OnServerResolved(index, result); });
+  if (servers_.size()) {
+    if (!ResolveServerName(servers_.back())) {
+      End(RESOLVE_FAILED);
+    }
     return;
   }
 
-  if (all_servers_ips_.size() == 0) {
-    End(RESOLVE_FAILED, result);
+  if (all_servers_addrs_.size() == 0) {
+    End(RESOLVE_FAILED);
     return;
   }
 
   // Dedupe.
-  std::set<rtc::SocketAddress> addrs(all_servers_ips_.begin(),
-                                     all_servers_ips_.end());
-  all_servers_ips_.assign(addrs.begin(), addrs.end());
+  std::set<rtc::SocketAddress> addrs(all_servers_addrs_.begin(),
+                                     all_servers_addrs_.end());
+  all_servers_addrs_.assign(addrs.begin(), addrs.end());
 
-  rtc::IPAddress addr;
-  if (GetLocalAddress(&addr) != 0) {
-    End(GENERIC_FAILURE, result);
-    return;
-  }
-
-  socket_factory_->Prepare(GetTotalClientSockets(), GetTotalServerSockets(),
-                           [this](int result) {
-                             if (result == 0) {
-                               this->MaybeScheduleStunRequests();
-                             }
-                           });
-}
-
-int StunProber::GetLocalAddress(rtc::IPAddress* addr) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  if (local_addr_.family() == AF_UNSPEC) {
-    rtc::SocketAddress sock_addr;
-    rtc::scoped_ptr<ClientSocketInterface> socket(
-        socket_factory_->CreateClientSocket());
-    int rv = socket->Connect(all_servers_ips_[0]);
-    if (rv != SUCCESS) {
-      End(GENERIC_FAILURE, rv);
-      return rv;
+  // Prepare all the sockets beforehand. All of them will bind to "any" address.
+  while (sockets_.size() < total_socket_required()) {
+    rtc::scoped_ptr<rtc::AsyncPacketSocket> socket(
+        socket_factory_->CreateUdpSocket(rtc::SocketAddress(INADDR_ANY, 0), 0,
+                                         0));
+    if (!socket) {
+      End(GENERIC_FAILURE);
+      return;
     }
-    rv = socket->GetLocalAddress(&sock_addr);
-    if (rv != SUCCESS) {
-      End(GENERIC_FAILURE, rv);
-      return rv;
+    // Chrome and WebRTC behave differently in terms of the state of a socket
+    // once returned from PacketSocketFactory::CreateUdpSocket.
+    if (socket->GetState() == rtc::AsyncPacketSocket::STATE_BINDING) {
+      socket->SignalAddressReady.connect(this, &StunProber::OnSocketReady);
+    } else {
+      OnSocketReady(socket.get(), rtc::SocketAddress(INADDR_ANY, 0));
     }
-    local_addr_ = sock_addr.ipaddr();
-    socket->Close();
+    sockets_.push_back(socket.release());
   }
-  *addr = local_addr_;
-  return 0;
 }
 
 StunProber::Requester* StunProber::CreateRequester() {
   DCHECK(thread_checker_.CalledOnValidThread());
-  rtc::scoped_ptr<ServerSocketInterface> socket(
-      socket_factory_->CreateServerSocket(kMaxUdpBufferSize,
-                                          kMaxUdpBufferSize));
-  if (!socket) {
+  if (!sockets_.size()) {
     return nullptr;
   }
+  StunProber::Requester* requester;
   if (shared_socket_mode_) {
-    return new Requester(this, socket.release(), all_servers_ips_);
+    requester = new Requester(this, sockets_.back(), all_servers_addrs_);
   } else {
     std::vector<rtc::SocketAddress> server_ip;
     server_ip.push_back(
-        all_servers_ips_[(num_request_sent_ % all_servers_ips_.size())]);
-    return new Requester(this, socket.release(), server_ip);
+        all_servers_addrs_[(num_request_sent_ % all_servers_addrs_.size())]);
+    requester = new Requester(this, sockets_.back(), server_ip);
   }
+
+  sockets_.pop_back();
+  return requester;
 }
 
 bool StunProber::SendNextRequest() {
@@ -407,19 +380,20 @@
   uint32 now = rtc::Time();
 
   if (Done()) {
-    task_runner_->PostTask(rtc::Bind(&StunProber::End, this, SUCCESS, 0),
-                           timeout_ms_);
+    invoker_.AsyncInvokeDelayed<void>(
+        thread_, rtc::Bind(&StunProber::End, this, SUCCESS), timeout_ms_);
     return;
   }
-  if (now >= next_request_time_ms_) {
+  if ((now + (thread_wake_up_interval_ms / 2)) >= next_request_time_ms_) {
     if (!SendNextRequest()) {
-      End(GENERIC_FAILURE, 0);
+      End(GENERIC_FAILURE);
       return;
     }
     next_request_time_ms_ = now + interval_ms_;
   }
-  task_runner_->PostTask(
-      rtc::Bind(&StunProber::MaybeScheduleStunRequests, this), 1 /* ms */);
+  invoker_.AsyncInvokeDelayed<void>(
+      thread_, rtc::Bind(&StunProber::MaybeScheduleStunRequests, this),
+      thread_wake_up_interval_ms /* ms */);
 }
 
 bool StunProber::GetStats(StunProber::Stats* prob_stats) const {
@@ -464,14 +438,7 @@
       IncrementCounterByAddress(&num_response_per_server, request->server_addr);
       IncrementCounterByAddress(&num_response_per_srflx_addr,
                                 request->srflx_addr);
-
       rtt_sum += request->rtt();
-      if (nat_type == NATTYPE_INVALID) {
-        nat_type = request->behind_nat ? NATTYPE_UNKNOWN : NATTYPE_NONE;
-      } else if (behind_nat(nat_type) != request->behind_nat) {
-        // Detect the inconsistency in NAT presence.
-        return false;
-      }
       stats.srflx_addrs.insert(request->srflx_addr.ToString());
       srflx_ips.insert(request->srflx_addr.ipaddr());
     }
@@ -505,18 +472,34 @@
     return false;
   }
 
-  stats.nat_type = nat_type;
-
   // Shared mode is only true if we use the shared socket and there are more
   // than 1 responding servers.
   stats.shared_socket_mode =
       shared_socket_mode_ && (num_server_ip_with_response > 1);
 
-  if (stats.shared_socket_mode && nat_type == NATTYPE_UNKNOWN) {
-    stats.nat_type = NATTYPE_NON_SYMMETRIC;
+  if (stats.shared_socket_mode && nat_type == NATTYPE_INVALID) {
+    nat_type = NATTYPE_NON_SYMMETRIC;
   }
 
-  stats.host_ip = local_addr_.ToString();
+  // If we could find a local IP matching srflx, we're not behind a NAT.
+  rtc::SocketAddress srflx_addr;
+  if (!srflx_addr.FromString(*(stats.srflx_addrs.begin()))) {
+    return false;
+  }
+  for (const auto& net : networks_) {
+    if (srflx_addr.ipaddr() == net->GetBestIP()) {
+      nat_type = stunprober::NATTYPE_NONE;
+      stats.host_ip = net->GetBestIP().ToString();
+      break;
+    }
+  }
+
+  // Finally, we know we're behind a NAT but can't determine which type it is.
+  if (nat_type == NATTYPE_INVALID) {
+    nat_type = NATTYPE_UNKNOWN;
+  }
+
+  stats.nat_type = nat_type;
   stats.num_request_sent = num_sent;
   stats.num_response_received = num_received;
   stats.target_request_interval_ns = interval_ms_ * 1000;
@@ -538,14 +521,14 @@
   return true;
 }
 
-void StunProber::End(StunProber::Status status, int result) {
+void StunProber::End(StunProber::Status status) {
   DCHECK(thread_checker_.CalledOnValidThread());
   if (!finished_callback_.empty()) {
     AsyncCallback callback = finished_callback_;
     finished_callback_ = AsyncCallback();
 
     // Callback at the last since the prober might be deleted in the callback.
-    callback(status);
+    callback(this, status);
   }
 }
 
diff --git a/webrtc/p2p/stunprober/stunprober.h b/webrtc/p2p/stunprober/stunprober.h
index d773d57..56d5369 100644
--- a/webrtc/p2p/stunprober/stunprober.h
+++ b/webrtc/p2p/stunprober/stunprober.h
@@ -15,20 +15,32 @@
 #include <string>
 #include <vector>
 
+#include "webrtc/base/asyncinvoker.h"
 #include "webrtc/base/basictypes.h"
 #include "webrtc/base/bytebuffer.h"
 #include "webrtc/base/callback.h"
 #include "webrtc/base/ipaddress.h"
+#include "webrtc/base/network.h"
 #include "webrtc/base/scoped_ptr.h"
 #include "webrtc/base/socketaddress.h"
+#include "webrtc/base/thread.h"
 #include "webrtc/base/thread_checker.h"
 #include "webrtc/typedefs.h"
 
+namespace rtc {
+class AsyncPacketSocket;
+class PacketSocketFactory;
+class Thread;
+class NetworkManager;
+}  // namespace rtc
+
 namespace stunprober {
 
+class StunProber;
+
 static const int kMaxUdpBufferSize = 1200;
 
-typedef rtc::Callback1<void, int> AsyncCallback;
+typedef rtc::Callback2<void, StunProber*, int> AsyncCallback;
 
 enum NatType {
   NATTYPE_INVALID,
@@ -38,104 +50,7 @@
   NATTYPE_NON_SYMMETRIC  // Behind a non-symmetric NAT.
 };
 
-class HostNameResolverInterface {
- public:
-  HostNameResolverInterface() {}
-
-  // Resolve should allow re-entry as |callback| could trigger another
-  // Resolve().
-  virtual void Resolve(const rtc::SocketAddress& addr,
-                       std::vector<rtc::SocketAddress>* addresses,
-                       AsyncCallback callback) = 0;
-
-  virtual ~HostNameResolverInterface() {}
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(HostNameResolverInterface);
-};
-
-// Chrome has client and server socket. Client socket supports Connect but not
-// Bind. Server is opposite.
-class SocketInterface {
- public:
-  enum {
-    IO_PENDING = -1,
-    FAILED = -2,
-  };
-  SocketInterface() {}
-  virtual void Close() = 0;
-  virtual ~SocketInterface() {}
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(SocketInterface);
-};
-
-class ClientSocketInterface : public SocketInterface {
- public:
-  ClientSocketInterface() {}
-  // Even though we have SendTo and RecvFrom, if Connect is not called first,
-  // getsockname will only return 0.0.0.0.
-  virtual int Connect(const rtc::SocketAddress& addr) = 0;
-
-  virtual int GetLocalAddress(rtc::SocketAddress* local_address) = 0;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(ClientSocketInterface);
-};
-
-class ServerSocketInterface : public SocketInterface {
- public:
-  ServerSocketInterface() {}
-
-  virtual int SendTo(const rtc::SocketAddress& addr,
-                     char* buf,
-                     size_t buf_len,
-                     AsyncCallback callback) = 0;
-
-  // If the returned value is positive, it means that buf has been
-  // sent. Otherwise, it should return IO_PENDING. Callback will be invoked
-  // after the data is successfully read into buf.
-  virtual int RecvFrom(char* buf,
-                       size_t buf_len,
-                       rtc::SocketAddress* addr,
-                       AsyncCallback callback) = 0;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(ServerSocketInterface);
-};
-
-class SocketFactoryInterface {
- public:
-  SocketFactoryInterface() {}
-  // To provide a chance to prepare the sockets that we need. This is
-  // implemented for chrome renderer process as the socket needs to be ready to
-  // use in browser process.
-  virtual void Prepare(size_t total_client_socket,
-                       size_t total_server_socket,
-                       AsyncCallback callback) {
-    callback(0);
-  }
-  virtual ClientSocketInterface* CreateClientSocket() = 0;
-  virtual ServerSocketInterface* CreateServerSocket(
-      size_t send_buffer_size,
-      size_t receive_buffer_size) = 0;
-  virtual ~SocketFactoryInterface() {}
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(SocketFactoryInterface);
-};
-
-class TaskRunnerInterface {
- public:
-  TaskRunnerInterface() {}
-  virtual void PostTask(rtc::Callback0<void>, uint32_t delay_ms) = 0;
-  virtual ~TaskRunnerInterface() {}
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(TaskRunnerInterface);
-};
-
-class StunProber {
+class StunProber : public sigslot::has_slots<> {
  public:
   enum Status {       // Used in UMA_HISTOGRAM_ENUMERATION.
     SUCCESS,          // Successfully received bytes from the server.
@@ -167,11 +82,9 @@
     std::set<std::string> srflx_addrs;
   };
 
-  // StunProber is not thread safe. It's task_runner's responsibility to ensure
-  // all calls happen sequentially.
-  StunProber(HostNameResolverInterface* host_name_resolver,
-             SocketFactoryInterface* socket_factory,
-             TaskRunnerInterface* task_runner);
+  StunProber(rtc::PacketSocketFactory* socket_factory,
+             rtc::Thread* thread,
+             const rtc::NetworkManager::NetworkList& networks);
   virtual ~StunProber();
 
   // Begin performing the probe test against the |servers|. If
@@ -203,16 +116,19 @@
   // STUN servers.
   class Requester;
 
-  void OnServerResolved(int index, int result);
+  bool ResolveServerName(const rtc::SocketAddress& addr);
+  void OnServerResolved(rtc::AsyncResolverInterface* resolver);
+
+  void OnSocketReady(rtc::AsyncPacketSocket* socket,
+                     const rtc::SocketAddress& addr);
 
   bool Done() {
-    return num_request_sent_ >= requests_per_ip_ * all_servers_ips_.size();
+    return num_request_sent_ >= requests_per_ip_ * all_servers_addrs_.size();
   }
 
-  int GetTotalClientSockets() { return 1; }
-  int GetTotalServerSockets() {
-    return static_cast<int>(
-        (shared_socket_mode_ ? 1 : all_servers_ips_.size()) * requests_per_ip_);
+  size_t total_socket_required() {
+    return (shared_socket_mode_ ? 1 : all_servers_addrs_.size()) *
+           requests_per_ip_;
   }
 
   bool SendNextRequest();
@@ -223,14 +139,7 @@
 
   // End the probe with the given |status|.  Invokes |fininsh_callback|, which
   // may destroy the class.
-  void End(StunProber::Status status, int result);
-
-  // Create a socket, connect to the first resolved server, and return the
-  // result of getsockname().  All Requesters will bind to this name. We do this
-  // because if a socket is not bound nor connected, getsockname will return
-  // 0.0.0.0. We can't connect to a single STUN server IP either as that will
-  // fail subsequent requests in shared mode.
-  int GetLocalAddress(rtc::IPAddress* addr);
+  void End(StunProber::Status status);
 
   Requester* CreateRequester();
 
@@ -256,19 +165,12 @@
   // STUN server name to be resolved.
   std::vector<rtc::SocketAddress> servers_;
 
-  // The local address that each probing socket will be bound to.
-  rtc::IPAddress local_addr_;
+  // Weak references.
+  rtc::PacketSocketFactory* socket_factory_;
+  rtc::Thread* thread_;
 
-  // Owned pointers.
-  rtc::scoped_ptr<SocketFactoryInterface> socket_factory_;
-  rtc::scoped_ptr<HostNameResolverInterface> resolver_;
-  rtc::scoped_ptr<TaskRunnerInterface> task_runner_;
-
-  // Addresses filled out by HostNameResolver for a single server.
-  std::vector<rtc::SocketAddress> resolved_ips_;
-
-  // Accumulate all resolved IPs.
-  std::vector<rtc::SocketAddress> all_servers_ips_;
+  // Accumulate all resolved addresses.
+  std::vector<rtc::SocketAddress> all_servers_addrs_;
 
   // Caller-supplied callback executed when testing is completed, called by
   // End().
@@ -279,6 +181,15 @@
 
   rtc::ThreadChecker thread_checker_;
 
+  // Temporary storage for created sockets.
+  std::vector<rtc::AsyncPacketSocket*> sockets_;
+  // This tracks how many of the sockets are ready.
+  size_t total_ready_sockets_ = 0;
+
+  rtc::AsyncInvoker invoker_;
+
+  rtc::NetworkManager::NetworkList networks_;
+
   DISALLOW_COPY_AND_ASSIGN(StunProber);
 };
 
diff --git a/webrtc/p2p/stunprober/stunprober_dependencies.h b/webrtc/p2p/stunprober/stunprober_dependencies.h
deleted file mode 100644
index 4e64df7..0000000
--- a/webrtc/p2p/stunprober/stunprober_dependencies.h
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- *  Copyright 2015 The WebRTC Project Authors. All rights reserved.
- *
- *  Use of this source code is governed by a BSD-style license
- *  that can be found in the LICENSE file in the root of the source
- *  tree. An additional intellectual property rights grant can be found
- *  in the file PATENTS.  All contributing project authors may
- *  be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef WEBRTC_P2P_STUNPROBER_STUNPROBER_DEPENDENCIES_H_
-#define WEBRTC_P2P_STUNPROBER_STUNPROBER_DEPENDENCIES_H_
-
-#include "webrtc/base/checks.h"
-#include "webrtc/base/helpers.h"
-#include "webrtc/base/logging.h"
-#include "webrtc/base/scoped_ptr.h"
-#include "webrtc/base/thread.h"
-#include "webrtc/base/timeutils.h"
-#include "webrtc/p2p/stunprober/stunprober.h"
-
-// Common classes used by both the command line driver and the unit tests.
-namespace stunprober {
-
-class Socket : public ClientSocketInterface,
-               public ServerSocketInterface,
-               public sigslot::has_slots<> {
- public:
-  explicit Socket(rtc::AsyncSocket* socket) : socket_(socket) {
-    socket_->SignalReadEvent.connect(this, &Socket::OnReadEvent);
-    socket_->SignalWriteEvent.connect(this, &Socket::OnWriteEvent);
-  }
-
-  int Connect(const rtc::SocketAddress& addr) override {
-    return MapResult(socket_->Connect(addr));
-  }
-
-  int SendTo(const rtc::SocketAddress& addr,
-             char* buf,
-             size_t buf_len,
-             AsyncCallback callback) override {
-    write_ = NetworkWrite(addr, buf, buf_len, callback);
-    return MapResult(socket_->SendTo(buf, buf_len, addr));
-  }
-
-  int RecvFrom(char* buf,
-               size_t buf_len,
-               rtc::SocketAddress* addr,
-               AsyncCallback callback) override {
-    read_ = NetworkRead(buf, buf_len, addr, callback);
-    return MapResult(socket_->RecvFrom(buf, buf_len, addr));
-  }
-
-  int GetLocalAddress(rtc::SocketAddress* local_address) override {
-    *local_address = socket_->GetLocalAddress();
-    return 0;
-  }
-
-  void Close() override { socket_->Close(); }
-
-  virtual ~Socket() {}
-
- protected:
-  int MapResult(int rv) {
-    if (rv >= 0) {
-      return rv;
-    }
-    int err = socket_->GetError();
-    if (err == EWOULDBLOCK || err == EAGAIN) {
-      return IO_PENDING;
-    } else {
-      return FAILED;
-    }
-  }
-
-  void OnReadEvent(rtc::AsyncSocket* socket) {
-    DCHECK(socket_ == socket);
-    NetworkRead read = read_;
-    read_ = NetworkRead();
-    if (!read.callback.empty()) {
-      read.callback(socket_->RecvFrom(read.buf, read.buf_len, read.addr));
-    }
-  }
-
-  void OnWriteEvent(rtc::AsyncSocket* socket) {
-    DCHECK(socket_ == socket);
-    NetworkWrite write = write_;
-    write_ = NetworkWrite();
-    if (!write.callback.empty()) {
-      write.callback(socket_->SendTo(write.buf, write.buf_len, write.addr));
-    }
-  }
-
-  struct NetworkWrite {
-    NetworkWrite() : buf(nullptr), buf_len(0) {}
-    NetworkWrite(const rtc::SocketAddress& addr,
-                 char* buf,
-                 size_t buf_len,
-                 AsyncCallback callback)
-        : buf(buf), buf_len(buf_len), addr(addr), callback(callback) {}
-    char* buf;
-    size_t buf_len;
-    rtc::SocketAddress addr;
-    AsyncCallback callback;
-  };
-
-  NetworkWrite write_;
-
-  struct NetworkRead {
-    NetworkRead() : buf(nullptr), buf_len(0) {}
-    NetworkRead(char* buf,
-                size_t buf_len,
-                rtc::SocketAddress* addr,
-                AsyncCallback callback)
-        : buf(buf), buf_len(buf_len), addr(addr), callback(callback) {}
-
-    char* buf;
-    size_t buf_len;
-    rtc::SocketAddress* addr;
-    AsyncCallback callback;
-  };
-
-  NetworkRead read_;
-
-  rtc::scoped_ptr<rtc::AsyncSocket> socket_;
-};
-
-class SocketFactory : public SocketFactoryInterface {
- public:
-  ClientSocketInterface* CreateClientSocket() override {
-    return new Socket(
-        rtc::Thread::Current()->socketserver()->CreateAsyncSocket(SOCK_DGRAM));
-  }
-  ServerSocketInterface* CreateServerSocket(size_t send_buffer_size,
-                                            size_t recv_buffer_size) override {
-    rtc::scoped_ptr<rtc::AsyncSocket> socket(
-        rtc::Thread::Current()->socketserver()->CreateAsyncSocket(SOCK_DGRAM));
-
-    if (socket) {
-      socket->SetOption(rtc::AsyncSocket::OPT_SNDBUF,
-                        static_cast<int>(send_buffer_size));
-      socket->SetOption(rtc::AsyncSocket::OPT_RCVBUF,
-                        static_cast<int>(recv_buffer_size));
-      return new Socket(socket.release());
-    } else {
-      return nullptr;
-    }
-  }
-};
-
-class TaskRunner : public TaskRunnerInterface, public rtc::MessageHandler {
- protected:
-  class CallbackMessageData : public rtc::MessageData {
-   public:
-    explicit CallbackMessageData(rtc::Callback0<void> callback)
-        : callback_(callback) {}
-    rtc::Callback0<void> callback_;
-  };
-
- public:
-  void PostTask(rtc::Callback0<void> callback, uint32_t delay_ms) {
-    if (delay_ms == 0) {
-      rtc::Thread::Current()->Post(this, 0, new CallbackMessageData(callback));
-    } else {
-      rtc::Thread::Current()->PostDelayed(delay_ms, this, 0,
-                                          new CallbackMessageData(callback));
-    }
-  }
-
-  void OnMessage(rtc::Message* msg) {
-    rtc::scoped_ptr<CallbackMessageData> callback(
-        reinterpret_cast<CallbackMessageData*>(msg->pdata));
-    callback->callback_();
-  }
-};
-
-}  // namespace stunprober
-#endif  // WEBRTC_P2P_STUNPROBER_STUNPROBER_DEPENDENCIES_H_
diff --git a/webrtc/p2p/stunprober/stunprober_unittest.cc b/webrtc/p2p/stunprober/stunprober_unittest.cc
index ffd5040..3e03014 100644
--- a/webrtc/p2p/stunprober/stunprober_unittest.cc
+++ b/webrtc/p2p/stunprober/stunprober_unittest.cc
@@ -8,6 +8,7 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
+#include "webrtc/base/asyncresolverinterface.h"
 #include "webrtc/base/basictypes.h"
 #include "webrtc/base/bind.h"
 #include "webrtc/base/checks.h"
@@ -16,20 +17,12 @@
 #include "webrtc/base/scoped_ptr.h"
 #include "webrtc/base/ssladapter.h"
 #include "webrtc/base/virtualsocketserver.h"
-
+#include "webrtc/p2p/base/basicpacketsocketfactory.h"
 #include "webrtc/p2p/base/teststunserver.h"
 #include "webrtc/p2p/stunprober/stunprober.h"
-#include "webrtc/p2p/stunprober/stunprober_dependencies.h"
 
-using stunprober::HostNameResolverInterface;
-using stunprober::TaskRunner;
-using stunprober::SocketFactory;
 using stunprober::StunProber;
 using stunprober::AsyncCallback;
-using stunprober::ClientSocketInterface;
-using stunprober::ServerSocketInterface;
-using stunprober::SocketFactory;
-using stunprober::TaskRunner;
 
 namespace stunprober {
 
@@ -41,58 +34,6 @@
 const rtc::SocketAddress kFailedStunAddr("1.1.1.3", 3478);
 const rtc::SocketAddress kStunMappedAddr("77.77.77.77", 0);
 
-class TestSocketServer : public rtc::VirtualSocketServer {
- public:
-  using rtc::VirtualSocketServer::CreateAsyncSocket;
-  explicit TestSocketServer(SocketServer* ss) : rtc::VirtualSocketServer(ss) {}
-  void SetLocalAddress(const rtc::SocketAddress& addr) { addr_ = addr; }
-
-  // CreateAsyncSocket is used by StunProber to create both client and server
-  // sockets. The first socket is used to retrieve local address which will be
-  // used later for Bind().
-  rtc::AsyncSocket* CreateAsyncSocket(int type) override {
-    rtc::VirtualSocket* socket = static_cast<rtc::VirtualSocket*>(
-        rtc::VirtualSocketServer::CreateAsyncSocket(type));
-    if (!local_addr_set_) {
-      // Only the first socket can SetLocalAddress. For others, Bind will fail
-      // if local address is set.
-      socket->SetLocalAddress(addr_);
-      local_addr_set_ = true;
-    } else {
-      sockets_.push_back(socket);
-    }
-    return socket;
-  }
-
-  size_t num_socket() { return sockets_.size(); }
-
- private:
-  bool local_addr_set_ = false;
-  std::vector<rtc::VirtualSocket*> sockets_;
-  rtc::SocketAddress addr_;
-};
-
-class FakeHostNameResolver : public HostNameResolverInterface {
- public:
-  FakeHostNameResolver() {}
-  void set_result(int ret) { ret_ = ret; }
-  void set_addresses(const std::vector<rtc::SocketAddress>& addresses) {
-    server_ips_ = addresses;
-  }
-  const std::vector<rtc::SocketAddress>& get_addresses() { return server_ips_; }
-  void add_address(const rtc::SocketAddress& ip) { server_ips_.push_back(ip); }
-  void Resolve(const rtc::SocketAddress& addr,
-               std::vector<rtc::SocketAddress>* addresses,
-               stunprober::AsyncCallback callback) override {
-    *addresses = server_ips_;
-    callback(ret_);
-  }
-
- private:
-  int ret_ = 0;
-  std::vector<rtc::SocketAddress> server_ips_;
-};
-
 }  // namespace
 
 class StunProberTest : public testing::Test {
@@ -100,7 +41,7 @@
   StunProberTest()
       : main_(rtc::Thread::Current()),
         pss_(new rtc::PhysicalSocketServer),
-        ss_(new TestSocketServer(pss_.get())),
+        ss_(new rtc::VirtualSocketServer(pss_.get())),
         ss_scope_(ss_.get()),
         result_(StunProber::SUCCESS),
         stun_server_1_(cricket::TestStunServer::Create(rtc::Thread::Current(),
@@ -114,62 +55,56 @@
 
   void set_expected_result(int result) { result_ = result; }
 
-  void StartProbing(HostNameResolverInterface* resolver,
-                    SocketFactoryInterface* socket_factory,
-                    const rtc::SocketAddress& addr,
+  void StartProbing(rtc::PacketSocketFactory* socket_factory,
+                    const std::vector<rtc::SocketAddress>& addrs,
+                    const rtc::NetworkManager::NetworkList& networks,
                     bool shared_socket,
                     uint16 interval,
                     uint16 pings_per_ip) {
-    std::vector<rtc::SocketAddress> addrs;
-    addrs.push_back(addr);
-    prober.reset(new StunProber(resolver, socket_factory, new TaskRunner()));
+    prober.reset(
+        new StunProber(socket_factory, rtc::Thread::Current(), networks));
     prober->Start(addrs, shared_socket, interval, pings_per_ip,
-                  100 /* timeout_ms */,
-                  [this](int result) { this->StopCallback(result); });
+                  100 /* timeout_ms */, [this](StunProber* prober, int result) {
+                    this->StopCallback(prober, result);
+                  });
   }
 
   void RunProber(bool shared_mode) {
     const int pings_per_ip = 3;
-    const uint16 port = kStunAddr1.port();
-    rtc::SocketAddress addr("stun.l.google.com", port);
     std::vector<rtc::SocketAddress> addrs;
-
-    // Set up the resolver for 2 stun server addresses.
-    rtc::scoped_ptr<FakeHostNameResolver> resolver(new FakeHostNameResolver());
-    resolver->add_address(kStunAddr1);
-    resolver->add_address(kStunAddr2);
+    addrs.push_back(kStunAddr1);
+    addrs.push_back(kStunAddr2);
     // Add a non-existing server. This shouldn't pollute the result.
-    resolver->add_address(kFailedStunAddr);
+    addrs.push_back(kFailedStunAddr);
 
-    rtc::scoped_ptr<SocketFactory> socket_factory(new SocketFactory());
+    rtc::Network ipv4_network1("test_eth0", "Test Network Adapter 1",
+                               rtc::IPAddress(0x12345600U), 24);
+    ipv4_network1.AddIP(rtc::IPAddress(0x12345678));
+    rtc::NetworkManager::NetworkList networks;
+    networks.push_back(&ipv4_network1);
 
-    // Set local address in socketserver so getsockname will return kLocalAddr
-    // instead of 0.0.0.0 for the first socket.
-    ss_->SetLocalAddress(kLocalAddr);
+    rtc::scoped_ptr<rtc::BasicPacketSocketFactory> socket_factory(
+        new rtc::BasicPacketSocketFactory());
 
     // Set up the expected results for verification.
     std::set<std::string> srflx_addresses;
     srflx_addresses.insert(kStunMappedAddr.ToString());
     const uint32 total_pings_tried =
-        static_cast<uint32>(pings_per_ip * resolver->get_addresses().size());
+        static_cast<uint32>(pings_per_ip * addrs.size());
 
     // The reported total_pings should not count for pings sent to the
     // kFailedStunAddr.
     const uint32 total_pings_reported = total_pings_tried - pings_per_ip;
 
-    size_t total_sockets = shared_mode ? pings_per_ip : total_pings_tried;
-
-    StartProbing(resolver.release(), socket_factory.release(), addr,
-                 shared_mode, 3, pings_per_ip);
+    StartProbing(socket_factory.get(), addrs, networks, shared_mode, 3,
+                 pings_per_ip);
 
     WAIT(stopped_, 1000);
 
     StunProber::Stats stats;
-    EXPECT_EQ(ss_->num_socket(), total_sockets);
     EXPECT_TRUE(prober->GetStats(&stats));
     EXPECT_EQ(stats.success_percent, 100);
     EXPECT_TRUE(stats.nat_type > stunprober::NATTYPE_NONE);
-    EXPECT_EQ(stats.host_ip, kLocalAddr.ipaddr().ToString());
     EXPECT_EQ(stats.srflx_addrs, srflx_addresses);
     EXPECT_EQ(static_cast<uint32>(stats.num_request_sent),
               total_pings_reported);
@@ -178,14 +113,14 @@
   }
 
  private:
-  void StopCallback(int result) {
+  void StopCallback(StunProber* prober, int result) {
     EXPECT_EQ(result, result_);
     stopped_ = true;
   }
 
   rtc::Thread* main_;
   rtc::scoped_ptr<rtc::PhysicalSocketServer> pss_;
-  rtc::scoped_ptr<TestSocketServer> ss_;
+  rtc::scoped_ptr<rtc::VirtualSocketServer> ss_;
   rtc::SocketServerScope ss_scope_;
   rtc::scoped_ptr<StunProber> prober;
   int result_ = 0;
@@ -194,19 +129,6 @@
   rtc::scoped_ptr<cricket::TestStunServer> stun_server_2_;
 };
 
-TEST_F(StunProberTest, DNSFailure) {
-  rtc::SocketAddress addr("stun.l.google.com", 19302);
-  rtc::scoped_ptr<FakeHostNameResolver> resolver(new FakeHostNameResolver());
-  rtc::scoped_ptr<SocketFactory> socket_factory(new SocketFactory());
-
-  set_expected_result(StunProber::RESOLVE_FAILED);
-
-  // Non-0 value is treated as failure.
-  resolver->set_result(1);
-  StartProbing(resolver.release(), socket_factory.release(), addr, false, 10,
-               30);
-}
-
 TEST_F(StunProberTest, NonSharedMode) {
   RunProber(false);
 }