summaryrefslogtreecommitdiffstats
path: root/media/mtransport/test_nr_socket.h
diff options
context:
space:
mode:
Diffstat (limited to 'media/mtransport/test_nr_socket.h')
-rw-r--r--media/mtransport/test_nr_socket.h335
1 files changed, 335 insertions, 0 deletions
diff --git a/media/mtransport/test_nr_socket.h b/media/mtransport/test_nr_socket.h
new file mode 100644
index 000000000..a38e2e5ed
--- /dev/null
+++ b/media/mtransport/test_nr_socket.h
@@ -0,0 +1,335 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+*/
+
+/*
+Based partially on original code from nICEr and nrappkit.
+
+nICEr copyright:
+
+Copyright (c) 2007, Adobe Systems, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+* Neither the name of Adobe Systems, Network Resonance nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+nrappkit copyright:
+
+ Copyright (C) 2001-2003, Network Resonance, Inc.
+ Copyright (C) 2006, Network Resonance, Inc.
+ All Rights Reserved
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. Neither the name of Network Resonance, Inc. nor the name of any
+ contributors to this software may be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+
+ 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;
+
+/**
+ * A group of TestNrSockets that behave as if they were behind the same NAT.
+ * @note We deliberately avoid addref/release of TestNrSocket here to avoid
+ * masking lifetime errors elsewhere.
+*/
+class TestNat {
+ public:
+ typedef enum {
+ /** For mapping, one port is used for all destinations.
+ * For filtering, allow any external address/port. */
+ ENDPOINT_INDEPENDENT,
+
+ /** For mapping, one port for each destination address (for any port).
+ * For filtering, allow incoming traffic from addresses that outgoing
+ * traffic has been sent to. */
+ ADDRESS_DEPENDENT,
+
+ /** For mapping, one port for each destination address/port.
+ * For filtering, allow incoming traffic only from addresses/ports that
+ * outgoing traffic has been sent to. */
+ PORT_DEPENDENT,
+ } NatBehavior;
+
+ TestNat() :
+ enabled_(false),
+ filtering_type_(ENDPOINT_INDEPENDENT),
+ mapping_type_(ENDPOINT_INDEPENDENT),
+ mapping_timeout_(30000),
+ allow_hairpinning_(false),
+ refresh_on_ingress_(false),
+ block_udp_(false),
+ block_stun_(false),
+ delay_stun_resp_ms_(0),
+ sockets_() {}
+
+ bool has_port_mappings() const;
+
+ // Helps determine whether we're hairpinning
+ bool is_my_external_tuple(const nr_transport_addr &addr) const;
+ bool is_an_internal_tuple(const nr_transport_addr &addr) const;
+
+ int create_socket_factory(nr_socket_factory **factorypp);
+
+ void insert_socket(TestNrSocket *socket) {
+ sockets_.insert(socket);
+ }
+
+ 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_;
+ bool block_stun_;
+ /* Note: this can only delay a single response so far (bug 1253657) */
+ uint32_t delay_stun_resp_ms_;
+
+ private:
+ std::set<TestNrSocket*> sockets_;
+
+ ~TestNat(){}
+};
+
+/**
+ * Subclass of NrSocketBase that can simulate things like being behind a NAT,
+ * packet loss, latency, packet rewriting, etc. Also exposes some stuff that
+ * assists in diagnostics.
+ * This is accomplished by wrapping an "internal" socket (that handles traffic
+ * behind the NAT), and a collection of "external" sockets (that handle traffic
+ * into/out of the NAT)
+ */
+class TestNrSocket : public NrSocketBase {
+ public:
+ explicit TestNrSocket(TestNat *nat);
+
+ bool has_port_mappings() const;
+ bool is_my_external_tuple(const nr_transport_addr &addr) const;
+
+ // Overrides of NrSocketBase
+ int create(nr_transport_addr *addr) override;
+ int sendto(const void *msg, size_t len,
+ int flags, nr_transport_addr *to) override;
+ int recvfrom(void * buf, size_t maxlen,
+ size_t *len, int flags,
+ nr_transport_addr *from) override;
+ int getaddr(nr_transport_addr *addrp) override;
+ void close() override;
+ int connect(nr_transport_addr *addr) override;
+ int write(const void *msg, size_t len, size_t *written) override;
+ int read(void *buf, size_t maxlen, size_t *len) override;
+
+ int listen(int backlog) override;
+ int accept(nr_transport_addr *addrp, nr_socket **sockp) override;
+ int async_wait(int how, NR_async_cb cb, void *cb_arg,
+ char *function, int line) override;
+ int cancel(int how) override;
+
+ // Need override since this is virtual in NrSocketBase
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TestNrSocket, override)
+
+ private:
+ virtual ~TestNrSocket();
+
+ class UdpPacket {
+ public:
+ UdpPacket(const void *msg, size_t len, const nr_transport_addr &addr) :
+ buffer_(new DataBuffer(static_cast<const uint8_t*>(msg), len)) {
+ // TODO(bug 1170299): Remove const_cast when no longer necessary
+ nr_transport_addr_copy(&remote_address_,
+ const_cast<nr_transport_addr*>(&addr));
+ }
+
+ nr_transport_addr remote_address_;
+ UniquePtr<DataBuffer> buffer_;
+
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(UdpPacket);
+ private:
+ ~UdpPacket(){}
+ };
+
+ class PortMapping {
+ public:
+ PortMapping(const nr_transport_addr &remote_address,
+ const RefPtr<NrSocketBase> &external_socket);
+
+ int sendto(const void *msg, size_t len, const nr_transport_addr &to);
+ int async_wait(int how, NR_async_cb cb, void *cb_arg,
+ char *function, int line);
+ int cancel(int how);
+ int send_from_queue();
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PortMapping);
+
+ PRIntervalTime last_used_;
+ RefPtr<NrSocketBase> external_socket_;
+ // For non-symmetric, most of the data here doesn't matter
+ nr_transport_addr remote_address_;
+
+ private:
+ ~PortMapping() {
+ external_socket_->close();
+ }
+
+ // If external_socket_ returns E_WOULDBLOCK, we don't want to propagate
+ // that to the code using the TestNrSocket. We can also perhaps use this
+ // to help simulate things like latency.
+ std::list<RefPtr<UdpPacket>> send_queue_;
+ };
+
+ struct DeferredPacket {
+ DeferredPacket(TestNrSocket *sock,
+ const void *data, size_t len,
+ int flags,
+ nr_transport_addr *addr,
+ RefPtr<NrSocketBase> internal_socket) :
+ socket_(sock),
+ buffer_(reinterpret_cast<const uint8_t *>(data), len),
+ flags_(flags),
+ internal_socket_(internal_socket) {
+ nr_transport_addr_copy(&to_, addr);
+ }
+
+ TestNrSocket *socket_;
+ DataBuffer buffer_;
+ int flags_;
+ nr_transport_addr to_;
+ RefPtr<NrSocketBase> internal_socket_;
+ };
+
+ bool is_port_mapping_stale(const PortMapping &port_mapping) const;
+ bool allow_ingress(const nr_transport_addr &from,
+ PortMapping **port_mapping_used) const;
+ void destroy_stale_port_mappings();
+
+ static void socket_readable_callback(void *real_sock_v,
+ int how,
+ void *test_sock_v);
+ void on_socket_readable(NrSocketBase *external_or_internal_socket);
+ void fire_readable_callback();
+
+ static void port_mapping_tcp_passthrough_callback(void *ext_sock_v,
+ int how,
+ void *test_sock_v);
+ void cancel_port_mapping_async_wait(int how);
+
+ static void port_mapping_writeable_callback(void *ext_sock_v,
+ int how,
+ void *test_sock_v);
+ void write_to_port_mapping(NrSocketBase *external_socket);
+ bool is_tcp_connection_behind_nat() const;
+
+ PortMapping* get_port_mapping(const nr_transport_addr &remote_addr,
+ TestNat::NatBehavior filter) const;
+ PortMapping* create_port_mapping(
+ const nr_transport_addr &remote_addr,
+ const RefPtr<NrSocketBase> &external_socket) const;
+ RefPtr<NrSocketBase> create_external_socket(
+ const nr_transport_addr &remote_addr) const;
+
+ static void process_delayed_cb(NR_SOCKET s, int how, void *cb_arg);
+
+ RefPtr<NrSocketBase> readable_socket_;
+ // The socket for the "internal" address; used to talk to stuff behind the
+ // same nat.
+ RefPtr<NrSocketBase> internal_socket_;
+ RefPtr<TestNat> nat_;
+ // Since our comparison logic is different depending on what kind of NAT
+ // we simulate, and the STL does not make it very easy to switch out the
+ // comparison function at runtime, and these lists are going to be very
+ // small anyway, we just brute-force it.
+ std::list<RefPtr<PortMapping>> port_mappings_;
+
+ void *timer_handle_;
+};
+
+} // namespace mozilla
+
+#endif // test_nr_socket__
+