Bug 1567201 - Use mdns_service to handle mDNS queries; r=mjf
authorDan Minor <dminor@mozilla.com>
Tue, 01 Oct 2019 12:58:23 +0000
changeset 495824 b2f61006436d2fbea39d6a55ceb6ca991e02ec5e
parent 495823 2afa8a8a04450eac1dd07b3efcd3438cbb674d52
child 495825 6f29bc4ed9526784b6acbd8b1fb690dc9c426acf
push id114140
push userdvarga@mozilla.com
push dateWed, 02 Oct 2019 18:04:51 +0000
treeherdermozilla-inbound@32eb0ea893f3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmjf
bugs1567201
milestone71.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1567201 - Use mdns_service to handle mDNS queries; r=mjf Differential Revision: https://phabricator.services.mozilla.com/D46977
dom/media/webrtc/MediaTransportParent.h
dom/media/webrtc/PMediaTransport.ipdl
media/webrtc/signaling/gtest/mediapipeline_unittest.cpp
media/webrtc/signaling/src/peerconnection/MediaTransportHandler.cpp
media/webrtc/signaling/src/peerconnection/MediaTransportHandler.h
media/webrtc/signaling/src/peerconnection/MediaTransportHandlerIPC.cpp
media/webrtc/signaling/src/peerconnection/MediaTransportHandlerIPC.h
media/webrtc/signaling/src/peerconnection/MediaTransportParent.cpp
media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp
media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h
--- a/dom/media/webrtc/MediaTransportParent.h
+++ b/dom/media/webrtc/MediaTransportParent.h
@@ -44,17 +44,18 @@ class MediaTransportParent : public dom:
   mozilla::ipc::IPCResult RecvRemoveTransportsExcept(
       const StringVector& transportIds);
   mozilla::ipc::IPCResult RecvStartIceChecks(const bool& isControlling,
                                              const StringVector& iceOptions);
   mozilla::ipc::IPCResult RecvSendPacket(const string& transportId,
                                          const MediaPacket& packet);
   mozilla::ipc::IPCResult RecvAddIceCandidate(const string& transportId,
                                               const string& candidate,
-                                              const string& ufrag);
+                                              const string& ufrag,
+                                              const string& obfuscatedAddress);
   mozilla::ipc::IPCResult RecvUpdateNetworkState(const bool& online);
   mozilla::ipc::IPCResult RecvGetIceStats(
       const string& transportId, const double& now,
       const RTCStatsReportInternal& reportIn, GetIceStatsResolver&& aResolve);
 
   void ActorDestroy(ActorDestroyReason aWhy);
 
  private:
--- a/dom/media/webrtc/PMediaTransport.ipdl
+++ b/dom/media/webrtc/PMediaTransport.ipdl
@@ -76,17 +76,18 @@ parent:
 
   async StartIceChecks(bool isControlling,
                        StringVector iceOptions);
 
   async SendPacket(string transportId, MediaPacket packet);
 
   async AddIceCandidate(string transportId,
                         string candidate,
-                        string ufrag);
+                        string ufrag,
+                        string obfuscatedAddr);
 
   async UpdateNetworkState(bool online);
 
   async GetIceStats(string transportId,
                     double now,
                     RTCStatsReportInternal reportIn) returns (MovableRTCStatsReportInternal reportOut);
 
 child:
--- a/media/webrtc/signaling/gtest/mediapipeline_unittest.cpp
+++ b/media/webrtc/signaling/gtest/mediapipeline_unittest.cpp
@@ -182,18 +182,18 @@ class LoopbackTransport : public MediaTr
 
   void RemoveTransportsExcept(
       const std::set<std::string>& aTransportIds) override {}
 
   void StartIceChecks(bool aIsControlling,
                       const std::vector<std::string>& aIceOptions) override {}
 
   void AddIceCandidate(const std::string& aTransportId,
-                       const std::string& aCandidate,
-                       const std::string& aUfrag) override {}
+                       const std::string& aCandidate, const std::string& aUfrag,
+                       const std::string& aObfuscatedAddress) override {}
 
   void UpdateNetworkState(bool aOnline) override {}
 
   RefPtr<StatsPromise> GetIceStats(
       const std::string& aTransportId, DOMHighResTimeStamp aNow,
       std::unique_ptr<dom::RTCStatsReportInternal>&& aReport) override {
     return nullptr;
   }
--- a/media/webrtc/signaling/src/peerconnection/MediaTransportHandler.cpp
+++ b/media/webrtc/signaling/src/peerconnection/MediaTransportHandler.cpp
@@ -31,20 +31,16 @@
 #include "signaling/src/sdp/SdpAttribute.h"
 
 #include "runnable_utils.h"
 
 #include "mozilla/Telemetry.h"
 
 #include "mozilla/dom/RTCStatsReportBinding.h"
 
-// mDNS
-#include "nsIDNSRecord.h"
-#include "mozilla/net/DNS.h"
-
 #include "nss.h"                // For NSS_NoDB_Init
 #include "mozilla/PublicSSL.h"  // For psm::InitializeCipherSuite
 
 #include <string>
 #include <vector>
 #include <map>
 
 namespace mozilla {
@@ -102,18 +98,18 @@ class MediaTransportHandlerSTS : public 
 
   void RemoveTransportsExcept(
       const std::set<std::string>& aTransportIds) override;
 
   void StartIceChecks(bool aIsControlling,
                       const std::vector<std::string>& aIceOptions) override;
 
   void AddIceCandidate(const std::string& aTransportId,
-                       const std::string& aCandidate,
-                       const std::string& aUfrag) override;
+                       const std::string& aCandidate, const std::string& aUfrag,
+                       const std::string& aObfuscatedAddress) override;
 
   void UpdateNetworkState(bool aOnline) override;
 
   void SendPacket(const std::string& aTransportId,
                   MediaPacket&& aPacket) override;
 
   RefPtr<StatsPromise> GetIceStats(
       const std::string& aTransportId, DOMHighResTimeStamp aNow,
@@ -160,55 +156,18 @@ class MediaTransportHandlerSTS : public 
 
   virtual ~MediaTransportHandlerSTS() = default;
   nsCOMPtr<nsISerialEventTarget> mStsThread;
   RefPtr<NrIceCtx> mIceCtx;
   RefPtr<NrIceResolver> mDNSResolver;
   std::map<std::string, Transport> mTransports;
   bool mObfuscateHostAddresses = false;
 
-  // mDNS Support
-  class DNSListener final : public nsIDNSListener {
-    NS_DECL_THREADSAFE_ISUPPORTS
-    NS_DECL_NSIDNSLISTENER
-
-   public:
-    DNSListener(MediaTransportHandlerSTS& aTransportHandler,
-                const std::string& aTransportId, const std::string& aCandidate,
-                std::vector<std::string> aTokenizedCandidate,
-                const std::string& aUfrag)
-        : mTransportHandler(aTransportHandler),
-          mTransportId(aTransportId),
-          mCandidate(aCandidate),
-          mTokenizedCandidate(aTokenizedCandidate),
-          mUfrag(aUfrag) {}
+  std::set<std::string> mSignaledAddresses;
 
-    void Cancel() {
-      mCancel->Cancel(NS_ERROR_ABORT);
-      mCancel = nullptr;
-    }
-
-    MediaTransportHandlerSTS& mTransportHandler;
-
-    const std::string mTransportId;
-    const std::string mCandidate;
-    std::vector<std::string> mTokenizedCandidate;
-    const std::string mUfrag;
-
-    nsCOMPtr<nsICancelable> mCancel;
-
-   private:
-    ~DNSListener() = default;
-  };
-
-  void PendingDNSRequestResolved(DNSListener* aListener);
-
-  nsCOMPtr<nsIDNSService> mDNSService;
-  std::set<RefPtr<DNSListener>> mPendingDNSRequests;
-  std::set<std::string> mSignaledAddresses;
   // Init can only be done on main, but we want this to be usable on any thread
   typedef MozPromise<bool, std::string, false> InitPromise;
   RefPtr<InitPromise> mInitPromise;
 };
 
 /* static */
 already_AddRefed<MediaTransportHandler> MediaTransportHandler::Create(
     nsISerialEventTarget* aCallbackThread) {
@@ -477,21 +436,16 @@ nsresult MediaTransportHandlerSTS::Creat
 void MediaTransportHandlerSTS::Destroy() {
   if (!mInitPromise) {
     return;
   }
 
   mInitPromise->Then(
       mStsThread, __func__,
       [this, self = RefPtr<MediaTransportHandlerSTS>(this)]() {
-        for (auto& listener : mPendingDNSRequests) {
-          listener->Cancel();
-        }
-        mPendingDNSRequests.clear();
-
         disconnect_all();
         if (mIceCtx) {
           NrIceStats stats = mIceCtx->Destroy();
           CSFLogDebug(LOGTAG,
                       "Ice Telemetry: stun (retransmits: %d)"
                       "   turn (401s: %d   403s: %d   438s: %d)",
                       stats.stun_retransmits, stats.turn_401s, stats.turn_403s,
                       stats.turn_438s);
@@ -717,80 +671,35 @@ static void TokenizeCandidate(const std:
 
   std::istringstream iss(aCandidate);
   std::string token;
   while (std::getline(iss, token, ' ')) {
     aTokens.push_back(token);
   }
 }
 
-void MediaTransportHandlerSTS::AddIceCandidate(const std::string& aTransportId,
-                                               const std::string& aCandidate,
-                                               const std::string& aUfrag) {
+void MediaTransportHandlerSTS::AddIceCandidate(
+    const std::string& aTransportId, const std::string& aCandidate,
+    const std::string& aUfrag, const std::string& aObfuscatedAddress) {
   mInitPromise->Then(
       mStsThread, __func__,
       [=, self = RefPtr<MediaTransportHandlerSTS>(this)]() {
         std::vector<std::string> tokens;
         TokenizeCandidate(aCandidate, tokens);
 
-        if (tokens.size() > 4) {
-          std::string addr = tokens[4];
-
-          // Check for address ending with .local
-          size_t nPeriods = std::count(addr.begin(), addr.end(), '.');
-          size_t dotLocalLength = 6;  // length of ".local"
-
-          if (nPeriods == 1 &&
-              addr.rfind(".local") + dotLocalLength == addr.length()) {
-            CSFLogDebug(
-                LOGTAG,
-                "Using mDNS to resolve candidate with transport id: %s: %s",
-                aTransportId.c_str(), aCandidate.c_str());
-
-            auto listener =
-                *(mPendingDNSRequests
-                      .emplace(new DNSListener(*this, aTransportId, aCandidate,
-                                               tokens, aUfrag))
-                      .first);
-            OriginAttributes attrs;
-
-            if (!mDNSService) {
-              nsresult rv;
-              mDNSService = do_GetService(NS_DNSSERVICE_CONTRACTID, &rv);
-              if (NS_FAILED(rv)) {
-                MOZ_ASSERT(false);
-                MOZ_CRASH();
-              }
-            }
-
-            if (NS_FAILED(mDNSService->AsyncResolveNative(
-                    nsAutoCString(tokens[4].c_str()), 0, listener, mStsThread,
-                    attrs, getter_AddRefs(listener->mCancel)))) {
-              CSFLogError(
-                  LOGTAG,
-                  "Error using mDNS to resolve candidate with transport id "
-                  "%s: %s",
-                  aTransportId.c_str(), aCandidate.c_str());
-            }
-            // TODO: Bug 1535690, we don't want to tell the ICE context that
-            // remote trickle is done if we are waiting to resolve a mDNS
-            // candidate.
-            return;
-          }
-        }
-
         RefPtr<NrIceMediaStream> stream(mIceCtx->GetStream(aTransportId));
         if (!stream) {
           CSFLogError(LOGTAG,
                       "No ICE stream for candidate with transport id %s: %s",
                       aTransportId.c_str(), aCandidate.c_str());
           return;
         }
 
-        nsresult rv = stream->ParseTrickleCandidate(aCandidate, aUfrag, "");
+        nsresult rv = stream->ParseTrickleCandidate(aCandidate, aUfrag,
+                                                    aObfuscatedAddress);
         if (NS_SUCCEEDED(rv)) {
           if (mObfuscateHostAddresses && tokens.size() > 4) {
             mSignaledAddresses.insert(tokens[4]);
           }
         } else {
           CSFLogError(LOGTAG,
                       "Couldn't process ICE candidate with transport id %s: "
                       "%s",
@@ -1027,21 +936,16 @@ MediaTransportHandlerSTS::GetIceStats(
               GetIceStats(*stream, aNow, aReport.get());
             }
           }
         }
         return StatsPromise::CreateAndResolve(std::move(aReport), __func__);
       });
 }
 
-void MediaTransportHandlerSTS::PendingDNSRequestResolved(
-    DNSListener* aListener) {
-  mPendingDNSRequests.erase(aListener);
-}
-
 RefPtr<MediaTransportHandler::IceLogPromise>
 MediaTransportHandlerSTS::GetIceLog(const nsCString& aPattern) {
   return InvokeAsync(
       mStsThread, __func__, [=, self = RefPtr<MediaTransportHandlerSTS>(this)] {
         dom::Sequence<nsString> converted;
         RLogConnector* logs = RLogConnector::GetInstance();
         nsAutoPtr<std::deque<std::string>> result(new std::deque<std::string>);
         // Might not exist yet.
@@ -1409,95 +1313,9 @@ void MediaTransportHandlerSTS::PacketRec
   OnPacketReceived(aLayer->flow_id(), aPacket);
 }
 
 void MediaTransportHandlerSTS::EncryptedPacketSending(TransportLayer* aLayer,
                                                       MediaPacket& aPacket) {
   OnEncryptedSending(aLayer->flow_id(), aPacket);
 }
 
-NS_IMPL_ISUPPORTS(MediaTransportHandlerSTS::DNSListener, nsIDNSListener);
-
-nsresult MediaTransportHandlerSTS::DNSListener::OnLookupComplete(
-    nsICancelable* aRequest, nsIDNSRecord* aRecord, nsresult aStatus) {
-  if (mCancel) {
-    MOZ_ASSERT(mTransportHandler.mStsThread->IsOnCurrentThread());
-    if (NS_SUCCEEDED(aStatus)) {
-      nsTArray<net::NetAddr> addresses;
-      aRecord->GetAddresses(addresses);
-
-      // https://tools.ietf.org/html/draft-ietf-rtcweb-mdns-ice-candidates-03#section-3.2.2
-      if (addresses.Length() == 1) {
-        char buf[net::kIPv6CStrBufSize];
-        if (!net::NetAddrToString(&addresses[0], buf, sizeof(buf))) {
-          CSFLogError(LOGTAG,
-                      "Unable to convert mDNS address for candidate with"
-                      " transport id %s: %s",
-                      mTransportId.c_str(), mCandidate.c_str());
-          return NS_OK;
-        }
-
-        CSFLogDebug(LOGTAG,
-                    "Adding mDNS candidate with transport id: %s: %s:"
-                    " resolved to: %s",
-                    mTransportId.c_str(), mCandidate.c_str(), buf);
-
-        // Replace obfuscated address with actual address
-        std::string obfuscatedAddr = mTokenizedCandidate[4];
-        mTokenizedCandidate[4] = buf;
-        std::ostringstream o;
-        for (size_t i = 0; i < mTokenizedCandidate.size(); ++i) {
-          o << mTokenizedCandidate[i];
-          if (i + 1 != mTokenizedCandidate.size()) {
-            o << " ";
-          }
-        }
-
-        std::string mungedCandidate = o.str();
-
-        RefPtr<NrIceMediaStream> stream(
-            mTransportHandler.mIceCtx->GetStream(mTransportId));
-        if (!stream) {
-          CSFLogError(LOGTAG,
-                      "No ICE stream for candidate with transport id %s: %s",
-                      mTransportId.c_str(), mCandidate.c_str());
-          return NS_OK;
-        }
-
-        nsresult rv = stream->ParseTrickleCandidate(mungedCandidate, mUfrag,
-                                                    obfuscatedAddr);
-        if (NS_FAILED(rv)) {
-          CSFLogError(LOGTAG,
-                      "Couldn't process ICE candidate with transport id %s: "
-                      "%s",
-                      mTransportId.c_str(), mCandidate.c_str());
-        }
-      } else {
-        CSFLogError(LOGTAG,
-                    "More than one mDNS result for candidate with transport"
-                    " id: %s: %s, candidate ignored",
-                    mTransportId.c_str(), mCandidate.c_str());
-      }
-    } else {
-      CSFLogError(LOGTAG,
-                  "Using mDNS failed for candidate with transport id: %s: %s",
-                  mTransportId.c_str(), mCandidate.c_str());
-    }
-
-    mCancel = nullptr;
-    mTransportHandler.PendingDNSRequestResolved(this);
-  }
-
-  return NS_OK;
-}
-
-nsresult MediaTransportHandlerSTS::DNSListener::OnLookupByTypeComplete(
-    nsICancelable* aRequest, nsIDNSByTypeRecord* aResult, nsresult aStatus) {
-  MOZ_ASSERT_UNREACHABLE(
-      "MediaTranportHandlerSTS::DNSListener::OnLookupByTypeComplete");
-  if (mCancel) {
-    mCancel = nullptr;
-    mTransportHandler.PendingDNSRequestResolved(this);
-  }
-  return NS_OK;
-}
-
 }  // namespace mozilla
--- a/media/webrtc/signaling/src/peerconnection/MediaTransportHandler.h
+++ b/media/webrtc/signaling/src/peerconnection/MediaTransportHandler.h
@@ -105,17 +105,18 @@ class MediaTransportHandler {
   virtual void StartIceChecks(bool aIsControlling,
                               const std::vector<std::string>& aIceOptions) = 0;
 
   virtual void SendPacket(const std::string& aTransportId,
                           MediaPacket&& aPacket) = 0;
 
   virtual void AddIceCandidate(const std::string& aTransportId,
                                const std::string& aCandidate,
-                               const std::string& aUFrag) = 0;
+                               const std::string& aUFrag,
+                               const std::string& aObfuscatedAddress) = 0;
 
   virtual void UpdateNetworkState(bool aOnline) = 0;
 
   // dom::RTCStatsReportInternal doesn't have move semantics.
   typedef MozPromise<std::unique_ptr<dom::RTCStatsReportInternal>, nsresult,
                      true>
       StatsPromise;
   virtual RefPtr<StatsPromise> GetIceStats(
--- a/media/webrtc/signaling/src/peerconnection/MediaTransportHandlerIPC.cpp
+++ b/media/webrtc/signaling/src/peerconnection/MediaTransportHandlerIPC.cpp
@@ -275,24 +275,25 @@ void MediaTransportHandlerIPC::SendPacke
        aPacket = std::move(aPacket)](bool /*dummy*/) mutable {
         if (mChild) {
           mChild->SendSendPacket(aTransportId, aPacket);
         }
       },
       [](const nsCString& aError) {});
 }
 
-void MediaTransportHandlerIPC::AddIceCandidate(const std::string& aTransportId,
-                                               const std::string& aCandidate,
-                                               const std::string& aUfrag) {
+void MediaTransportHandlerIPC::AddIceCandidate(
+    const std::string& aTransportId, const std::string& aCandidate,
+    const std::string& aUfrag, const std::string& aObfuscatedAddress) {
   mInitPromise->Then(
       mCallbackThread, __func__,
       [=, self = RefPtr<MediaTransportHandlerIPC>(this)](bool /*dummy*/) {
         if (mChild) {
-          mChild->SendAddIceCandidate(aTransportId, aCandidate, aUfrag);
+          mChild->SendAddIceCandidate(aTransportId, aCandidate, aUfrag,
+                                      aObfuscatedAddress);
         }
       },
       [](const nsCString& aError) {});
 }
 
 void MediaTransportHandlerIPC::UpdateNetworkState(bool aOnline) {
   mInitPromise->Then(
       mCallbackThread, __func__,
--- a/media/webrtc/signaling/src/peerconnection/MediaTransportHandlerIPC.h
+++ b/media/webrtc/signaling/src/peerconnection/MediaTransportHandlerIPC.h
@@ -61,18 +61,18 @@ class MediaTransportHandlerIPC : public 
 
   void StartIceChecks(bool aIsControlling,
                       const std::vector<std::string>& aIceOptions) override;
 
   void SendPacket(const std::string& aTransportId,
                   MediaPacket&& aPacket) override;
 
   void AddIceCandidate(const std::string& aTransportId,
-                       const std::string& aCandidate,
-                       const std::string& aUfrag) override;
+                       const std::string& aCandidate, const std::string& aUfrag,
+                       const std::string& aObfuscatedAddress) override;
 
   void UpdateNetworkState(bool aOnline) override;
 
   RefPtr<StatsPromise> GetIceStats(
       const std::string& aTransportId, DOMHighResTimeStamp aNow,
       std::unique_ptr<dom::RTCStatsReportInternal>&& aReport) override;
 
  private:
--- a/media/webrtc/signaling/src/peerconnection/MediaTransportParent.cpp
+++ b/media/webrtc/signaling/src/peerconnection/MediaTransportParent.cpp
@@ -193,18 +193,20 @@ mozilla::ipc::IPCResult MediaTransportPa
 mozilla::ipc::IPCResult MediaTransportParent::RecvSendPacket(
     const string& transportId, const MediaPacket& packet) {
   MediaPacket copy(packet);  // Laaaaaaame.
   mImpl->mHandler->SendPacket(transportId, std::move(copy));
   return ipc::IPCResult::Ok();
 }
 
 mozilla::ipc::IPCResult MediaTransportParent::RecvAddIceCandidate(
-    const string& transportId, const string& candidate, const string& ufrag) {
-  mImpl->mHandler->AddIceCandidate(transportId, candidate, ufrag);
+    const string& transportId, const string& candidate, const string& ufrag,
+    const string& obfuscatedAddr) {
+  mImpl->mHandler->AddIceCandidate(transportId, candidate, ufrag,
+                                   obfuscatedAddr);
   return ipc::IPCResult::Ok();
 }
 
 mozilla::ipc::IPCResult MediaTransportParent::RecvUpdateNetworkState(
     const bool& online) {
   mImpl->mHandler->UpdateNetworkState(online);
   return ipc::IPCResult::Ok();
 }
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp
@@ -36,33 +36,52 @@ using namespace dom;
 
 static const char* pcmLogTag = "PeerConnectionMedia";
 #ifdef LOGTAG
 #  undef LOGTAG
 #endif
 #define LOGTAG pcmLogTag
 
 void PeerConnectionMedia::StunAddrsHandler::OnMDNSQueryComplete(
-    const nsCString& hostname, const nsCString& address) {}
+    const nsCString& hostname, const nsCString& address) {
+  ASSERT_ON_THREAD(pcm_->mMainThread);
+  auto itor = pcm_->mQueriedMDNSHostnames.find(hostname.BeginReading());
+  if (itor != pcm_->mQueriedMDNSHostnames.end()) {
+    for (auto& cand : itor->second) {
+      // Replace obfuscated address with actual address
+      std::string obfuscatedAddr = cand.mTokenizedCandidate[4];
+      cand.mTokenizedCandidate[4] = address.BeginReading();
+      std::ostringstream o;
+      for (size_t i = 0; i < cand.mTokenizedCandidate.size(); ++i) {
+        o << cand.mTokenizedCandidate[i];
+        if (i + 1 != cand.mTokenizedCandidate.size()) {
+          o << " ";
+        }
+      }
+      std::string mungedCandidate = o.str();
+      pcm_->mTransportHandler->AddIceCandidate(
+          cand.mTransportId, mungedCandidate, cand.mUfrag, obfuscatedAddr);
+    }
+    pcm_->mQueriedMDNSHostnames.erase(itor);
+  }
+}
 
 void PeerConnectionMedia::StunAddrsHandler::OnStunAddrsAvailable(
     const mozilla::net::NrIceStunAddrArray& addrs) {
   CSFLogInfo(LOGTAG, "%s: receiving (%d) stun addrs", __FUNCTION__,
              (int)addrs.Length());
   if (pcm_) {
     pcm_->mStunAddrs = addrs;
     pcm_->mLocalAddrsCompleted = true;
     pcm_->FlushIceCtxOperationQueueIfReady();
     // If parent process returns 0 STUN addresses, change ICE connection
     // state to failed.
     if (!pcm_->mStunAddrs.Length()) {
       pcm_->IceConnectionStateChange_m(dom::RTCIceConnectionState::Failed);
     }
-
-    pcm_ = nullptr;
   }
 }
 
 PeerConnectionMedia::PeerConnectionMedia(PeerConnectionImpl* parent)
     : mTransportHandler(parent->GetTransportHandler()),
       mParent(parent),
       mParentHandle(parent->GetHandle()),
       mParentName(parent->GetName()),
@@ -312,18 +331,62 @@ void PeerConnectionMedia::ConnectSignals
       this, &PeerConnectionMedia::OnCandidateFound_s);
   mTransportHandler->SignalAlpnNegotiated.connect(
       this, &PeerConnectionMedia::AlpnNegotiated_s);
 }
 
 void PeerConnectionMedia::AddIceCandidate(const std::string& aCandidate,
                                           const std::string& aTransportId,
                                           const std::string& aUfrag) {
+  ASSERT_ON_THREAD(mMainThread);
   MOZ_ASSERT(!aTransportId.empty());
-  mTransportHandler->AddIceCandidate(aTransportId, aCandidate, aUfrag);
+
+  bool obfuscate_host_addresses = Preferences::GetBool(
+      "media.peerconnection.ice.obfuscate_host_addresses", false);
+
+  if (obfuscate_host_addresses) {
+    std::vector<std::string> tokens;
+    TokenizeCandidate(aCandidate, tokens);
+
+    if (tokens.size() > 4) {
+      std::string addr = tokens[4];
+
+      // Check for address ending with .local
+      size_t nPeriods = std::count(addr.begin(), addr.end(), '.');
+      size_t dotLocalLength = 6;  // length of ".local"
+
+      if (nPeriods == 1 &&
+          addr.rfind(".local") + dotLocalLength == addr.length()) {
+        if (mStunAddrsRequest) {
+          PendingIceCandidate cand;
+          cand.mTokenizedCandidate = std::move(tokens);
+          cand.mTransportId = aTransportId;
+          cand.mUfrag = aUfrag;
+          mQueriedMDNSHostnames[addr].push_back(cand);
+
+          mMainThread->Dispatch(NS_NewRunnableFunction(
+              "PeerConnectionMedia::SendQueryMDNSHostname",
+              [self = RefPtr<PeerConnectionMedia>(this), addr]() mutable {
+                if (self->mStunAddrsRequest) {
+                  self->mStunAddrsRequest->SendQueryMDNSHostname(
+                      nsCString(nsAutoCString(addr.c_str())));
+                }
+                NS_ReleaseOnMainThreadSystemGroup(
+                    "PeerConnectionMedia::SendQueryMDNSHostname",
+                    self.forget());
+              }));
+        }
+        // TODO: Bug 1535690, we don't want to tell the ICE context that remote
+        // trickle is done if we are waiting to resolve a mDNS candidate.
+        return;
+      }
+    }
+  }
+
+  mTransportHandler->AddIceCandidate(aTransportId, aCandidate, aUfrag, "");
 }
 
 void PeerConnectionMedia::UpdateNetworkState(bool online) {
   mTransportHandler->UpdateNetworkState(online);
 }
 
 void PeerConnectionMedia::FlushIceCtxOperationQueueIfReady() {
   ASSERT_ON_THREAD(mMainThread);
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h
@@ -227,14 +227,22 @@ class PeerConnectionMedia : public sigsl
   bool mTargetForDefaultLocalAddressLookupIsSet;
 
   // Set to true when the object is going to be released.
   bool mDestroyed;
 
   // Used to store the mDNS hostnames that we have registered
   std::set<std::string> mRegisteredMDNSHostnames;
 
+  // Used to store the mDNS hostnames that we have queried
+  struct PendingIceCandidate {
+    std::vector<std::string> mTokenizedCandidate;
+    std::string mTransportId;
+    std::string mUfrag;
+  };
+  std::map<std::string, std::list<PendingIceCandidate>> mQueriedMDNSHostnames;
+
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PeerConnectionMedia)
 };
 
 }  // namespace mozilla
 
 #endif