123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335 |
- /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
- /* 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__
|