Bug 1345511 - pt 3 - start using IPC call for stun addrs in PCMedia. r=bwc draft
authorMichael Froman <mfroman@mozilla.com>
Thu, 16 Mar 2017 13:04:44 -0500
changeset 500168 0db6a46804a4eaadb5d6c60ac62824e1e1af4c0d
parent 500167 79d36cac6da5b9ac3aa258976196e8e633d32612
child 549562 c185b633d017daa2477f5e6121f683779435410a
push id49641
push userbmo:mfroman@nostrum.com
push dateThu, 16 Mar 2017 19:45:20 +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
@@ -50,17 +50,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,54 @@ NrIceCtx::GetNewPwd()
   }
 
   std::string pwdStr = pwd;
   RFREE(pwd);
 
   return pwdStr;
 }
 
+#define MAXADDRS 100 // mirrors setting in ice_ctx.c
+
+nsTArray<NrIceStunAddr>
+NrIceCtx::GetStunAddrs()
+{
+  nsTArray<NrIceStunAddr> addrs;
+
+  nr_local_addr local_addrs[MAXADDRS];
+  int addr_ct=0;
+
+  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_get_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 main process to support
+  // future 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,67 @@ 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();
+  }
+}
+
 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(bool allowLoopback,
+                                    bool tcpEnabled,
+                                    bool allowLinkLocal)
+{
+  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.
+    // Note that since NrIceCtx::InitializeGlobals also initializes some
+    // some settings in nICEr, we need to send along enough information
+    // to allow an NrIceCtx to initialize on the main process.
+    mStunAddrsRequest =
+        new StunAddrsRequestChild(allowLoopback, tcpEnabled, allowLinkLocal,
+                                  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 normally.
+    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 +388,22 @@ 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);
 
+  // makes me sad - we need to pass a few things along here so that
+  // NrIceCtx::InitializeGlobals can be called on the master process
+  InitLocalAddrs(mParent->GetAllowIceLoopback(),
+                 ice_tcp,
+                 mParent->GetAllowIceLinkLocal());
+
   // 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 +961,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 +1062,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,19 @@ class PeerConnectionMedia : public sigsl
                    const std::string&, uint16_t, uint16_t>
       SignalUpdateDefaultCandidate;
   sigslot::signal1<uint16_t>
       SignalEndOfLocalCandidates;
 
   RefPtr<WebRtcCallWrapper> mCall;
 
  private:
+  void InitLocalAddrs(bool allowLoopback,
+                      bool tcpEnabled,
+                      bool allowLinkLocal);
   nsresult InitProxy();
   class ProtocolProxyQueryHandler : public nsIProtocolProxyCallback {
    public:
     explicit ProtocolProxyQueryHandler(PeerConnectionMedia *pcm) :
       pcm_(pcm) {}
 
     NS_IMETHOD OnProxyAvailable(nsICancelable *request,
                                 nsIChannel *aChannel,
@@ -444,16 +448,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:
+    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 +532,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 +587,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