diff options
Diffstat (limited to '')
-rw-r--r-- | dom/media/webrtc/transport/nricectx.h | 421 |
1 files changed, 421 insertions, 0 deletions
diff --git a/dom/media/webrtc/transport/nricectx.h b/dom/media/webrtc/transport/nricectx.h new file mode 100644 index 0000000000..a0a0b5b772 --- /dev/null +++ b/dom/media/webrtc/transport/nricectx.h @@ -0,0 +1,421 @@ +/* -*- 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/. */ + +// Original author: ekr@rtfm.com + +// Some of this code is cut-and-pasted from nICEr. Copyright is: + +/* +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. +*/ + +/* 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/. */ + +// Original author: ekr@rtfm.com + +// This is a wrapper around the nICEr ICE stack +#ifndef nricectx_h__ +#define nricectx_h__ + +#include <memory> +#include <string> +#include <vector> +#include <map> + +#include "sigslot.h" + +#include "prnetdb.h" + +#include "mozilla/RefPtr.h" +#include "mozilla/UniquePtr.h" +#include "nsIEventTarget.h" +#include "nsTArray.h" +#include "mozilla/Maybe.h" + +#include "m_cpp_utils.h" +#include "nricestunaddr.h" +#include "nricemediastream.h" + +typedef struct nr_ice_ctx_ nr_ice_ctx; +typedef struct nr_ice_peer_ctx_ nr_ice_peer_ctx; +typedef struct nr_ice_media_stream_ nr_ice_media_stream; +typedef struct nr_ice_handler_ nr_ice_handler; +typedef struct nr_ice_handler_vtbl_ nr_ice_handler_vtbl; +typedef struct nr_ice_candidate_ nr_ice_candidate; +typedef struct nr_ice_cand_pair_ nr_ice_cand_pair; +typedef struct nr_ice_stun_server_ nr_ice_stun_server; +typedef struct nr_ice_turn_server_ nr_ice_turn_server; +typedef struct nr_resolver_ nr_resolver; +typedef struct nr_proxy_tunnel_config_ nr_proxy_tunnel_config; + +typedef void* NR_SOCKET; + +namespace mozilla { + +class NrSocketProxyConfig; + +class NrIceMediaStream; + +extern const char kNrIceTransportUdp[]; +extern const char kNrIceTransportTcp[]; +extern const char kNrIceTransportTls[]; + +class NrIceStunServer { + public: + explicit NrIceStunServer(const PRNetAddr& addr) : has_addr_(true) { + memcpy(&addr_, &addr, sizeof(addr)); + } + + // The main function to use. Will take either an address or a hostname. + static UniquePtr<NrIceStunServer> Create( + const std::string& addr, uint16_t port, + const char* transport = kNrIceTransportUdp) { + UniquePtr<NrIceStunServer> server(new NrIceStunServer(transport)); + + nsresult rv = server->Init(addr, port); + if (NS_FAILED(rv)) return nullptr; + + return server; + } + + nsresult ToNicerStunStruct(nr_ice_stun_server* server) const; + + bool HasFqdn() const { return !has_addr_; } + + void SetUseIPv6IfFqdn() { + MOZ_ASSERT(HasFqdn()); + use_ipv6_if_fqdn_ = true; + } + + protected: + explicit NrIceStunServer(const char* transport) + : addr_(), transport_(transport) {} + + nsresult Init(const std::string& addr, uint16_t port) { + PRStatus status = PR_StringToNetAddr(addr.c_str(), &addr_); + if (status == PR_SUCCESS) { + // Parseable as an address + addr_.inet.port = PR_htons(port); + port_ = port; + has_addr_ = true; + return NS_OK; + } else if (addr.size() < 256) { + // Apparently this is a hostname. + host_ = addr; + port_ = port; + has_addr_ = false; + return NS_OK; + } + + return NS_ERROR_FAILURE; + } + + bool has_addr_; + std::string host_; + uint16_t port_; + PRNetAddr addr_; + std::string transport_; + bool use_ipv6_if_fqdn_ = false; +}; + +class NrIceTurnServer : public NrIceStunServer { + public: + static UniquePtr<NrIceTurnServer> Create( + const std::string& addr, uint16_t port, const std::string& username, + const std::vector<unsigned char>& password, + const char* transport = kNrIceTransportUdp) { + UniquePtr<NrIceTurnServer> server( + new NrIceTurnServer(username, password, transport)); + + nsresult rv = server->Init(addr, port); + if (NS_FAILED(rv)) return nullptr; + + return server; + } + + nsresult ToNicerTurnStruct(nr_ice_turn_server* server) const; + + private: + NrIceTurnServer(const std::string& username, + const std::vector<unsigned char>& password, + const char* transport) + : NrIceStunServer(transport), username_(username), password_(password) {} + + std::string username_; + std::vector<unsigned char> password_; +}; + +class TestNat; + +class NrIceStats { + public: + uint16_t stun_retransmits = 0; + uint16_t turn_401s = 0; + uint16_t turn_403s = 0; + uint16_t turn_438s = 0; +}; + +class NrIceCtx { + public: + enum ConnectionState { + ICE_CTX_INIT, + ICE_CTX_CHECKING, + ICE_CTX_CONNECTED, + ICE_CTX_COMPLETED, + ICE_CTX_FAILED, + ICE_CTX_DISCONNECTED, + ICE_CTX_CLOSED + }; + + enum GatheringState { + ICE_CTX_GATHER_INIT, + ICE_CTX_GATHER_STARTED, + ICE_CTX_GATHER_COMPLETE + }; + + enum Controlling { ICE_CONTROLLING, ICE_CONTROLLED }; + + enum Policy { ICE_POLICY_RELAY, ICE_POLICY_NO_HOST, ICE_POLICY_ALL }; + + struct NatSimulatorConfig { + bool mBlockTcp = false; + bool mBlockUdp = false; + bool mBlockTls = false; + int mErrorCodeForDrop = 0; + nsCString mMappingType = "ENDPOINT_INDEPENDENT"_ns; + nsCString mFilteringType = "ENDPOINT_INDEPENDENT"_ns; + nsCString mRedirectAddress; + CopyableTArray<nsCString> mRedirectTargets; + }; + + struct Config { + NrIceCtx::Policy mPolicy = NrIceCtx::ICE_POLICY_ALL; + Maybe<NatSimulatorConfig> mNatSimulatorConfig; + }; + + static RefPtr<NrIceCtx> Create(const std::string& aName); + + nsresult SetIceConfig(const Config& aConfig); + + RefPtr<NrIceMediaStream> CreateStream(const std::string& id, + const std::string& name, + int components); + void DestroyStream(const std::string& id); + + struct GlobalConfig { + bool mAllowLinkLocal = false; + bool mAllowLoopback = false; + bool mTcpEnabled = true; + int mStunClientMaxTransmits = 7; + int mTrickleIceGracePeriod = 5000; + int mIceTcpSoSockCount = 3; + int mIceTcpListenBacklog = 10; + nsCString mForceNetInterface; + }; + + // initialize ICE globals, crypto, and logging + static void InitializeGlobals(const GlobalConfig& aConfig); + + void SetTargetForDefaultLocalAddressLookup(const std::string& target_ip, + uint16_t target_port); + + // static GetStunAddrs for use in parent process to support + // sandboxing restrictions + static nsTArray<NrIceStunAddr> GetStunAddrs(); + void SetStunAddrs(const nsTArray<NrIceStunAddr>& addrs); + + bool Initialize(); + + int SetNat(const RefPtr<TestNat>& aNat); + + // Deinitialize all ICE global state. Used only for testing. + static void internal_DeinitializeGlobal(); + + // Divide some timers to faster testing. Used only for testing. + void internal_SetTimerAccelarator(int divider); + + nr_ice_ctx* ctx() { return ctx_; } + nr_ice_peer_ctx* peer() { return peer_; } + + // Testing only. + void destroy_peer_ctx(); + + RefPtr<NrIceMediaStream> GetStream(const std::string& id) { + auto it = streams_.find(id); + if (it != streams_.end()) { + return it->second; + } + return nullptr; + } + + std::vector<RefPtr<NrIceMediaStream>> GetStreams() const { + std::vector<RefPtr<NrIceMediaStream>> result; + for (auto& idAndStream : streams_) { + result.push_back(idAndStream.second); + } + return result; + } + + bool HasStreamsToConnect() const; + + // The name of the ctx + const std::string& name() const { return name_; } + + // Current state + ConnectionState connection_state() const { return connection_state_; } + + // Current state + GatheringState gathering_state() const { return gathering_state_; } + + // Get the global attributes + std::vector<std::string> GetGlobalAttributes(); + + // Set the other side's global attributes + nsresult ParseGlobalAttributes(std::vector<std::string> attrs); + + // Set whether we are controlling or not. + nsresult SetControlling(Controlling controlling); + + Controlling GetControlling(); + + // Set the STUN servers. Must be called before StartGathering + // (if at all). + nsresult SetStunServers(const std::vector<NrIceStunServer>& stun_servers); + + // Set the TURN servers. Must be called before StartGathering + // (if at all). + nsresult SetTurnServers(const std::vector<NrIceTurnServer>& turn_servers); + + // Provide the resolution provider. Must be called before + // StartGathering. + nsresult SetResolver(nr_resolver* resolver); + + // Provide the proxy address. Must be called before + // StartGathering. + nsresult SetProxyConfig(NrSocketProxyConfig&& config); + + const std::shared_ptr<NrSocketProxyConfig>& GetProxyConfig() { + return proxy_config_; + } + + void SetCtxFlags(bool default_route_only); + + // Start ICE gathering + nsresult StartGathering(bool default_route_only, + bool obfuscate_host_addresses); + + // Start checking + nsresult StartChecks(); + + // Notify that the network has gone online/offline + void UpdateNetworkState(bool online); + + void AccumulateStats(const NrIceStats& stats); + NrIceStats Destroy(); + + // Are we trickling? + bool generating_trickle() const { return trickle_; } + + // Signals to indicate events. API users can (and should) + // register for these. + sigslot::signal2<NrIceCtx*, NrIceCtx::GatheringState> + SignalGatheringStateChange; + sigslot::signal2<NrIceCtx*, NrIceCtx::ConnectionState> + SignalConnectionStateChange; + + // The thread to direct method calls to + nsCOMPtr<nsIEventTarget> thread() { return sts_target_; } + + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(NrIceCtx) + + private: + explicit NrIceCtx(const std::string& name); + + virtual ~NrIceCtx(); + + DISALLOW_COPY_ASSIGN(NrIceCtx); + + // Callbacks for nICEr + static void gather_cb(NR_SOCKET s, int h, void* arg); // ICE gather complete + + // Handler implementation + static int select_pair(void* obj, nr_ice_media_stream* stream, + int component_id, nr_ice_cand_pair** potentials, + int potential_ct); + static int stream_ready(void* obj, nr_ice_media_stream* stream); + static int stream_failed(void* obj, nr_ice_media_stream* stream); + static int ice_checking(void* obj, nr_ice_peer_ctx* pctx); + static int ice_connected(void* obj, nr_ice_peer_ctx* pctx); + static int ice_disconnected(void* obj, nr_ice_peer_ctx* pctx); + static int msg_recvd(void* obj, nr_ice_peer_ctx* pctx, + nr_ice_media_stream* stream, int component_id, + unsigned char* msg, int len); + static void trickle_cb(void* arg, nr_ice_ctx* ctx, + nr_ice_media_stream* stream, int component_id, + nr_ice_candidate* candidate); + + // Find a media stream by stream ptr. Gross + RefPtr<NrIceMediaStream> FindStream(nr_ice_media_stream* stream); + + // Set the state + void SetConnectionState(ConnectionState state); + + // Set the state + void SetGatheringState(GatheringState state); + + void GenerateObfuscatedAddress(nr_ice_candidate* candidate, + std::string* mdns_address, + std::string* actual_address); + + ConnectionState connection_state_; + GatheringState gathering_state_; + const std::string name_; + bool ice_controlling_set_; + std::map<std::string, 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 + Config config_; + RefPtr<TestNat> nat_; + std::shared_ptr<NrSocketProxyConfig> proxy_config_; + std::map<std::string, std::string> obfuscated_host_addresses_; +}; + +} // namespace mozilla +#endif |