Bug 1345511 - pt 3 - start using IPC call for stun addrs in PCMedia. r=bwc draft
authorMichael Froman <mfroman@mozilla.com>
Wed, 22 Mar 2017 09:59:46 -0500
changeset 503032 5b14b102ca4f7da72534ac17a5537c9fc03b4bad
parent 502598 d5c948a804285b62c263d766b363c838889c406c
child 550314 9735ceb06107da52d102d7876670b60a9d2cf52f
push id50460
push userbmo:mfroman@nostrum.com
push dateWed, 22 Mar 2017 17:37:19 +0000
reviewersbwc
bugs1345511
milestone55.0a1
Bug 1345511 - pt 3 - start using IPC call for stun addrs in PCMedia. r=bwc Two new calls are added to NrIceCtx. 1) A static call to allow StunAddrsRequestParent to get stun addrs from the main process. 2) A call to allow StunAddrsRequestChild to pass the new stun addrs back to PeerConnectionMedia on the content process. PeerConnectionMedia, when running in e10s mode, sets up the StunAddrsRequestChild and makes the async request to get the stun addrs. When they are returned, it sets the stun addrs in NrIceCtx avoid the network calls that would otherwise cause a further restricted sandbox to fail. MozReview-Commit-ID: C2hYBzm6WNv
media/mtransport/ipc/StunAddrsRequestParent.cpp
media/mtransport/nricectx.cpp
media/mtransport/nricectx.h
media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp
media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h
--- a/media/mtransport/ipc/StunAddrsRequestParent.cpp
+++ b/media/mtransport/ipc/StunAddrsRequestParent.cpp
@@ -44,17 +44,17 @@ StunAddrsRequestParent::ActorDestroy(Act
 }
 
 void
 StunAddrsRequestParent::GetStunAddrs_s()
 {
   ASSERT_ON_THREAD(mSTSThread);
 
   // get the stun addresses while on STS thread
-  NrIceStunAddrArray addrs; // = NrIceCtx::GetStunAddrs();
+  NrIceStunAddrArray addrs = NrIceCtx::GetStunAddrs();
 
   // in order to return the result over IPC, we need to be on main thread
   RUN_ON_THREAD(mMainThread,
                 WrapRunnable(this,
                              &StunAddrsRequestParent::SendStunAddrs_m,
                              std::move(addrs)),
                 NS_DISPATCH_NORMAL);
 }
--- a/media/mtransport/nricectx.cpp
+++ b/media/mtransport/nricectx.cpp
@@ -77,16 +77,17 @@ extern "C" {
 #include "transport_addr.h"
 #include "nr_crypto.h"
 #include "nr_socket.h"
 #include "nr_socket_local.h"
 #include "nr_proxy_tunnel.h"
 #include "stun_client_ctx.h"
 #include "stun_reg.h"
 #include "stun_server_ctx.h"
+#include "stun_util.h"
 #include "ice_codeword.h"
 #include "ice_ctx.h"
 #include "ice_candidate.h"
 #include "ice_handler.h"
 }
 
 // Local includes
 #include "nricectx.h"
@@ -515,16 +516,61 @@ NrIceCtx::GetNewPwd()
   }
 
   std::string pwdStr = pwd;
   RFREE(pwd);
 
   return pwdStr;
 }
 
+#define MAXADDRS 100 // mirrors setting in ice_ctx.c
+
+/* static */
+nsTArray<NrIceStunAddr>
+NrIceCtx::GetStunAddrs()
+{
+  nsTArray<NrIceStunAddr> addrs;
+
+  nr_local_addr local_addrs[MAXADDRS];
+  int addr_ct=0;
+
+  // most likely running on parent process and need crypto vtbl
+  // initialized on Windows (Linux and OSX don't seem to care)
+  if (!initialized) {
+    nr_crypto_vtbl = &nr_ice_crypto_nss_vtbl;
+  }
+
+  MOZ_MTLOG(ML_INFO, "NrIceCtx static call to find local stun addresses");
+  if (nr_stun_find_local_addresses(local_addrs, MAXADDRS, &addr_ct)) {
+    MOZ_MTLOG(ML_INFO, "Error finding local stun addresses");
+  } else {
+    for(int i=0; i<addr_ct; ++i) {
+      NrIceStunAddr addr(&local_addrs[i]);
+      addrs.AppendElement(addr);
+    }
+  }
+
+  return addrs;
+}
+
+void
+NrIceCtx::SetStunAddrs(const nsTArray<NrIceStunAddr>& addrs)
+{
+  nr_local_addr* local_addrs;
+  local_addrs = new nr_local_addr[addrs.Length()];
+
+  for(size_t i=0; i<addrs.Length(); ++i) {
+    nr_local_addr_copy(&local_addrs[i],
+                       const_cast<nr_local_addr*>(&addrs[i].localAddr()));
+  }
+  nr_ice_set_local_addresses(ctx_, local_addrs, addrs.Length());
+
+  delete[] local_addrs;
+}
+
 bool
 NrIceCtx::Initialize()
 {
   std::string ufrag = GetNewUfrag();
   std::string pwd = GetNewPwd();
 
   return Initialize(ufrag, pwd);
 }
--- a/media/mtransport/nricectx.h
+++ b/media/mtransport/nricectx.h
@@ -58,18 +58,20 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 #include "prnetdb.h"
 
 #include "mozilla/RefPtr.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/UniquePtr.h"
 #include "nsAutoPtr.h"
 #include "nsIEventTarget.h"
 #include "nsITimer.h"
+#include "nsTArray.h"
 
 #include "m_cpp_utils.h"
+#include "nricestunaddr.h"
 
 typedef struct nr_ice_ctx_ nr_ice_ctx;
 typedef struct nr_ice_peer_ctx_ nr_ice_peer_ctx;
 typedef struct nr_ice_media_stream_ nr_ice_media_stream;
 typedef struct nr_ice_handler_ nr_ice_handler;
 typedef struct nr_ice_handler_vtbl_ nr_ice_handler_vtbl;
 typedef struct nr_ice_candidate_ nr_ice_candidate;
 typedef struct nr_ice_cand_pair_ nr_ice_cand_pair;
@@ -228,16 +230,21 @@ class NrIceCtx {
 
   // initialize ICE globals, crypto, and logging
   static void InitializeGlobals(bool allow_loopback = false,
                                 bool tcp_enabled = true,
                                 bool allow_link_local = false);
   static std::string GetNewUfrag();
   static std::string GetNewPwd();
 
+  // static GetStunAddrs for use in parent process to support
+  // sandboxing restrictions
+  static nsTArray<NrIceStunAddr> GetStunAddrs();
+  void SetStunAddrs(const nsTArray<NrIceStunAddr>& addrs);
+
   bool Initialize();
   bool Initialize(const std::string& ufrag, const std::string& pwd);
 
   int SetNat(const RefPtr<TestNat>& aNat);
 
   // Deinitialize all ICE global state. Used only for testing.
   static void internal_DeinitializeGlobal();
 
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp
@@ -254,27 +254,62 @@ PeerConnectionMedia::ProtocolProxyQueryH
   } else {
     CSFLogError(logTag, "%s: Failed to set proxy server (ICE ctx unavailable)",
         __FUNCTION__);
   }
 }
 
 NS_IMPL_ISUPPORTS(PeerConnectionMedia::ProtocolProxyQueryHandler, nsIProtocolProxyCallback)
 
+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_->mStunAddrsRequest = nullptr;
+    pcm_->FlushIceCtxOperationQueueIfReady();
+    pcm_ = nullptr;
+  }
+}
+
 PeerConnectionMedia::PeerConnectionMedia(PeerConnectionImpl *parent)
     : mParent(parent),
       mParentHandle(parent->GetHandle()),
       mParentName(parent->GetName()),
       mIceCtxHdlr(nullptr),
       mDNSResolver(new NrIceResolver()),
       mUuidGen(MakeUnique<PCUuidGenerator>()),
       mMainThread(mParent->GetMainThread()),
       mSTSThread(mParent->GetSTSThread()),
       mProxyResolveCompleted(false),
-      mIceRestartState(ICE_RESTART_NONE) {
+      mIceRestartState(ICE_RESTART_NONE),
+      mLocalAddrsCompleted(false) {
+}
+
+void
+PeerConnectionMedia::InitLocalAddrs()
+{
+  if (XRE_IsContentProcess()) {
+    CSFLogDebug(logTag, "%s: Get stun addresses via IPC",
+                mParentHandle.c_str());
+    // We're in the content process, so send a request over IPC for the
+    // stun address discovery.
+    mStunAddrsRequest =
+        new StunAddrsRequestChild(new StunAddrsHandler(this));
+    mStunAddrsRequest->SendGetStunAddrs();
+  } else {
+    // No content process, so don't need to hold up the ice event queue
+    // until completion of stun address discovery. We can let the
+    // discovery of stun addresses happen in the same process.
+    mLocalAddrsCompleted = true;
+  }
 }
 
 nsresult
 PeerConnectionMedia::InitProxy()
 {
   // Allow mochitests to disable this, since mochitest configures a fake proxy
   // that serves up content.
   bool disable = Preferences::GetBool("media.peerconnection.disable_http_proxy",
@@ -348,16 +383,19 @@ nsresult PeerConnectionMedia::Init(const
                                    const std::vector<NrIceTurnServer>& turn_servers,
                                    NrIceCtx::Policy policy)
 {
   nsresult rv = InitProxy();
   NS_ENSURE_SUCCESS(rv, rv);
 
   bool ice_tcp = Preferences::GetBool("media.peerconnection.ice.tcp", false);
 
+  // setup the stun local addresses IPC async call
+  InitLocalAddrs();
+
   // TODO(ekr@rtfm.com): need some way to set not offerer later
   // Looks like a bug in the NrIceCtx API.
   mIceCtxHdlr = NrIceCtxHandler::Create("PC:" + mParentName,
                                         mParent->GetAllowIceLoopback(),
                                         ice_tcp,
                                         mParent->GetAllowIceLinkLocal(),
                                         policy);
   if(!mIceCtxHdlr) {
@@ -915,16 +953,20 @@ PeerConnectionMedia::EnsureIceGathering_
   if (mProxyServer) {
     mIceCtxHdlr->ctx()->SetProxyServer(*mProxyServer);
   } else if (aProxyOnly) {
     IceGatheringStateChange_s(mIceCtxHdlr->ctx().get(),
                               NrIceCtx::ICE_CTX_GATHER_COMPLETE);
     return;
   }
 
+  if (mStunAddrs.Length()) {
+    mIceCtxHdlr->ctx()->SetStunAddrs(mStunAddrs);
+  }
+
   // Start gathering, but only if there are streams
   for (size_t i = 0; i < mIceCtxHdlr->ctx()->GetStreamCount(); ++i) {
     if (mIceCtxHdlr->ctx()->GetStream(i)) {
       mIceCtxHdlr->ctx()->StartGathering(aDefaultRouteOnly, aProxyOnly);
       return;
     }
   }
 
@@ -1012,16 +1054,21 @@ PeerConnectionMedia::SelfDestruct()
   for (uint32_t i=0; i < mLocalSourceStreams.Length(); ++i) {
     mLocalSourceStreams[i]->DetachMedia_m();
   }
 
   for (uint32_t i=0; i < mRemoteSourceStreams.Length(); ++i) {
     mRemoteSourceStreams[i]->DetachMedia_m();
   }
 
+  if (mStunAddrsRequest) {
+    mStunAddrsRequest->Cancel();
+    mStunAddrsRequest = nullptr;
+  }
+
   if (mProxyRequest) {
     mProxyRequest->Cancel(NS_ERROR_ABORT);
     mProxyRequest = nullptr;
   }
 
   // Shutdown the transport (async)
   RUN_ON_THREAD(mSTSThread, WrapRunnable(
       this, &PeerConnectionMedia::ShutdownMediaTransport_s),
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h
@@ -9,16 +9,17 @@
 #include <vector>
 #include <map>
 
 #include "nspr.h"
 #include "prlock.h"
 
 #include "mozilla/RefPtr.h"
 #include "mozilla/UniquePtr.h"
+#include "mozilla/net/StunAddrsRequestChild.h"
 #include "nsComponentManagerUtils.h"
 #include "nsIProtocolProxyCallback.h"
 
 #include "signaling/src/jsep/JsepSession.h"
 #include "AudioSegment.h"
 
 #include "Layers.h"
 #include "VideoUtils.h"
@@ -426,16 +427,17 @@ class PeerConnectionMedia : public sigsl
                    const std::string&, uint16_t, uint16_t>
       SignalUpdateDefaultCandidate;
   sigslot::signal1<uint16_t>
       SignalEndOfLocalCandidates;
 
   RefPtr<WebRtcCallWrapper> mCall;
 
  private:
+  void InitLocalAddrs(); // for stun local address IPC request
   nsresult InitProxy();
   class ProtocolProxyQueryHandler : public nsIProtocolProxyCallback {
    public:
     explicit ProtocolProxyQueryHandler(PeerConnectionMedia *pcm) :
       pcm_(pcm) {}
 
     NS_IMETHOD OnProxyAvailable(nsICancelable *request,
                                 nsIChannel *aChannel,
@@ -444,16 +446,27 @@ class PeerConnectionMedia : public sigsl
     NS_DECL_ISUPPORTS
 
    private:
     void SetProxyOnPcm(nsIProxyInfo& proxyinfo);
     RefPtr<PeerConnectionMedia> pcm_;
     virtual ~ProtocolProxyQueryHandler() {}
   };
 
+  class StunAddrsHandler : public net::StunAddrsListener {
+   public:
+    explicit StunAddrsHandler(PeerConnectionMedia *pcm) :
+      pcm_(pcm) {}
+    void OnStunAddrsAvailable(
+        const mozilla::net::NrIceStunAddrArray& addrs) override;
+   private:
+    RefPtr<PeerConnectionMedia> pcm_;
+    virtual ~StunAddrsHandler() {}
+  };
+
   // Shutdown media transport. Must be called on STS thread.
   void ShutdownMediaTransport_s();
 
   // Final destruction of the media stream. Must be called on the main
   // thread.
   void SelfDestruct_m();
 
   // Manage ICE transports.
@@ -517,17 +530,17 @@ class PeerConnectionMedia : public sigsl
                           uint16_t aDefaultRtcpPort,
                           uint16_t aMLine);
   void EndOfLocalCandidates_m(const std::string& aDefaultAddr,
                               uint16_t aDefaultPort,
                               const std::string& aDefaultRtcpAddr,
                               uint16_t aDefaultRtcpPort,
                               uint16_t aMLine);
   bool IsIceCtxReady() const {
-    return mProxyResolveCompleted;
+    return mProxyResolveCompleted && mLocalAddrsCompleted;
   }
 
   // The parent PC
   PeerConnectionImpl *mParent;
   // and a loose handle on it for event driven stuff
   std::string mParentHandle;
   std::string mParentName;
 
@@ -572,14 +585,23 @@ class PeerConnectionMedia : public sigsl
   bool mProxyResolveCompleted;
 
   // Used to store the result of the request.
   UniquePtr<NrIceProxyServer> mProxyServer;
 
   // Used to track the state of ice restart
   IceRestartState mIceRestartState;
 
+  // Used to cancel incoming stun addrs response
+  RefPtr<net::StunAddrsRequestChild> mStunAddrsRequest;
+
+  // Used to track the state of the stun addr IPC request
+  bool mLocalAddrsCompleted;
+
+  // Used to store the result of the stun addr IPC request
+  nsTArray<NrIceStunAddr> mStunAddrs;
+
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PeerConnectionMedia)
 };
 
 } // namespace mozilla
 
 #endif