Bug 837919 - RTCPeerConnection constructor supports FQDN STUN servers. r=ekr
authorJan-Ivar Bruaroey <jib@mozilla.com>
Fri, 08 Mar 2013 15:11:17 -0500
changeset 124311 9e6232e86000c2e736ca097fbff5b0cd5cc086fe
parent 124310 50caa662b5a4ee68976237ab6a6153d08de6227c
child 124312 1feae6162b87d7e0a78f4cc96077ff89dd0e3e78
child 124324 80f3b6ae39bb61703c6bfd80b173d7a64034ff30
push id1412
push userttaubert@mozilla.com
push dateMon, 11 Mar 2013 12:01:17 +0000
treeherderfx-team@1176278e959b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersekr
bugs837919
milestone22.0a1
Bug 837919 - RTCPeerConnection constructor supports FQDN STUN servers. r=ekr
media/mtransport/nr_socket_prsock.cpp
media/mtransport/nr_socket_prsock.h
media/mtransport/nriceresolver.cpp
media/mtransport/nriceresolver.h
media/mtransport/objs.mk
media/mtransport/test/ice_unittest.cpp
media/mtransport/test/mtransport_test_utils.h
media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp
media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h
media/webrtc/signaling/test/signaling_unittests.cpp
--- a/media/mtransport/nr_socket_prsock.cpp
+++ b/media/mtransport/nr_socket_prsock.cpp
@@ -90,32 +90,32 @@ nrappkit copyright:
 #include <assert.h>
 #include <errno.h>
 
 #include "nspr.h"
 #include "prerror.h"
 #include "prio.h"
 #include "prnetdb.h"
 
+#include "mozilla/net/DNS.h"
 #include "nsCOMPtr.h"
 #include "nsASocketHandler.h"
 #include "nsISocketTransportService.h"
 #include "nsNetCID.h"
 #include "nsISupportsImpl.h"
 #include "nsServiceManagerUtils.h"
 #include "nsXPCOM.h"
 #include "runnable_utils.h"
 
 extern "C" {
 #include "nr_api.h"
 #include "async_wait.h"
 #include "nr_socket.h"
 #include "nr_socket_local.h"
 }
-
 #include "nr_socket_prsock.h"
 
 // Implement the nsISupports ref counting
 namespace mozilla {
 
 NS_IMPL_THREADSAFE_ISUPPORTS0(NrSocket)
 
 
@@ -235,42 +235,67 @@ static int nr_transport_addr_to_praddr(n
         ABORT(R_BAD_ARGS);
     }
 
     _status = 0;
   abort:
     return(_status);
   }
 
+int nr_netaddr_to_transport_addr(const net::NetAddr *netaddr,
+  nr_transport_addr *addr)
+  {
+    int _status;
+    int r;
+
+    switch(netaddr->raw.family) {
+      case AF_INET:
+        if ((r = nr_ip4_port_to_transport_addr(ntohl(netaddr->inet.ip),
+                                               ntohs(netaddr->inet.port),
+                                               IPPROTO_UDP, addr)))
+          ABORT(r);
+        break;
+      case AF_INET6:
+        ABORT(R_BAD_ARGS);
+      default:
+        MOZ_ASSERT(false);
+        ABORT(R_BAD_ARGS);
+    }
+    _status=0;
+  abort:
+    return(_status);
+  }
+
 int nr_praddr_to_transport_addr(const PRNetAddr *praddr,
   nr_transport_addr *addr, int keep)
   {
     int _status;
     int r;
     struct sockaddr_in ip4;
 
     switch(praddr->raw.family) {
       case PR_AF_INET:
         ip4.sin_family = PF_INET;
         ip4.sin_addr.s_addr = praddr->inet.ip;
         ip4.sin_port = praddr->inet.port;
         if ((r = nr_sockaddr_to_transport_addr((sockaddr *)&ip4,
-                                              sizeof(ip4),
-                                              IPPROTO_UDP, 1,
-              addr)))
+                                               sizeof(ip4),
+                                               IPPROTO_UDP, keep,
+                                               addr)))
           ABORT(r);
         break;
       case PR_AF_INET6:
 #if 0
         r = nr_sockaddr_to_transport_addr((sockaddr *)&praddr->raw,
           sizeof(struct sockaddr_in6),IPPROTO_UDP,keep,addr);
         break;
 #endif
         ABORT(R_BAD_ARGS);
       default:
+        MOZ_ASSERT(false);
         ABORT(R_BAD_ARGS);
     }
 
     _status=0;
  abort:
     return(_status);
   }
 
--- a/media/mtransport/nr_socket_prsock.h
+++ b/media/mtransport/nr_socket_prsock.h
@@ -56,16 +56,20 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 #include "nsISocketTransportService.h"
 #include "nsXPCOM.h"
 #include "nsIEventTarget.h"
 
 #include "m_cpp_utils.h"
 
 namespace mozilla {
 
+namespace net {
+  union NetAddr;
+}
+
 class NrSocket : public nsASocketHandler {
 public:
   NrSocket() : fd_(nullptr) {
     memset(&my_addr_, 0, sizeof(my_addr_));
     memset(cbs_, 0, sizeof(cbs_));
     memset(cb_args_, 0, sizeof(cb_args_));
   }
   virtual ~NrSocket() {
@@ -105,13 +109,14 @@ private:
 
   PRFileDesc *fd_;
   nr_transport_addr my_addr_;
   NR_async_cb cbs_[NR_ASYNC_WAIT_WRITE + 1];
   void *cb_args_[NR_ASYNC_WAIT_WRITE + 1];
   nsCOMPtr<nsIEventTarget> ststhread_;
 };
 
+int nr_netaddr_to_transport_addr(const net::NetAddr *netaddr,
+                                 nr_transport_addr *addr);
 int nr_praddr_to_transport_addr(const PRNetAddr *praddr,
                                 nr_transport_addr *addr, int keep);
-
 }  // close namespace
 #endif
new file mode 100644
--- /dev/null
+++ b/media/mtransport/nriceresolver.cpp
@@ -0,0 +1,218 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+
+// Original authors: jib@mozilla.com, ekr@rtfm.com
+
+// Some of this code is cut-and-pasted from nICEr. Copyright is:
+
+/*
+Copyright (c) 2007, Adobe Systems, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+  notice, this list of conditions and the following disclaimer in the
+  documentation and/or other materials provided with the distribution.
+
+* Neither the name of Adobe Systems, Network Resonance nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "nspr.h"
+#include "prnetdb.h"
+
+#include "mozilla/Assertions.h"
+
+extern "C" {
+#include "nr_api.h"
+#include "async_timer.h"
+#include "nr_resolver.h"
+#include "transport_addr.h"
+}
+
+#include "mozilla/net/DNS.h" // TODO(jib@mozilla.com) down here because bug 848578
+#include "nsThreadUtils.h"
+#include "nsServiceManagerUtils.h"
+#include "nsIDNSService.h"
+#include "nsIDNSListener.h"
+#include "nsIDNSRecord.h"
+#include "nsNetCID.h"
+#include "nsCOMPtr.h"
+#include "nriceresolver.h"
+#include "nr_socket_prsock.h"
+#include "mtransport/runnable_utils.h"
+
+// Local includes
+#include "logging.h"
+
+namespace mozilla {
+
+MOZ_MTLOG_MODULE("mtransport")
+
+NrIceResolver::NrIceResolver() :
+    vtbl_(new nr_resolver_vtbl())
+#ifdef DEBUG
+    , allocated_resolvers_(0)
+#endif
+{
+  vtbl_->destroy = &NrIceResolver::destroy;
+  vtbl_->resolve = &NrIceResolver::resolve;
+  vtbl_->cancel = &NrIceResolver::cancel;
+}
+
+NrIceResolver::~NrIceResolver() {
+  MOZ_ASSERT(!allocated_resolvers_);
+  delete vtbl_;
+}
+
+nsresult NrIceResolver::Init() {
+  nsresult rv;
+
+  sts_thread_ = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
+  MOZ_ASSERT(NS_SUCCEEDED(rv));
+  dns_ = do_GetService(NS_DNSSERVICE_CONTRACTID, &rv);
+  if (NS_FAILED(rv)) {
+    MOZ_MTLOG(PR_LOG_ERROR, "Could not acquire DNS service");
+  }
+  return rv;
+}
+
+nr_resolver *NrIceResolver::AllocateResolver() {
+  nr_resolver *resolver;
+
+  int r = nr_resolver_create_int((void *)this, vtbl_, &resolver);
+  MOZ_ASSERT(!r);
+  if(r) {
+    MOZ_MTLOG(PR_LOG_ERROR, "nr_resolver_create_int failed");
+    return nullptr;
+  }
+  // We must be available to allocators until they all call DestroyResolver,
+  // because allocators may (and do) outlive the originator of NrIceResolver.
+  AddRef();
+#ifdef DEBUG
+  ++allocated_resolvers_;
+#endif
+  return resolver;
+}
+
+void NrIceResolver::DestroyResolver() {
+#ifdef DEBUG
+  --allocated_resolvers_;
+#endif
+  // Undoes Addref in AllocateResolver so the NrIceResolver can be freed.
+  Release();
+}
+
+int NrIceResolver::destroy(void **objp) {
+  if (!objp || !*objp)
+    return 0;
+  NrIceResolver *resolver = static_cast<NrIceResolver *>(*objp);
+  *objp = 0;
+  resolver->DestroyResolver();
+  return 0;
+}
+
+int NrIceResolver::resolve(void *obj,
+                           nr_resolver_resource *resource,
+                           int (*cb)(void *cb_arg, nr_transport_addr *addr),
+                           void *cb_arg,
+                           void **handle) {
+  MOZ_ASSERT(obj);
+  return static_cast<NrIceResolver *>(obj)->resolve(resource, cb, cb_arg, handle);
+}
+
+int NrIceResolver::resolve(nr_resolver_resource *resource,
+                           int (*cb)(void *cb_arg, nr_transport_addr *addr),
+                           void *cb_arg,
+                           void **handle) {
+  int _status;
+  MOZ_ASSERT(allocated_resolvers_ > 0);
+  ASSERT_ON_THREAD(sts_thread_);
+  nsCOMPtr<PendingResolution> pr;
+
+  if (resource->transport_protocol != IPPROTO_UDP) {
+    MOZ_MTLOG(PR_LOG_ERROR, "Only UDP is supported.");
+    ABORT(R_NOT_FOUND);
+  }
+  pr = new PendingResolution(sts_thread_, resource->port? resource->port : 3478,
+                             cb, cb_arg);
+  if (NS_FAILED(dns_->AsyncResolve(nsAutoCString(resource->domain_name),
+                                   nsIDNSService::RESOLVE_DISABLE_IPV6, pr,
+                                   sts_thread_, getter_AddRefs(pr->request_)))) {
+    MOZ_MTLOG(PR_LOG_ERROR, "AsyncResolve failed.");
+    ABORT(R_NOT_FOUND);
+  }
+  // Because the C API offers no "finished" method to release the handle we
+  // return, we cannot return the request we got from AsyncResolve directly.
+  //
+  // Instead, we return an addref'ed reference to PendingResolution itself,
+  // which in turn holds the request and coordinates between cancel and
+  // OnLookupComplete to release it only once.
+  *handle = pr.forget().get();
+
+  _status=0;
+abort:
+  return _status;
+}
+
+nsresult NrIceResolver::PendingResolution::OnLookupComplete(
+    nsICancelable *request, nsIDNSRecord *record, nsresult status) {
+  ASSERT_ON_THREAD(thread_);
+  // First check if we've been canceled. This is single-threaded on the STS
+  // thread, but cancel() cannot guarantee this event isn't on the queue.
+  if (!canceled_) {
+    nr_transport_addr *cb_addr = nullptr;
+    nr_transport_addr ta;
+    // TODO(jib@mozilla.com): Revisit when we do TURN.
+    if (NS_SUCCEEDED(status)) {
+      net::NetAddr na;
+      if (NS_SUCCEEDED(record->GetNextAddr(port_, &na))) {
+        MOZ_ALWAYS_TRUE (nr_netaddr_to_transport_addr(&na, &ta) == 0);
+        cb_addr = &ta;
+      }
+    }
+    cb_(cb_arg_, cb_addr);
+    Release();
+  }
+  return NS_OK;
+}
+
+int NrIceResolver::cancel(void *obj, void *handle) {
+  MOZ_ALWAYS_TRUE(obj);
+  MOZ_ASSERT(handle);
+  ASSERT_ON_THREAD(static_cast<NrIceResolver *>(obj)->sts_thread_);
+  return static_cast<PendingResolution *>(handle)->cancel();
+}
+
+int NrIceResolver::PendingResolution::cancel() {
+  request_->Cancel (NS_ERROR_ABORT);
+  canceled_ = true; // in case OnLookupComplete is already on event queue.
+  Release();
+  return 0;
+}
+
+NS_IMPL_THREADSAFE_ISUPPORTS1(NrIceResolver::PendingResolution, nsIDNSListener);
+}  // End of namespace mozilla
new file mode 100644
--- /dev/null
+++ b/media/mtransport/nriceresolver.h
@@ -0,0 +1,120 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+
+// Original authors: jib@mozilla.com, ekr@rtfm.com
+
+// Some of this code is cut-and-pasted from nICEr. Copyright is:
+
+/*
+Copyright (c) 2007, Adobe Systems, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+  notice, this list of conditions and the following disclaimer in the
+  documentation and/or other materials provided with the distribution.
+
+* Neither the name of Adobe Systems, Network Resonance nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef nriceresolver_h__
+#define nriceresolver_h__
+
+#include <map>
+#include <string>
+#include "nspr.h"
+#include "prnetdb.h"
+#include "nsIDNSService.h"
+#include "nsIDNSListener.h"
+#include "nsICancelable.h"
+
+typedef struct nr_resolver_ nr_resolver;
+typedef struct nr_resolver_vtbl_ nr_resolver_vtbl;
+typedef struct nr_transport_addr_ nr_transport_addr;
+typedef struct nr_resolver_resource_ nr_resolver_resource;
+
+namespace mozilla {
+
+class NrIceResolver
+{
+ public:
+  NrIceResolver();
+  ~NrIceResolver();
+
+  nsresult Init();
+  nr_resolver *AllocateResolver();
+  void DestroyResolver();
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(NrIceResolver)
+
+ private:
+  // Implementations of vtbl functions
+  static int destroy(void **objp);
+  static int resolve(void *obj, nr_resolver_resource *resource,
+                     int (*cb)(void *cb_arg, nr_transport_addr *addr),
+                     void *cb_arg, void **handle);
+  static void resolve_cb(NR_SOCKET s, int how, void *cb_arg);
+  static int cancel(void *obj, void *handle);
+
+  int resolve(nr_resolver_resource *resource,
+              int (*cb)(void *cb_arg, nr_transport_addr *addr),
+              void *cb_arg, void **handle);
+
+  class PendingResolution : public nsIDNSListener
+  {
+   public:
+    PendingResolution(nsIEventTarget *thread, uint16_t port,
+                      int (*cb)(void *cb_arg, nr_transport_addr *addr),
+                      void *cb_arg) :
+        thread_(thread),
+        port_(port),
+        cb_(cb), cb_arg_(cb_arg),
+        canceled_ (false) {}
+    virtual ~PendingResolution(){};
+    NS_IMETHOD OnLookupComplete(nsICancelable *request, nsIDNSRecord *record,
+                                nsresult status);
+    int cancel();
+    nsCOMPtr<nsICancelable> request_;
+    NS_DECL_ISUPPORTS
+
+   private:
+    nsCOMPtr<nsIEventTarget> thread_;
+    uint16_t port_;
+    int (*cb_)(void *cb_arg, nr_transport_addr *addr);
+    void *cb_arg_;
+    bool canceled_;
+  };
+
+  nr_resolver_vtbl* vtbl_;
+  nsCOMPtr<nsIEventTarget> sts_thread_;
+  nsCOMPtr<nsIDNSService> dns_;
+#ifdef DEBUG
+  int allocated_resolvers_;
+#endif
+};
+
+}  // End of namespace mozilla
+#endif
--- a/media/mtransport/objs.mk
+++ b/media/mtransport/objs.mk
@@ -62,16 +62,17 @@ DEFINES += \
    -DR_DEFINED_INT8=int64_t -DR_DEFINED_UINT8=uint64_t \
    $(NULL)
 
 MTRANSPORT_LCPPSRCS = \
   dtlsidentity.cpp \
   nricectx.cpp \
   nricemediastream.cpp \
   nriceresolverfake.cpp \
+  nriceresolver.cpp \
   nr_socket_prsock.cpp \
   nr_timer.cpp \
   transportflow.cpp \
   transportlayer.cpp \
   transportlayerice.cpp \
   transportlayerdtls.cpp \
   transportlayerlog.cpp \
   transportlayerloopback.cpp \
--- a/media/mtransport/test/ice_unittest.cpp
+++ b/media/mtransport/test/ice_unittest.cpp
@@ -20,30 +20,31 @@
 #include "mozilla/Scoped.h"
 #include "nsThreadUtils.h"
 #include "nsXPCOM.h"
 
 #include "logging.h"
 #include "nricectx.h"
 #include "nricemediastream.h"
 #include "nriceresolverfake.h"
+#include "nriceresolver.h"
 #include "mtransport_test_utils.h"
 #include "runnable_utils.h"
 
 #define GTEST_HAS_RTTI 0
 #include "gtest/gtest.h"
 #include "gtest_utils.h"
 
 using namespace mozilla;
 MtransportTestUtils *test_utils;
 
 bool stream_added = false;
 
 const std::string kDefaultStunServerAddress((char *)"23.21.150.121");
-const std::string kDefaultStunServerHostname((char *)"stun-server.invalid");
+const std::string kDefaultStunServerHostname((char *)"ec2-23-21-150-121.compute-1.amazonaws.com");
 const std::string kBogusStunServerHostname((char *)"stun-server-nonexistent.invalid");
 const uint16_t kDefaultStunServerPort=3478;
 
 namespace {
 
 enum TrickleMode { TRICKLE_NONE, TRICKLE_DEFERRED };
 
 class IceTestPeer : public sigslot::has_slots<> {
@@ -55,19 +56,20 @@ class IceTestPeer : public sigslot::has_
       streams_(),
       candidates_(),
       gathering_complete_(false),
       ready_ct_(0),
       ice_complete_(false),
       received_(0),
       sent_(0),
       fake_resolver_(),
+      dns_resolver_(new NrIceResolver()),
       remote_(nullptr) {
     ice_ctx_->SignalGatheringCompleted.connect(this,
-                                              &IceTestPeer::GatheringComplete);
+                                               &IceTestPeer::GatheringComplete);
     ice_ctx_->SignalCompleted.connect(this, &IceTestPeer::IceCompleted);
   }
 
   ~IceTestPeer() {
     test_utils->sts_target()->Dispatch(WrapRunnable(this,
                                                     &IceTestPeer::Shutdown),
         NS_DISPATCH_SYNC);
 
@@ -93,28 +95,28 @@ class IceTestPeer : public sigslot::has_
   void SetStunServer(const std::string addr, uint16_t port) {
     std::vector<NrIceStunServer> stun_servers;
     ScopedDeletePtr<NrIceStunServer> server(NrIceStunServer::Create(addr,
                                                                     port));
     stun_servers.push_back(*server);
     ASSERT_TRUE(NS_SUCCEEDED(ice_ctx_->SetStunServers(stun_servers)));
   }
 
-  void AddAddressToResolver(const std::string hostname,
-                            const std::string address) {
+  void SetFakeResolver() {
+    ASSERT_TRUE(NS_SUCCEEDED(dns_resolver_->Init()));
     PRNetAddr addr;
-    PRStatus status = PR_StringToNetAddr(address.c_str(), &addr);
+    PRStatus status = PR_StringToNetAddr(kDefaultStunServerAddress.c_str(), &addr);
     ASSERT_EQ(PR_SUCCESS, status);
-
-    fake_resolver_.SetAddr(hostname, addr);
+    fake_resolver_.SetAddr(kDefaultStunServerHostname, addr);
+    ASSERT_TRUE(NS_SUCCEEDED(ice_ctx_->SetResolver(fake_resolver_.AllocateResolver())));
   }
 
-  void SetResolver() {
-    ASSERT_TRUE(NS_SUCCEEDED(ice_ctx_->SetResolver(
-        fake_resolver_.AllocateResolver())));
+  void SetDNSResolver() {
+    ASSERT_TRUE(NS_SUCCEEDED(dns_resolver_->Init()));
+    ASSERT_TRUE(NS_SUCCEEDED(ice_ctx_->SetResolver(dns_resolver_->AllocateResolver())));
   }
 
   void Gather() {
     nsresult res;
 
     test_utils->sts_target()->Dispatch(
         WrapRunnableRet(ice_ctx_, &NrIceCtx::StartGathering, &res),
         NS_DISPATCH_SYNC);
@@ -265,30 +267,25 @@ class IceTestPeer : public sigslot::has_
   std::vector<mozilla::RefPtr<NrIceMediaStream> > streams_;
   std::map<std::string, std::vector<std::string> > candidates_;
   bool gathering_complete_;
   int ready_ct_;
   bool ice_complete_;
   size_t received_;
   size_t sent_;
   NrIceResolverFake fake_resolver_;
+  nsRefPtr<NrIceResolver> dns_resolver_;
   IceTestPeer *remote_;
 };
 
 class IceGatherTest : public ::testing::Test {
  public:
   void SetUp() {
     peer_ = new IceTestPeer("P1", true, false);
     peer_->AddStream(1);
-    peer_->AddAddressToResolver(kDefaultStunServerHostname,
-                                kDefaultStunServerAddress);
-  }
-
-  void SetResolver() {
-    peer_->SetResolver();
   }
 
   void Gather() {
     peer_->Gather();
 
     ASSERT_TRUE_WAIT(peer_->gathering_complete(), 10000);
   }
  protected:
@@ -390,40 +387,57 @@ class IceConnectTest : public ::testing:
   bool initted_;
   nsCOMPtr<nsIEventTarget> target_;
   mozilla::ScopedDeletePtr<IceTestPeer> p1_;
   mozilla::ScopedDeletePtr<IceTestPeer> p2_;
 };
 
 }  // end namespace
 
-
-TEST_F(IceGatherTest, TestGatherStunServerIpAddress) {
-  peer_->SetStunServer(kDefaultStunServerAddress, kDefaultStunServerPort);
-  peer_->SetResolver();
-  Gather();
-}
-
-TEST_F(IceGatherTest, TestGatherStunServerHostname) {
-  peer_->SetStunServer(kDefaultStunServerHostname, kDefaultStunServerPort);
-  peer_->SetResolver();
-  Gather();
-}
-
-TEST_F(IceGatherTest, TestGatherStunBogusHostname) {
-  peer_->SetStunServer(kBogusStunServerHostname, kDefaultStunServerPort);
-  peer_->SetResolver();
-  Gather();
-}
-
-TEST_F(IceGatherTest, TestGatherStunServerHostnameNoResolver) {
+TEST_F(IceGatherTest, TestGatherFakeStunServerHostnameNoResolver) {
   peer_->SetStunServer(kDefaultStunServerHostname, kDefaultStunServerPort);
   Gather();
 }
 
+TEST_F(IceGatherTest, TestGatherFakeStunServerIpAddress) {
+  peer_->SetStunServer(kDefaultStunServerAddress, kDefaultStunServerPort);
+  peer_->SetFakeResolver();
+  Gather();
+}
+
+TEST_F(IceGatherTest, TestGatherFakeStunServerHostname) {
+  peer_->SetStunServer(kDefaultStunServerHostname, kDefaultStunServerPort);
+  peer_->SetFakeResolver();
+  Gather();
+}
+
+TEST_F(IceGatherTest, TestGatherFakeStunBogusHostname) {
+  peer_->SetStunServer(kBogusStunServerHostname, kDefaultStunServerPort);
+  peer_->SetFakeResolver();
+  Gather();
+}
+
+TEST_F(IceGatherTest, TestGatherDNSStunServerIpAddress) {
+  peer_->SetStunServer(kDefaultStunServerAddress, kDefaultStunServerPort);
+  peer_->SetDNSResolver();
+  Gather();
+  // TODO(jib@mozilla.com): ensure we get server reflexive candidates Bug 848094
+}
+
+TEST_F(IceGatherTest, TestGatherDNSStunServerHostname) {
+  peer_->SetStunServer(kDefaultStunServerHostname, kDefaultStunServerPort);
+  peer_->SetDNSResolver();
+  Gather();
+}
+
+TEST_F(IceGatherTest, TestGatherDNSStunBogusHostname) {
+  peer_->SetStunServer(kBogusStunServerHostname, kDefaultStunServerPort);
+  peer_->SetDNSResolver();
+  Gather();
+}
 
 TEST_F(IceConnectTest, TestGather) {
   AddStream("first", 1);
   ASSERT_TRUE(Gather(true));
 }
 
 TEST_F(IceConnectTest, TestGatherAutoPrioritize) {
   Init(false);
--- a/media/mtransport/test/mtransport_test_utils.h
+++ b/media/mtransport/test/mtransport_test_utils.h
@@ -12,16 +12,17 @@
 #include "nspr.h"
 #include "nsCOMPtr.h"
 #include "nsNetCID.h"
 #include "nsXPCOMGlue.h"
 #include "nsXPCOM.h"
 
 #include "nsIComponentManager.h"
 #include "nsIComponentRegistrar.h"
+#include "nsNetUtil.h"
 #include "nsIIOService.h"
 #include "nsIServiceManager.h"
 #include "nsISocketTransportService.h"
 #include "nsDirectoryServiceUtils.h"
 #include "nsDirectoryServiceDefs.h"
 #ifdef MOZ_CRASHREPORTER
 #include "nsICrashReporter.h"
 #endif
@@ -39,20 +40,20 @@ class MtransportTestUtils {
   }
 
   ~MtransportTestUtils() {
     sts_->Shutdown();
   }
 
   void InitServices() {
     nsresult rv;
-
+    ioservice_ = do_GetIOService(&rv);
+    MOZ_ASSERT(NS_SUCCEEDED(rv));
     sts_target_ = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
     MOZ_ASSERT(NS_SUCCEEDED(rv));
-
     sts_ = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
     MOZ_ASSERT(NS_SUCCEEDED(rv));
 
 #ifdef MOZ_CRASHREPORTER
     char *crashreporter = PR_GetEnv("MOZ_CRASHREPORTER");
     if (crashreporter && !strcmp(crashreporter, "1")) {
       //TODO: move this to an even-more-common location to use in all
       // C++ unittests
@@ -73,16 +74,17 @@ class MtransportTestUtils {
     }
 #endif
   }
 
   nsCOMPtr<nsIEventTarget> sts_target() { return sts_target_; }
 
  private:
   ScopedXPCOM xpcom_;
+  nsCOMPtr<nsIIOService> ioservice_;
   nsCOMPtr<nsIEventTarget> sts_target_;
   nsCOMPtr<nsPISocketTransportService> sts_;
 #ifdef MOZ_CRASHREPORTER
   nsCOMPtr<nsICrashReporter> crashreporter_;
 #endif
 };
 
 
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp
@@ -74,18 +74,27 @@ nsresult PeerConnectionMedia::Init(const
 {
   // TODO(ekr@rtfm.com): need some way to set not offerer later
   // Looks like a bug in the NrIceCtx API.
   mIceCtx = NrIceCtx::Create("PC:" + mParent->GetHandle(), true);
   if(!mIceCtx) {
     CSFLogError(logTag, "%s: Failed to create Ice Context", __FUNCTION__);
     return NS_ERROR_FAILURE;
   }
-  nsresult rv = mIceCtx->SetStunServers(stun_servers);
-  if (NS_FAILED(rv)) {
+  nsresult rv;
+  if (NS_FAILED(rv = mIceCtx->SetStunServers(stun_servers))) {
+    CSFLogError(logTag, "%s: Failed to set stun servers", __FUNCTION__);
+    return rv;
+  }
+  if (NS_FAILED(rv = mDNSResolver->Init())) {
+    CSFLogError(logTag, "%s: Failed to initialize dns resolver", __FUNCTION__);
+    return rv;
+  }
+  if (NS_FAILED(rv = mIceCtx->SetResolver(mDNSResolver->AllocateResolver()))) {
+    CSFLogError(logTag, "%s: Failed to get dns resolver", __FUNCTION__);
     return rv;
   }
   mIceCtx->SignalGatheringCompleted.connect(this,
                                             &PeerConnectionMedia::IceGatheringCompleted);
   mIceCtx->SignalCompleted.connect(this,
                                    &PeerConnectionMedia::IceCompleted);
 
   // Create three streams to start with.
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h
@@ -32,16 +32,17 @@
 #include "VideoSegment.h"
 #else
 namespace mozilla {
   class DataChannel;
 }
 #endif
 
 #include "nricectx.h"
+#include "nriceresolver.h"
 #include "nricemediastream.h"
 #include "MediaPipeline.h"
 
 namespace sipcc {
 
 class PeerConnectionImpl;
 
 /* Temporary for providing audio data */
@@ -234,23 +235,22 @@ class RemoteSourceStreamInfo {
   std::map<int, bool> mTypes;
 };
 
 class PeerConnectionMedia : public sigslot::has_slots<> {
  public:
   PeerConnectionMedia(PeerConnectionImpl *parent)
       : mParent(parent),
       mLocalSourceStreamsLock("PeerConnectionMedia.mLocalSourceStreamsLock"),
-      mIceCtx(NULL) {}
+      mIceCtx(NULL),
+      mDNSResolver(new mozilla::NrIceResolver()) {}
 
-  ~PeerConnectionMedia() {
-  }
+  ~PeerConnectionMedia() {}
 
   nsresult Init(const std::vector<mozilla::NrIceStunServer>& stun_servers);
-
   // WARNING: This destroys the object!
   void SelfDestruct();
 
   mozilla::RefPtr<mozilla::NrIceCtx> ice_ctx() const { return mIceCtx; }
 
   mozilla::RefPtr<mozilla::NrIceMediaStream> ice_media_stream(size_t i) const {
     // TODO(ekr@rtfm.com): If someone asks for a value that doesn't exist,
     // make one.
@@ -349,16 +349,19 @@ class PeerConnectionMedia : public sigsl
 
   // A list of streams provided by the other side
   nsTArray<nsRefPtr<RemoteSourceStreamInfo> > mRemoteSourceStreams;
 
   // ICE objects
   mozilla::RefPtr<mozilla::NrIceCtx> mIceCtx;
   std::vector<mozilla::RefPtr<mozilla::NrIceMediaStream> > mIceStreams;
 
+  // DNS
+  nsRefPtr<mozilla::NrIceResolver> mDNSResolver;
+
   // Transport flows: even is RTP, odd is RTCP
   std::map<int, mozilla::RefPtr<mozilla::TransportFlow> > mTransportFlows;
 
   // Conduits: even is receive, odd is transmit (for easier correlation with
   // flows)
   std::map<int, mozilla::RefPtr<mozilla::AudioSessionConduit> > mAudioConduits;
 
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PeerConnectionMedia)
--- a/media/webrtc/signaling/test/signaling_unittests.cpp
+++ b/media/webrtc/signaling/test/signaling_unittests.cpp
@@ -22,16 +22,20 @@ using namespace std;
 
 #include "FakeMediaStreams.h"
 #include "FakeMediaStreamsImpl.h"
 #include "PeerConnectionImpl.h"
 #include "PeerConnectionCtx.h"
 #include "runnable_utils.h"
 #include "nsStaticComponents.h"
 #include "nsIDOMRTCPeerConnection.h"
+#include "nsServiceManagerUtils.h"
+#include "nsNetUtil.h"
+#include "nsIIOService.h"
+#include "nsIDNSService.h"
 #include "nsWeakReference.h"
 #include "nricectx.h"
 
 #include "mtransport_test_utils.h"
 MtransportTestUtils *test_utils;
 nsCOMPtr<nsIThread> gThread;
 
 
@@ -1135,17 +1139,16 @@ public:
     a1_.AddIceCandidate(candidate, mid, level, false);
   }
 
  protected:
   SignalingAgent a1_;  // Canonically "caller"
   SignalingAgent a2_;  // Canonically "callee"
 };
 
-
 TEST_F(SignalingTest, JustInit)
 {
 }
 
 TEST_F(SignalingTest, CreateSetOffer)
 {
   sipcc::MediaConstraints constraints;
   CreateSetOffer(constraints, SHOULD_SENDRECV_AV);