Bug 1231973: Allow NAT simulator to be enabled with the pref system. r?drno
--- 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;
}