summaryrefslogtreecommitdiffstats
path: root/dom/media/webrtc/transport/test_nr_socket.h
diff options
context:
space:
mode:
Diffstat (limited to 'dom/media/webrtc/transport/test_nr_socket.h')
-rw-r--r--dom/media/webrtc/transport/test_nr_socket.h370
1 files changed, 370 insertions, 0 deletions
diff --git a/dom/media/webrtc/transport/test_nr_socket.h b/dom/media/webrtc/transport/test_nr_socket.h
new file mode 100644
index 0000000000..c6a796c063
--- /dev/null
+++ b/dom/media/webrtc/transport/test_nr_socket.h
@@ -0,0 +1,370 @@
+/* -*- 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 <map>
+#include <list>
+#include <string>
+
+#include "mozilla/UniquePtr.h"
+#include "prinrval.h"
+#include "mediapacket.h"
+
+namespace mozilla {
+
+class TestNrSocket;
+class NrSocketProxyConfig;
+
+/**
+ * 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:
+ /**
+ * This allows TestNat traffic to be passively inspected.
+ * If a non-zero (error) value is returned, the packet will be dropped,
+ * allowing for tests to extend how packet manipulation is done by
+ * TestNat with having to modify TestNat itself.
+ */
+ class NatDelegate {
+ public:
+ virtual int on_read(TestNat* nat, void* buf, size_t maxlen,
+ size_t* len) = 0;
+ virtual int on_sendto(TestNat* nat, const void* msg, size_t len, int flags,
+ const nr_transport_addr* to) = 0;
+ virtual int on_write(TestNat* nat, const void* msg, size_t len,
+ size_t* written) = 0;
+ };
+
+ 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),
+ block_tcp_(false),
+ block_tls_(false),
+ error_code_for_drop_(0),
+ delay_stun_resp_ms_(0),
+ nat_delegate_(nullptr),
+ 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);
+
+ void set_proxy_config(std::shared_ptr<NrSocketProxyConfig> aProxyConfig);
+
+ 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_;
+ bool block_tcp_;
+ bool block_tls_;
+ bool error_code_for_drop_;
+ /* Note: this can only delay a single response so far (bug 1253657) */
+ uint32_t delay_stun_resp_ms_;
+
+ // When we see an outgoing STUN request with a destination address or
+ // destination FQDN that matches a key in this map, we respond with a STUN/300
+ // with a list of ALTERNATE-SERVER fields based on the value in this map.
+ std::map<nsCString, CopyableTArray<nsCString>> stun_redirect_map_;
+
+ NatDelegate* nat_delegate_;
+ std::shared_ptr<NrSocketProxyConfig> proxy_config_;
+
+ private:
+ std::set<TestNrSocket*> sockets_;
+
+ ~TestNat() = default;
+};
+
+/**
+ * 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,
+ const 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(const 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 MediaPacket) {
+ buffer_->Copy(static_cast<const uint8_t*>(msg), len);
+ nr_transport_addr_copy(&remote_address_, &addr);
+ }
+
+ UdpPacket(UdpPacket&& aOrig) = default;
+
+ ~UdpPacket() = default;
+
+ nr_transport_addr remote_address_;
+ UniquePtr<MediaPacket> buffer_;
+ };
+
+ 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<UdpPacket> send_queue_;
+ };
+
+ struct DeferredPacket {
+ DeferredPacket(TestNrSocket* sock, const void* data, size_t len, int flags,
+ const nr_transport_addr* addr,
+ RefPtr<NrSocketBase> internal_socket)
+ : socket_(sock),
+ buffer_(),
+ flags_(flags),
+ internal_socket_(internal_socket) {
+ buffer_.Copy(reinterpret_cast<const uint8_t*>(data), len);
+ nr_transport_addr_copy(&to_, addr);
+ }
+
+ TestNrSocket* socket_;
+ MediaPacket 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& to, 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;
+ static bool port_mapping_matches(const PortMapping& port_mapping,
+ const nr_transport_addr& remote_addr,
+ TestNat::NatBehavior filter);
+ 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);
+
+ bool maybe_send_fake_response(const void* msg, size_t len,
+ const nr_transport_addr* to);
+ Maybe<nsTArray<nsCString>> maybe_get_redirect_targets(
+ const nr_transport_addr* to) const;
+
+ 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_;
+ bool tls_;
+ // 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_;
+
+ // Just used for fake stun responses right now. Not _necessarily_ just UDP
+ // stuff, UdpPacket just has what we need to make this work for UDP.
+ std::list<UdpPacket> read_buffer_;
+ std::unique_ptr<nr_transport_addr> connect_fake_stun_address_;
+};
+
+} // namespace mozilla
+
+#endif // test_nr_socket__