michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set ts=2 et sw=2 tw=80: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: // Original author: ekr@rtfm.com michael@0: michael@0: // Some of this code is cut-and-pasted from nICEr. Copyright is: michael@0: michael@0: /* michael@0: Copyright (c) 2007, Adobe Systems, Incorporated michael@0: All rights reserved. michael@0: michael@0: Redistribution and use in source and binary forms, with or without michael@0: modification, are permitted provided that the following conditions are michael@0: met: michael@0: michael@0: * Redistributions of source code must retain the above copyright michael@0: notice, this list of conditions and the following disclaimer. michael@0: michael@0: * Redistributions in binary form must reproduce the above copyright michael@0: notice, this list of conditions and the following disclaimer in the michael@0: documentation and/or other materials provided with the distribution. michael@0: michael@0: * Neither the name of Adobe Systems, Network Resonance nor the names of its michael@0: contributors may be used to endorse or promote products derived from michael@0: this software without specific prior written permission. michael@0: michael@0: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS michael@0: "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT michael@0: LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR michael@0: A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT michael@0: OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, michael@0: SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT michael@0: LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, michael@0: DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY michael@0: THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT michael@0: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE michael@0: OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. michael@0: */ michael@0: michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: // Original author: ekr@rtfm.com michael@0: michael@0: // This is a wrapper around the nICEr ICE stack michael@0: #ifndef nricectx_h__ michael@0: #define nricectx_h__ michael@0: michael@0: #include michael@0: michael@0: #include "sigslot.h" michael@0: michael@0: #include "prnetdb.h" michael@0: michael@0: #include "mozilla/RefPtr.h" michael@0: #include "mozilla/Scoped.h" michael@0: #include "nsAutoPtr.h" michael@0: #include "nsIEventTarget.h" michael@0: #include "nsITimer.h" michael@0: michael@0: #include "m_cpp_utils.h" michael@0: michael@0: typedef struct nr_ice_ctx_ nr_ice_ctx; michael@0: typedef struct nr_ice_peer_ctx_ nr_ice_peer_ctx; michael@0: typedef struct nr_ice_media_stream_ nr_ice_media_stream; michael@0: typedef struct nr_ice_handler_ nr_ice_handler; michael@0: typedef struct nr_ice_handler_vtbl_ nr_ice_handler_vtbl; michael@0: typedef struct nr_ice_candidate_ nr_ice_candidate; michael@0: typedef struct nr_ice_cand_pair_ nr_ice_cand_pair; michael@0: typedef struct nr_ice_stun_server_ nr_ice_stun_server; michael@0: typedef struct nr_ice_turn_server_ nr_ice_turn_server; michael@0: typedef struct nr_resolver_ nr_resolver; michael@0: michael@0: typedef void* NR_SOCKET; michael@0: michael@0: namespace mozilla { michael@0: michael@0: class NrIceMediaStream; michael@0: michael@0: extern const char kNrIceTransportUdp[]; michael@0: extern const char kNrIceTransportTcp[]; michael@0: michael@0: class NrIceStunServer { michael@0: public: michael@0: NrIceStunServer(const PRNetAddr& addr) : has_addr_(true) { michael@0: memcpy(&addr_, &addr, sizeof(addr)); michael@0: } michael@0: michael@0: // The main function to use. Will take either an address or a hostname. michael@0: static NrIceStunServer* Create(const std::string& addr, uint16_t port) { michael@0: ScopedDeletePtr server( michael@0: new NrIceStunServer()); michael@0: michael@0: nsresult rv = server->Init(addr, port); michael@0: if (NS_FAILED(rv)) michael@0: return nullptr; michael@0: michael@0: return server.forget(); michael@0: } michael@0: michael@0: nsresult ToNicerStunStruct(nr_ice_stun_server* server, michael@0: const std::string& transport = michael@0: kNrIceTransportUdp) const; michael@0: michael@0: protected: michael@0: NrIceStunServer() : addr_() {} michael@0: michael@0: nsresult Init(const std::string& addr, uint16_t port) { michael@0: PRStatus status = PR_StringToNetAddr(addr.c_str(), &addr_); michael@0: if (status == PR_SUCCESS) { michael@0: // Parseable as an address michael@0: addr_.inet.port = PR_htons(port); michael@0: port_ = port; michael@0: has_addr_ = true; michael@0: return NS_OK; michael@0: } michael@0: else if (addr.size() < 256) { michael@0: // Apparently this is a hostname. michael@0: host_ = addr; michael@0: port_ = port; michael@0: has_addr_ = false; michael@0: return NS_OK; michael@0: } michael@0: michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: bool has_addr_; michael@0: std::string host_; michael@0: uint16_t port_; michael@0: PRNetAddr addr_; michael@0: }; michael@0: michael@0: class NrIceTurnServer : public NrIceStunServer { michael@0: public: michael@0: static NrIceTurnServer *Create(const std::string& addr, uint16_t port, michael@0: const std::string& username, michael@0: const std::vector& password, michael@0: const char *transport = kNrIceTransportUdp) { michael@0: ScopedDeletePtr server( michael@0: new NrIceTurnServer(username, password, transport)); michael@0: michael@0: nsresult rv = server->Init(addr, port); michael@0: if (NS_FAILED(rv)) michael@0: return nullptr; michael@0: michael@0: return server.forget(); michael@0: } michael@0: michael@0: nsresult ToNicerTurnStruct(nr_ice_turn_server *server) const; michael@0: michael@0: private: michael@0: NrIceTurnServer(const std::string& username, michael@0: const std::vector& password, michael@0: const char *transport) : michael@0: username_(username), password_(password), transport_(transport) {} michael@0: michael@0: std::string username_; michael@0: std::vector password_; michael@0: std::string transport_; michael@0: }; michael@0: michael@0: class NrIceCtx { michael@0: public: michael@0: enum ConnectionState { ICE_CTX_INIT, michael@0: ICE_CTX_CHECKING, michael@0: ICE_CTX_OPEN, michael@0: ICE_CTX_FAILED michael@0: }; michael@0: michael@0: enum GatheringState { ICE_CTX_GATHER_INIT, michael@0: ICE_CTX_GATHER_STARTED, michael@0: ICE_CTX_GATHER_COMPLETE michael@0: }; michael@0: michael@0: enum Controlling { ICE_CONTROLLING, michael@0: ICE_CONTROLLED michael@0: }; michael@0: michael@0: static RefPtr Create(const std::string& name, michael@0: bool offerer, michael@0: bool set_interface_priorities = true); michael@0: virtual ~NrIceCtx(); michael@0: michael@0: nr_ice_ctx *ctx() { return ctx_; } michael@0: nr_ice_peer_ctx *peer() { return peer_; } michael@0: michael@0: // Testing only. michael@0: void destroy_peer_ctx(); michael@0: michael@0: // Create a media stream michael@0: RefPtr CreateStream(const std::string& name, michael@0: int components); michael@0: michael@0: // The name of the ctx michael@0: const std::string& name() const { return name_; } michael@0: michael@0: // Current state michael@0: ConnectionState connection_state() const { michael@0: return connection_state_; michael@0: } michael@0: michael@0: // Current state michael@0: GatheringState gathering_state() const { michael@0: return gathering_state_; michael@0: } michael@0: michael@0: // Get the global attributes michael@0: std::vector GetGlobalAttributes(); michael@0: michael@0: // Set the other side's global attributes michael@0: nsresult ParseGlobalAttributes(std::vector attrs); michael@0: michael@0: // Set whether we are controlling or not. michael@0: nsresult SetControlling(Controlling controlling); michael@0: michael@0: // Set the STUN servers. Must be called before StartGathering michael@0: // (if at all). michael@0: nsresult SetStunServers(const std::vector& stun_servers); michael@0: michael@0: // Set the TURN servers. Must be called before StartGathering michael@0: // (if at all). michael@0: nsresult SetTurnServers(const std::vector& turn_servers); michael@0: michael@0: // Provide the resolution provider. Must be called before michael@0: // StartGathering. michael@0: nsresult SetResolver(nr_resolver *resolver); michael@0: michael@0: // Start ICE gathering michael@0: nsresult StartGathering(); michael@0: michael@0: // Start checking michael@0: nsresult StartChecks(); michael@0: michael@0: // Finalize the ICE negotiation. I.e., there will be no michael@0: // more forking. michael@0: nsresult Finalize(); michael@0: michael@0: // Are we trickling? michael@0: bool generating_trickle() const { return trickle_; } michael@0: michael@0: // Signals to indicate events. API users can (and should) michael@0: // register for these. michael@0: sigslot::signal2 michael@0: SignalGatheringStateChange; michael@0: sigslot::signal2 michael@0: SignalConnectionStateChange; michael@0: michael@0: // The thread to direct method calls to michael@0: nsCOMPtr thread() { return sts_target_; } michael@0: michael@0: NS_INLINE_DECL_THREADSAFE_REFCOUNTING(NrIceCtx) michael@0: michael@0: private: michael@0: NrIceCtx(const std::string& name, michael@0: bool offerer) michael@0: : connection_state_(ICE_CTX_INIT), michael@0: gathering_state_(ICE_CTX_GATHER_INIT), michael@0: name_(name), michael@0: offerer_(offerer), michael@0: streams_(), michael@0: ctx_(nullptr), michael@0: peer_(nullptr), michael@0: ice_handler_vtbl_(nullptr), michael@0: ice_handler_(nullptr), michael@0: trickle_(true) { michael@0: // XXX: offerer_ will be used eventually; placate clang in the meantime. michael@0: (void)offerer_; michael@0: } michael@0: michael@0: DISALLOW_COPY_ASSIGN(NrIceCtx); michael@0: michael@0: // Callbacks for nICEr michael@0: static void initialized_cb(NR_SOCKET s, int h, void *arg); // ICE initialized michael@0: michael@0: // Handler implementation michael@0: static int select_pair(void *obj,nr_ice_media_stream *stream, michael@0: int component_id, nr_ice_cand_pair **potentials, michael@0: int potential_ct); michael@0: static int stream_ready(void *obj, nr_ice_media_stream *stream); michael@0: static int stream_failed(void *obj, nr_ice_media_stream *stream); michael@0: static int ice_completed(void *obj, nr_ice_peer_ctx *pctx); michael@0: static int msg_recvd(void *obj, nr_ice_peer_ctx *pctx, michael@0: nr_ice_media_stream *stream, int component_id, michael@0: unsigned char *msg, int len); michael@0: static void trickle_cb(void *arg, nr_ice_ctx *ctx, nr_ice_media_stream *stream, michael@0: int component_id, nr_ice_candidate *candidate); michael@0: michael@0: // Find a media stream by stream ptr. Gross michael@0: RefPtr FindStream(nr_ice_media_stream *stream); michael@0: michael@0: // Set the state michael@0: void SetConnectionState(ConnectionState state); michael@0: michael@0: // Set the state michael@0: void SetGatheringState(GatheringState state); michael@0: michael@0: ConnectionState connection_state_; michael@0: GatheringState gathering_state_; michael@0: const std::string name_; michael@0: bool offerer_; michael@0: std::vector > streams_; michael@0: nr_ice_ctx *ctx_; michael@0: nr_ice_peer_ctx *peer_; michael@0: nr_ice_handler_vtbl* ice_handler_vtbl_; // Must be pointer michael@0: nr_ice_handler* ice_handler_; // Must be pointer michael@0: bool trickle_; michael@0: nsCOMPtr sts_target_; // The thread to run on michael@0: }; michael@0: michael@0: michael@0: } // close namespace michael@0: #endif