Bug 1231973: Allow NAT simulator to be enabled with the pref system. r?drno draft
authorByron Campen [:bwc] <docfaraday@gmail.com>
Wed, 16 Dec 2015 14:26:02 -0600
changeset 327733 dc239786617d2dc51b5510c4135ebed7ca9b3b8d
parent 327605 d07dbd40dcd209124149f331f60dd55c8da33fbe
child 513733 2e827e53a26f94ccadfd4853b574f80f20d47e7e
push id10275
push userbcampen@mozilla.com
push dateMon, 01 Feb 2016 17:39:40 +0000
reviewersdrno
bugs1231973
milestone47.0a1
Bug 1231973: Allow NAT simulator to be enabled with the pref system. r?drno
media/mtransport/nr_socket_prsock.cpp
media/mtransport/nricectx.cpp
media/mtransport/nricectx.h
media/mtransport/test/ice_unittest.cpp
media/mtransport/test_nr_socket.cpp
media/mtransport/test_nr_socket.h
media/mtransport/third_party/nICEr/src/ice/ice_socket.c
--- a/media/mtransport/nr_socket_prsock.cpp
+++ b/media/mtransport/nr_socket_prsock.cpp
@@ -84,16 +84,17 @@ nrappkit copyright:
 */
 
 #include <csi_platform.h>
 #include <stdio.h>
 #include <string.h>
 #include <sys/types.h>
 #include <assert.h>
 #include <errno.h>
+#include <string>
 
 #include "nspr.h"
 #include "prerror.h"
 #include "prio.h"
 #include "prnetdb.h"
 
 #include "mozilla/net/DNS.h"
 #include "nsCOMPtr.h"
@@ -105,16 +106,18 @@ nrappkit copyright:
 #include "nsComponentManagerUtils.h"
 #include "nsXPCOM.h"
 #include "nsXULAppAPI.h"
 #include "runnable_utils.h"
 #include "mozilla/SyncRunnable.h"
 #include "nsTArray.h"
 #include "mozilla/dom/TCPSocketBinding.h"
 #include "nsITCPSocketCallback.h"
+#include "nsIPrefService.h"
+#include "nsIPrefBranch.h"
 
 #if defined(MOZILLA_INTERNAL_API) && !defined(MOZILLA_XPCOMRT_API)
 // csi_platform.h deep in nrappkit defines LOG_INFO and LOG_WARNING
 #ifdef LOG_INFO
 #define LOG_TEMP_INFO LOG_INFO
 #undef LOG_INFO
 #endif
 #ifdef LOG_WARNING
@@ -159,16 +162,17 @@ extern "C" {
 #include "nr_api.h"
 #include "async_wait.h"
 #include "nr_socket.h"
 #include "nr_socket_local.h"
 #include "stun_hint.h"
 }
 #include "nr_socket_prsock.h"
 #include "simpletokenbucket.h"
+#include "test_nr_socket.h"
 
 // Implement the nsISupports ref counting
 namespace mozilla {
 
 #if defined(MOZILLA_INTERNAL_API) && !defined(MOZILLA_XPCOMRT_API)
 class SingletonThreadHolder final
 {
 private:
--- a/media/mtransport/nricectx.cpp
+++ b/media/mtransport/nricectx.cpp
@@ -88,16 +88,17 @@ extern "C" {
 }
 
 // Local includes
 #include "nricectx.h"
 #include "nricemediastream.h"
 #include "nr_socket_prsock.h"
 #include "nrinterfaceprioritizer.h"
 #include "rlogringbuffer.h"
+#include "test_nr_socket.h"
 
 namespace mozilla {
 
 TimeStamp nr_socket_short_term_violation_time() {
   return NrSocketBase::short_term_violation_time();
 }
 
 TimeStamp nr_socket_long_term_violation_time() {
@@ -263,16 +264,35 @@ nsresult NrIceTurnServer::ToNicerTurnStr
   if (r) {
     RFREE(server->username);
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   return NS_OK;
 }
 
+NrIceCtx::NrIceCtx(const std::string& name,
+                   bool offerer,
+                   Policy policy)
+  : connection_state_(ICE_CTX_INIT),
+    gathering_state_(ICE_CTX_GATHER_INIT),
+    name_(name),
+    offerer_(offerer),
+    streams_(),
+    ctx_(nullptr),
+    peer_(nullptr),
+    ice_handler_vtbl_(nullptr),
+    ice_handler_(nullptr),
+    trickle_(true),
+    policy_(policy),
+    nat_ (nullptr) {
+  // XXX: offerer_ will be used eventually;  placate clang in the meantime.
+  (void)offerer_;
+}
+
 // Handler callbacks
 int NrIceCtx::select_pair(void *obj,nr_ice_media_stream *stream,
                    int component_id, nr_ice_cand_pair **potentials,
                    int potential_ct) {
   MOZ_MTLOG(ML_DEBUG, "select pair called: potential_ct = "
             << potential_ct);
 
   return 0;
@@ -493,16 +513,52 @@ RefPtr<NrIceCtx> NrIceCtx::Create(const 
   if (ctx->generating_trickle()) {
     r = nr_ice_ctx_set_trickle_cb(ctx->ctx_, &NrIceCtx::trickle_cb, ctx);
     if (r) {
       MOZ_MTLOG(ML_ERROR, "Couldn't set trickle cb for '" << name << "'");
       return nullptr;
     }
   }
 
+  char* mapping_type = nullptr;
+  char* filtering_type = nullptr;
+  bool block_udp = false;
+
+  nsresult rv;
+  nsCOMPtr<nsIPrefService> pref_service =
+    do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
+
+  if (NS_SUCCEEDED(rv)) {
+    nsCOMPtr<nsIPrefBranch> pref_branch;
+    rv = pref_service->GetBranch(nullptr, getter_AddRefs(pref_branch));
+    if (NS_SUCCEEDED(rv)) {
+      rv = pref_branch->GetCharPref(
+          "media.peerconnection.nat_simulator.mapping_type",
+          &mapping_type);
+      rv = pref_branch->GetCharPref(
+          "media.peerconnection.nat_simulator.filtering_type",
+          &filtering_type);
+      rv = pref_branch->GetBoolPref(
+          "media.peerconnection.nat_simulator.block_udp",
+          &block_udp);
+    }
+  }
+
+  MOZ_MTLOG(ML_DEBUG, "NAT filtering type: " << filtering_type);
+  MOZ_MTLOG(ML_DEBUG, "NAT mapping type: " << mapping_type);
+
+  if (mapping_type && filtering_type) {
+    TestNat* test_nat = new TestNat;
+    test_nat->filtering_type_ = TestNat::ToNatBehavior(filtering_type);
+    test_nat->mapping_type_ = TestNat::ToNatBehavior(mapping_type);
+    test_nat->block_udp_ = block_udp;
+    test_nat->enabled_ = true;
+    ctx->SetNat(test_nat);
+  }
+
   // Create the handler objects
   ctx->ice_handler_vtbl_ = new nr_ice_handler_vtbl();
   ctx->ice_handler_vtbl_->select_pair = &NrIceCtx::select_pair;
   ctx->ice_handler_vtbl_->stream_ready = &NrIceCtx::stream_ready;
   ctx->ice_handler_vtbl_->stream_failed = &NrIceCtx::stream_failed;
   ctx->ice_handler_vtbl_->ice_completed = &NrIceCtx::ice_completed;
   ctx->ice_handler_vtbl_->msg_recvd = &NrIceCtx::msg_recvd;
   ctx->ice_handler_vtbl_->ice_checking = &NrIceCtx::ice_checking;
@@ -517,25 +573,35 @@ RefPtr<NrIceCtx> NrIceCtx::Create(const 
   r = nr_ice_peer_ctx_create(ctx->ctx_, ctx->ice_handler_,
                              const_cast<char *>(peer_name.c_str()),
                              &ctx->peer_);
   if (r) {
     MOZ_MTLOG(ML_ERROR, "Couldn't create ICE peer ctx for '" << name << "'");
     return nullptr;
   }
 
-  nsresult rv;
   ctx->sts_target_ = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
 
   if (!NS_SUCCEEDED(rv))
     return nullptr;
 
   return ctx;
 }
 
+int NrIceCtx::SetNat(const RefPtr<TestNat>& aNat) {
+  nat_ = aNat;
+  nr_socket_factory *fac;
+  int r = nat_->create_socket_factory(&fac);
+  if (r) {
+    return r;
+  }
+  nr_ice_ctx_set_socket_factory(ctx_, fac);
+  return 0;
+}
+
 // ONLY USE THIS FOR TESTING. Will cause totally unpredictable and possibly very
 // bad effects if ICE is still live.
 void NrIceCtx::internal_DeinitializeGlobal() {
   NR_reg_del((char *)"stun");
   NR_reg_del((char *)"ice");
   RLogRingBuffer::DestroyInstance();
   nr_crypto_vtbl = nullptr;
   initialized = false;
--- a/media/mtransport/nricectx.h
+++ b/media/mtransport/nricectx.h
@@ -186,16 +186,17 @@ class NrIceProxyServer {
   const std::string& alpn() const { return alpn_; }
 
  private:
   std::string host_;
   uint16_t port_;
   std::string alpn_;
 };
 
+class TestNat;
 
 class NrIceCtx {
  public:
   enum ConnectionState { ICE_CTX_INIT,
                          ICE_CTX_CHECKING,
                          ICE_CTX_OPEN,
                          ICE_CTX_FAILED
   };
@@ -218,16 +219,18 @@ class NrIceCtx {
   static RefPtr<NrIceCtx> Create(const std::string& name,
                                  bool offerer,
                                  bool allow_loopback = false,
                                  bool tcp_enabled = true,
                                  bool allow_link_local = false,
                                  bool hide_non_default = false,
                                  Policy policy = ICE_POLICY_ALL);
 
+  int SetNat(const RefPtr<TestNat>& aNat);
+
   // Deinitialize all ICE global state. Used only for testing.
   static void internal_DeinitializeGlobal();
 
 
   nr_ice_ctx *ctx() { return ctx_; }
   nr_ice_peer_ctx *peer() { return peer_; }
 
   // Testing only.
@@ -327,31 +330,17 @@ class NrIceCtx {
   // The thread to direct method calls to
   nsCOMPtr<nsIEventTarget> thread() { return sts_target_; }
 
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(NrIceCtx)
 
  private:
   NrIceCtx(const std::string& name,
            bool offerer,
-           Policy policy)
-  : connection_state_(ICE_CTX_INIT),
-    gathering_state_(ICE_CTX_GATHER_INIT),
-    name_(name),
-    offerer_(offerer),
-    streams_(),
-    ctx_(nullptr),
-    peer_(nullptr),
-    ice_handler_vtbl_(nullptr),
-    ice_handler_(nullptr),
-    trickle_(true),
-    policy_(policy) {
-    // XXX: offerer_ will be used eventually;  placate clang in the meantime.
-    (void)offerer_;
-  }
+           Policy policy);
 
   virtual ~NrIceCtx();
 
   DISALLOW_COPY_ASSIGN(NrIceCtx);
 
   // Callbacks for nICEr
   static void gather_cb(NR_SOCKET s, int h, void *arg);  // ICE gather complete
 
@@ -385,13 +374,14 @@ class NrIceCtx {
   std::vector<RefPtr<NrIceMediaStream> > streams_;
   nr_ice_ctx *ctx_;
   nr_ice_peer_ctx *peer_;
   nr_ice_handler_vtbl* ice_handler_vtbl_;  // Must be pointer
   nr_ice_handler* ice_handler_;  // Must be pointer
   bool trickle_;
   nsCOMPtr<nsIEventTarget> sts_target_; // The thread to run on
   Policy policy_;
+  RefPtr<TestNat> nat_;
 };
 
 
 }  // close namespace
 #endif
--- a/media/mtransport/test/ice_unittest.cpp
+++ b/media/mtransport/test/ice_unittest.cpp
@@ -311,22 +311,19 @@ class IceTestPeer : public sigslot::has_
       nat_(new TestNat) {
     ice_ctx_->SignalGatheringStateChange.connect(
         this,
         &IceTestPeer::GatheringStateChange);
     ice_ctx_->SignalConnectionStateChange.connect(
         this,
         &IceTestPeer::ConnectionStateChange);
 
-    nr_socket_factory *fac;
-    int r = nat_->create_socket_factory(&fac);
+    int r = ice_ctx_->SetNat(nat_);
+    (void)r;
     MOZ_ASSERT(!r);
-    if (!r) {
-      nr_ice_ctx_set_socket_factory(ice_ctx_->ctx(), fac);
-    }
   }
 
   ~IceTestPeer() {
     test_utils->sts_target()->Dispatch(WrapRunnable(this,
                                                     &IceTestPeer::Shutdown),
         NS_DISPATCH_SYNC);
 
     // Give the ICE destruction callback time to fire before
--- a/media/mtransport/test_nr_socket.cpp
+++ b/media/mtransport/test_nr_socket.cpp
@@ -132,16 +132,31 @@ static int test_nat_socket_factory_destr
   return 0;
 }
 
 static nr_socket_factory_vtbl test_nat_socket_factory_vtbl = {
   test_nat_socket_create,
   test_nat_socket_factory_destroy
 };
 
+/* static */
+TestNat::NatBehavior
+TestNat::ToNatBehavior(const std::string& type) {
+  if (!type.compare("ENDPOINT_INDEPENDENT")) {
+    return TestNat::ENDPOINT_INDEPENDENT;
+  } else if (!type.compare("ADDRESS_DEPENDENT")) {
+    return TestNat::ADDRESS_DEPENDENT;
+  } else if (!type.compare("PORT_DEPENDENT")) {
+    return TestNat::PORT_DEPENDENT;
+  }
+
+  MOZ_ASSERT(false, "Invalid NAT behavior");
+  return TestNat::ENDPOINT_INDEPENDENT;
+}
+
 bool TestNat::has_port_mappings() const {
   for (TestNrSocket *sock : sockets_) {
     if (sock->has_port_mappings()) {
       return true;
     }
   }
   return false;
 }
@@ -507,16 +522,20 @@ int TestNrSocket::async_wait(int how, NR
     r = internal_socket_->async_wait(how,
                                      cb,
                                      cb_arg,
                                      function,
                                      line);
   }
 
   if (r) {
+    r_log(LOG_GENERIC, LOG_ERR, "TestNrSocket %s failed to async_wait for "
+                                "internal socket: %d\n",
+                                internal_socket_->my_addr().as_string,
+                                r);
     return r;
   }
 
   if (is_tcp_connection_behind_nat()) {
     // Bypass all port-mapping related logic
     return 0;
   }
 
@@ -536,16 +555,20 @@ int TestNrSocket::async_wait(int how, NR
     for (PortMapping *port_mapping : port_mappings_) {
       // Be ready to receive traffic on our port mappings
       r = port_mapping->async_wait(how,
                                    socket_readable_callback,
                                    this,
                                    function,
                                    line);
       if (r) {
+        r_log(LOG_GENERIC, LOG_ERR, "TestNrSocket %s failed to async_wait for "
+                                    "port mapping: %d\n",
+                                    internal_socket_->my_addr().as_string,
+                                    r);
         return r;
       }
     }
   }
 
   return 0;
 }
 
--- a/media/mtransport/test_nr_socket.h
+++ b/media/mtransport/test_nr_socket.h
@@ -78,26 +78,31 @@ nrappkit copyright:
    ekr@rtfm.com  Thu Dec 20 20:14:49 2001
 */
 
 // Original author: bcampen@mozilla.com [:bwc]
 
 #ifndef test_nr_socket__
 #define test_nr_socket__
 
+extern "C" {
+#include "transport_addr.h"
+}
+
 #include "nr_socket_prsock.h"
 
 extern "C" {
 #include "nr_socket.h"
 }
 
 #include <set>
 #include <vector>
 #include <map>
 #include <list>
+#include <string>
 
 #include "mozilla/UniquePtr.h"
 #include "prinrval.h"
 
 namespace mozilla {
 
 class TestNrSocket;
 
@@ -147,16 +152,18 @@ class TestNat {
     }
 
     void erase_socket(TestNrSocket *socket) {
       sockets_.erase(socket);
     }
 
     NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TestNat);
 
+    static NatBehavior ToNatBehavior(const std::string& type);
+
     bool enabled_;
     TestNat::NatBehavior filtering_type_;
     TestNat::NatBehavior mapping_type_;
     uint32_t mapping_timeout_;
     bool allow_hairpinning_;
     bool refresh_on_ingress_;
     bool block_udp_;
 
--- a/media/mtransport/third_party/nICEr/src/ice/ice_socket.c
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_socket.c
@@ -56,18 +56,20 @@ static void nr_ice_socket_readable_cb(NR
     int is_ind;
     int processed_indication=0;
 
     nr_socket *stun_srv_sock=sock->sock;
 
     r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): Socket ready to read",sock->ctx->label);
 
     /* Re-arm first! */
-    if (sock->type != NR_ICE_SOCKET_TYPE_STREAM_TCP)
+    if (sock->type != NR_ICE_SOCKET_TYPE_STREAM_TCP) {
+      r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): rearming",sock->ctx->label);
       NR_ASYNC_WAIT(s,how,nr_ice_socket_readable_cb,cb_arg);
+    }
 
     if(r=nr_socket_recvfrom(sock->sock,buf,sizeof(buf),&len_s,0,&addr)){
       if (r != R_WOULDBLOCK && (sock->type != NR_ICE_SOCKET_TYPE_DGRAM)) {
         /* Report this error upward. Bug 946423 */
         r_log(LOG_ICE,LOG_ERR,"ICE(%s): Error %d on reliable socket(%p). Abandoning.",sock->ctx->label, r, s);
       }
       return;
     }