nricectx.h (13256B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 5 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 // Original author: ekr@rtfm.com 8 9 // Some of this code is cut-and-pasted from nICEr. Copyright is: 10 11 /* 12 Copyright (c) 2007, Adobe Systems, Incorporated 13 All rights reserved. 14 15 Redistribution and use in source and binary forms, with or without 16 modification, are permitted provided that the following conditions are 17 met: 18 19 * Redistributions of source code must retain the above copyright 20 notice, this list of conditions and the following disclaimer. 21 22 * Redistributions in binary form must reproduce the above copyright 23 notice, this list of conditions and the following disclaimer in the 24 documentation and/or other materials provided with the distribution. 25 26 * Neither the name of Adobe Systems, Network Resonance nor the names of its 27 contributors may be used to endorse or promote products derived from 28 this software without specific prior written permission. 29 30 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 31 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 32 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 33 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 34 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 35 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 36 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 37 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 38 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 39 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 40 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 41 */ 42 43 /* This Source Code Form is subject to the terms of the Mozilla Public 44 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 45 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 46 47 // Original author: ekr@rtfm.com 48 49 // This is a wrapper around the nICEr ICE stack 50 #ifndef nricectx_h__ 51 #define nricectx_h__ 52 53 #include <map> 54 #include <memory> 55 #include <string> 56 #include <vector> 57 58 #include "m_cpp_utils.h" 59 #include "mozilla/Maybe.h" 60 #include "mozilla/RefPtr.h" 61 #include "mozilla/UniquePtr.h" 62 #include "nricemediastream.h" 63 #include "nricestunaddr.h" 64 #include "nsIEventTarget.h" 65 #include "nsTArray.h" 66 #include "prnetdb.h" 67 #include "sigslot.h" 68 69 typedef struct nr_ice_ctx_ nr_ice_ctx; 70 typedef struct nr_ice_peer_ctx_ nr_ice_peer_ctx; 71 typedef struct nr_ice_media_stream_ nr_ice_media_stream; 72 typedef struct nr_ice_handler_ nr_ice_handler; 73 typedef struct nr_ice_handler_vtbl_ nr_ice_handler_vtbl; 74 typedef struct nr_ice_gather_handler_ nr_ice_gather_handler; 75 typedef struct nr_ice_gather_handler_vtbl_ nr_ice_gather_handler_vtbl; 76 typedef struct nr_ice_candidate_ nr_ice_candidate; 77 typedef struct nr_ice_cand_pair_ nr_ice_cand_pair; 78 typedef struct nr_ice_stun_server_ nr_ice_stun_server; 79 typedef struct nr_ice_turn_server_ nr_ice_turn_server; 80 typedef struct nr_resolver_ nr_resolver; 81 typedef struct nr_proxy_tunnel_config_ nr_proxy_tunnel_config; 82 83 typedef void* NR_SOCKET; 84 85 namespace mozilla { 86 87 class NrSocketProxyConfig; 88 89 class NrIceMediaStream; 90 91 extern const char kNrIceTransportUdp[]; 92 extern const char kNrIceTransportTcp[]; 93 extern const char kNrIceTransportTls[]; 94 95 class NrIceStunServer { 96 public: 97 explicit NrIceStunServer(const PRNetAddr& addr) : has_addr_(true) { 98 memcpy(&addr_, &addr, sizeof(addr)); 99 } 100 101 // The main function to use. Will take either an address or a hostname. 102 static UniquePtr<NrIceStunServer> Create( 103 const std::string& addr, uint16_t port, 104 const char* transport = kNrIceTransportUdp) { 105 UniquePtr<NrIceStunServer> server(new NrIceStunServer(transport)); 106 107 nsresult rv = server->Init(addr, port); 108 if (NS_FAILED(rv)) return nullptr; 109 110 return server; 111 } 112 113 nsresult ToNicerStunStruct(nr_ice_stun_server* server) const; 114 115 bool HasFqdn() const { return !has_addr_; } 116 117 void SetUseIPv6IfFqdn() { 118 MOZ_ASSERT(HasFqdn()); 119 use_ipv6_if_fqdn_ = true; 120 } 121 122 protected: 123 explicit NrIceStunServer(const char* transport) 124 : addr_(), transport_(transport) {} 125 126 nsresult Init(const std::string& addr, uint16_t port) { 127 PRStatus status = PR_StringToNetAddr(addr.c_str(), &addr_); 128 if (status == PR_SUCCESS) { 129 // Parseable as an address 130 addr_.inet.port = PR_htons(port); 131 port_ = port; 132 has_addr_ = true; 133 return NS_OK; 134 } else if (addr.size() < 256) { 135 // Apparently this is a hostname. 136 host_ = addr; 137 port_ = port; 138 has_addr_ = false; 139 return NS_OK; 140 } 141 142 return NS_ERROR_FAILURE; 143 } 144 145 bool has_addr_; 146 std::string host_; 147 uint16_t port_; 148 PRNetAddr addr_; 149 std::string transport_; 150 bool use_ipv6_if_fqdn_ = false; 151 }; 152 153 class NrIceTurnServer : public NrIceStunServer { 154 public: 155 static UniquePtr<NrIceTurnServer> Create( 156 const std::string& addr, uint16_t port, const std::string& username, 157 const std::vector<unsigned char>& password, 158 const char* transport = kNrIceTransportUdp) { 159 UniquePtr<NrIceTurnServer> server( 160 new NrIceTurnServer(username, password, transport)); 161 162 nsresult rv = server->Init(addr, port); 163 if (NS_FAILED(rv)) return nullptr; 164 165 return server; 166 } 167 168 nsresult ToNicerTurnStruct(nr_ice_turn_server* server) const; 169 170 private: 171 NrIceTurnServer(const std::string& username, 172 const std::vector<unsigned char>& password, 173 const char* transport) 174 : NrIceStunServer(transport), username_(username), password_(password) {} 175 176 std::string username_; 177 std::vector<unsigned char> password_; 178 }; 179 180 class TestNat; 181 182 class NrIceStats { 183 public: 184 uint16_t stun_retransmits = 0; 185 uint16_t turn_401s = 0; 186 uint16_t turn_403s = 0; 187 uint16_t turn_438s = 0; 188 }; 189 190 class NrIceCtx { 191 public: 192 enum ConnectionState { 193 ICE_CTX_INIT, 194 ICE_CTX_CHECKING, 195 ICE_CTX_CONNECTED, 196 ICE_CTX_COMPLETED, 197 ICE_CTX_FAILED, 198 ICE_CTX_DISCONNECTED, 199 ICE_CTX_CLOSED 200 }; 201 202 enum Controlling { ICE_CONTROLLING, ICE_CONTROLLED }; 203 204 enum Policy { ICE_POLICY_RELAY, ICE_POLICY_NO_HOST, ICE_POLICY_ALL }; 205 206 struct NatSimulatorConfig { 207 bool mBlockTcp = false; 208 bool mBlockUdp = false; 209 bool mBlockTls = false; 210 int mErrorCodeForDrop = 0; 211 nsCString mMappingType = "ENDPOINT_INDEPENDENT"_ns; 212 nsCString mFilteringType = "ENDPOINT_INDEPENDENT"_ns; 213 nsCString mRedirectAddress; 214 CopyableTArray<nsCString> mRedirectTargets; 215 unsigned int mNetworkDelayMs = 0; 216 }; 217 218 struct Config { 219 NrIceCtx::Policy mPolicy = NrIceCtx::ICE_POLICY_ALL; 220 bool mAllowLinkLocal = false; 221 bool mAllowLoopback = false; 222 Maybe<NatSimulatorConfig> mNatSimulatorConfig; 223 }; 224 225 static RefPtr<NrIceCtx> Create(const std::string& aName); 226 227 nsresult SetIceConfig(const Config& aConfig); 228 229 RefPtr<NrIceMediaStream> CreateStream(const std::string& id, 230 const std::string& name, 231 int components); 232 void DestroyStream(const std::string& id); 233 234 struct GlobalConfig { 235 bool mTcpEnabled = true; 236 int mStunClientMaxTransmits = 7; 237 int mTrickleIceGracePeriod = 5000; 238 int mIceTcpSoSockCount = 3; 239 int mIceTcpListenBacklog = 10; 240 nsCString mForceNetInterface; 241 }; 242 243 // initialize ICE globals, crypto, and logging 244 static void InitializeGlobals(const GlobalConfig& aConfig); 245 246 void SetTargetForDefaultLocalAddressLookup(const std::string& target_ip, 247 uint16_t target_port); 248 249 // static GetStunAddrs for use in parent process to support 250 // sandboxing restrictions 251 static nsTArray<NrIceStunAddr> GetStunAddrs(); 252 void SetStunAddrs(const nsTArray<NrIceStunAddr>& addrs); 253 254 bool Initialize(); 255 256 int SetNat(const RefPtr<TestNat>& aNat); 257 258 // Deinitialize all ICE global state. Used only for testing. 259 static void internal_DeinitializeGlobal(); 260 261 // Divide some timers to faster testing. Used only for testing. 262 void internal_SetTimerAccelarator(int divider); 263 264 nr_ice_ctx* ctx() { return ctx_; } 265 nr_ice_peer_ctx* peer() { return peer_; } 266 267 // Testing only. 268 void destroy_peer_ctx(); 269 270 RefPtr<NrIceMediaStream> GetStream(const std::string& id) { 271 auto it = streams_.find(id); 272 if (it != streams_.end()) { 273 return it->second; 274 } 275 return nullptr; 276 } 277 278 std::vector<RefPtr<NrIceMediaStream>> GetStreams() const { 279 std::vector<RefPtr<NrIceMediaStream>> result; 280 for (auto& idAndStream : streams_) { 281 result.push_back(idAndStream.second); 282 } 283 return result; 284 } 285 286 bool HasStreamsToConnect() const; 287 288 // The name of the ctx 289 const std::string& name() const { return name_; } 290 291 // Get the global attributes 292 std::vector<std::string> GetGlobalAttributes(); 293 294 // Set the other side's global attributes 295 nsresult ParseGlobalAttributes(std::vector<std::string> attrs); 296 297 // Set whether we are controlling or not. 298 nsresult SetControlling(Controlling controlling); 299 300 Controlling GetControlling(); 301 302 // Set the STUN servers. Must be called before StartGathering 303 // (if at all). 304 nsresult SetStunServers(const std::vector<NrIceStunServer>& stun_servers); 305 306 // Set the TURN servers. Must be called before StartGathering 307 // (if at all). 308 nsresult SetTurnServers(const std::vector<NrIceTurnServer>& turn_servers); 309 310 // Provide the resolution provider. Must be called before 311 // StartGathering. 312 nsresult SetResolver(nr_resolver* resolver); 313 314 // Provide the proxy address. Must be called before 315 // StartGathering. 316 nsresult SetProxyConfig(NrSocketProxyConfig&& config); 317 318 const std::shared_ptr<NrSocketProxyConfig>& GetProxyConfig() { 319 return proxy_config_; 320 } 321 322 void SetCtxFlags(bool default_route_only); 323 324 // Start ICE gathering 325 nsresult StartGathering(bool default_route_only, 326 bool obfuscate_host_addresses); 327 328 // Start checking 329 nsresult StartChecks(); 330 331 // Notify that the network has gone online/offline 332 void UpdateNetworkState(bool online); 333 334 void AccumulateStats(const NrIceStats& stats); 335 NrIceStats Destroy(); 336 337 // Are we trickling? 338 bool generating_trickle() const { return trickle_; } 339 340 // Signals to indicate events. API users can (and should) 341 // register for these. 342 sigslot::signal2<NrIceMediaStream*, NrIceCtx::ConnectionState> 343 SignalConnectionStateChange; 344 345 // The thread to direct method calls to 346 nsCOMPtr<nsIEventTarget> thread() { return sts_target_; } 347 348 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(NrIceCtx) 349 350 private: 351 explicit NrIceCtx(const std::string& name); 352 353 virtual ~NrIceCtx(); 354 355 DISALLOW_COPY_ASSIGN(NrIceCtx); 356 357 // Callbacks for nICEr 358 static void gather_cb(NR_SOCKET s, int h, void* arg); // ICE gather complete 359 360 // Handler implementation 361 static int select_pair(void* obj, nr_ice_media_stream* stream, 362 int component_id, nr_ice_cand_pair** potentials, 363 int potential_ct); 364 static int stream_gathering(void* obj, nr_ice_media_stream* stream); 365 static int stream_gathered(void* obj, nr_ice_media_stream* stream); 366 static int stream_checking(void* obj, nr_ice_media_stream* stream); 367 static int stream_ready(void* obj, nr_ice_media_stream* stream); 368 static int stream_disconnected(void* obj, nr_ice_media_stream* stream); 369 static int stream_failed(void* obj, nr_ice_media_stream* stream); 370 static int ice_checking(void* obj, nr_ice_peer_ctx* pctx); 371 static int ice_connected(void* obj, nr_ice_peer_ctx* pctx); 372 static int ice_disconnected(void* obj, nr_ice_peer_ctx* pctx); 373 static int msg_recvd(void* obj, nr_ice_peer_ctx* pctx, 374 nr_ice_media_stream* stream, int component_id, 375 unsigned char* msg, int len); 376 static void trickle_cb(void* arg, nr_ice_ctx* ctx, 377 nr_ice_media_stream* stream, int component_id, 378 nr_ice_candidate* candidate); 379 380 void SignalAllStreamsFailed(); 381 382 // Find a media stream by stream ptr. Gross 383 RefPtr<NrIceMediaStream> FindStream(nr_ice_media_stream* stream); 384 385 void GenerateObfuscatedAddress(nr_ice_candidate* candidate, 386 std::string* mdns_address, 387 std::string* actual_address); 388 389 bool dumped_rlog_ = false; 390 const std::string name_; 391 bool ice_controlling_set_; 392 std::map<std::string, RefPtr<NrIceMediaStream>> streams_; 393 nr_ice_ctx* ctx_; 394 nr_ice_peer_ctx* peer_; 395 nr_ice_handler_vtbl* ice_handler_vtbl_; // Must be pointer 396 nr_ice_handler* ice_handler_; // Must be pointer 397 nr_ice_gather_handler_vtbl* ice_gather_handler_vtbl_; // Must be pointer 398 nr_ice_gather_handler* ice_gather_handler_; // Must be pointer 399 bool trickle_; 400 nsCOMPtr<nsIEventTarget> sts_target_; // The thread to run on 401 Config config_; 402 RefPtr<TestNat> nat_; 403 std::shared_ptr<NrSocketProxyConfig> proxy_config_; 404 std::map<std::string, std::string> obfuscated_host_addresses_; 405 }; 406 407 } // namespace mozilla 408 #endif