1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/media/mtransport/nricectx.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,740 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set ts=2 et sw=2 tw=80: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this file, 1.8 + * You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 + 1.11 +// Original author: ekr@rtfm.com 1.12 + 1.13 +// Some of this code is cut-and-pasted from nICEr. Copyright is: 1.14 + 1.15 +/* 1.16 +Copyright (c) 2007, Adobe Systems, Incorporated 1.17 +All rights reserved. 1.18 + 1.19 +Redistribution and use in source and binary forms, with or without 1.20 +modification, are permitted provided that the following conditions are 1.21 +met: 1.22 + 1.23 +* Redistributions of source code must retain the above copyright 1.24 + notice, this list of conditions and the following disclaimer. 1.25 + 1.26 +* Redistributions in binary form must reproduce the above copyright 1.27 + notice, this list of conditions and the following disclaimer in the 1.28 + documentation and/or other materials provided with the distribution. 1.29 + 1.30 +* Neither the name of Adobe Systems, Network Resonance nor the names of its 1.31 + contributors may be used to endorse or promote products derived from 1.32 + this software without specific prior written permission. 1.33 + 1.34 +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1.35 +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1.36 +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1.37 +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 1.38 +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 1.39 +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 1.40 +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1.41 +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 1.42 +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 1.43 +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 1.44 +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1.45 +*/ 1.46 + 1.47 +#include <string> 1.48 +#include <vector> 1.49 + 1.50 +#include "logging.h" 1.51 +#include "nspr.h" 1.52 +#include "nss.h" 1.53 +#include "pk11pub.h" 1.54 +#include "plbase64.h" 1.55 + 1.56 +#include "nsCOMPtr.h" 1.57 +#include "nsComponentManagerUtils.h" 1.58 +#include "nsError.h" 1.59 +#include "nsIEventTarget.h" 1.60 +#include "nsNetCID.h" 1.61 +#include "nsComponentManagerUtils.h" 1.62 +#include "nsServiceManagerUtils.h" 1.63 +#include "ScopedNSSTypes.h" 1.64 + 1.65 +// nICEr includes 1.66 +extern "C" { 1.67 +#include "nr_api.h" 1.68 +#include "registry.h" 1.69 +#include "async_timer.h" 1.70 +#include "r_crc32.h" 1.71 +#include "r_memory.h" 1.72 +#include "ice_reg.h" 1.73 +#include "ice_util.h" 1.74 +#include "transport_addr.h" 1.75 +#include "nr_crypto.h" 1.76 +#include "nr_socket.h" 1.77 +#include "nr_socket_local.h" 1.78 +#include "stun_client_ctx.h" 1.79 +#include "stun_server_ctx.h" 1.80 +#include "ice_codeword.h" 1.81 +#include "ice_ctx.h" 1.82 +#include "ice_candidate.h" 1.83 +#include "ice_handler.h" 1.84 +} 1.85 + 1.86 +// Local includes 1.87 +#include "nricectx.h" 1.88 +#include "nricemediastream.h" 1.89 +#include "nr_socket_prsock.h" 1.90 +#include "nrinterfaceprioritizer.h" 1.91 +#include "rlogringbuffer.h" 1.92 + 1.93 +namespace mozilla { 1.94 + 1.95 +MOZ_MTLOG_MODULE("mtransport") 1.96 + 1.97 +const char kNrIceTransportUdp[] = "udp"; 1.98 +const char kNrIceTransportTcp[] = "tcp"; 1.99 + 1.100 +static bool initialized = false; 1.101 + 1.102 +// Implement NSPR-based crypto algorithms 1.103 +static int nr_crypto_nss_random_bytes(UCHAR *buf, int len) { 1.104 + ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); 1.105 + if (!slot) 1.106 + return R_INTERNAL; 1.107 + 1.108 + SECStatus rv = PK11_GenerateRandomOnSlot(slot, buf, len); 1.109 + if (rv != SECSuccess) 1.110 + return R_INTERNAL; 1.111 + 1.112 + return 0; 1.113 +} 1.114 + 1.115 +static int nr_crypto_nss_hmac(UCHAR *key, int keyl, UCHAR *buf, int bufl, 1.116 + UCHAR *result) { 1.117 + CK_MECHANISM_TYPE mech = CKM_SHA_1_HMAC; 1.118 + PK11SlotInfo *slot = 0; 1.119 + MOZ_ASSERT(keyl > 0); 1.120 + SECItem keyi = { siBuffer, key, static_cast<unsigned int>(keyl)}; 1.121 + PK11SymKey *skey = 0; 1.122 + PK11Context *hmac_ctx = 0; 1.123 + SECStatus status; 1.124 + unsigned int hmac_len; 1.125 + SECItem param = { siBuffer, nullptr, 0 }; 1.126 + int err = R_INTERNAL; 1.127 + 1.128 + slot = PK11_GetInternalKeySlot(); 1.129 + if (!slot) 1.130 + goto abort; 1.131 + 1.132 + skey = PK11_ImportSymKey(slot, mech, PK11_OriginUnwrap, 1.133 + CKA_SIGN, &keyi, nullptr); 1.134 + if (!skey) 1.135 + goto abort; 1.136 + 1.137 + 1.138 + hmac_ctx = PK11_CreateContextBySymKey(mech, CKA_SIGN, 1.139 + skey, ¶m); 1.140 + if (!hmac_ctx) 1.141 + goto abort; 1.142 + 1.143 + status = PK11_DigestBegin(hmac_ctx); 1.144 + if (status != SECSuccess) 1.145 + goto abort; 1.146 + 1.147 + status = PK11_DigestOp(hmac_ctx, buf, bufl); 1.148 + if (status != SECSuccess) 1.149 + goto abort; 1.150 + 1.151 + status = PK11_DigestFinal(hmac_ctx, result, &hmac_len, 20); 1.152 + if (status != SECSuccess) 1.153 + goto abort; 1.154 + 1.155 + MOZ_ASSERT(hmac_len == 20); 1.156 + 1.157 + err = 0; 1.158 + 1.159 + abort: 1.160 + if(hmac_ctx) PK11_DestroyContext(hmac_ctx, PR_TRUE); 1.161 + if (skey) PK11_FreeSymKey(skey); 1.162 + if (slot) PK11_FreeSlot(slot); 1.163 + 1.164 + return err; 1.165 +} 1.166 + 1.167 +static int nr_crypto_nss_md5(UCHAR *buf, int bufl, UCHAR *result) { 1.168 + int err = R_INTERNAL; 1.169 + SECStatus rv; 1.170 + 1.171 + const SECHashObject *ho = HASH_GetHashObject(HASH_AlgMD5); 1.172 + MOZ_ASSERT(ho); 1.173 + if (!ho) 1.174 + goto abort; 1.175 + 1.176 + MOZ_ASSERT(ho->length == 16); 1.177 + 1.178 + rv = HASH_HashBuf(ho->type, result, buf, bufl); 1.179 + if (rv != SECSuccess) 1.180 + goto abort; 1.181 + 1.182 + err = 0; 1.183 +abort: 1.184 + return err; 1.185 +} 1.186 + 1.187 +static nr_ice_crypto_vtbl nr_ice_crypto_nss_vtbl = { 1.188 + nr_crypto_nss_random_bytes, 1.189 + nr_crypto_nss_hmac, 1.190 + nr_crypto_nss_md5 1.191 +}; 1.192 + 1.193 + 1.194 + 1.195 + 1.196 +nsresult NrIceStunServer::ToNicerStunStruct(nr_ice_stun_server *server, 1.197 + const std::string &transport) const { 1.198 + int r; 1.199 + int transport_int; 1.200 + 1.201 + memset(server, 0, sizeof(nr_ice_stun_server)); 1.202 + if (transport == kNrIceTransportUdp) { 1.203 + transport_int = IPPROTO_UDP; 1.204 + } else if (transport == kNrIceTransportTcp) { 1.205 + transport_int = IPPROTO_TCP; 1.206 + } else { 1.207 + MOZ_ASSERT(false); 1.208 + return NS_ERROR_FAILURE; 1.209 + } 1.210 + 1.211 + if (has_addr_) { 1.212 + r = nr_praddr_to_transport_addr(&addr_, &server->u.addr, 1.213 + transport_int, 0); 1.214 + if (r) { 1.215 + return NS_ERROR_FAILURE; 1.216 + } 1.217 + server->type=NR_ICE_STUN_SERVER_TYPE_ADDR; 1.218 + } 1.219 + else { 1.220 + MOZ_ASSERT(sizeof(server->u.dnsname.host) > host_.size()); 1.221 + PL_strncpyz(server->u.dnsname.host, host_.c_str(), 1.222 + sizeof(server->u.dnsname.host)); 1.223 + server->u.dnsname.port = port_; 1.224 + server->type=NR_ICE_STUN_SERVER_TYPE_DNSNAME; 1.225 + } 1.226 + 1.227 + return NS_OK; 1.228 +} 1.229 + 1.230 + 1.231 +nsresult NrIceTurnServer::ToNicerTurnStruct(nr_ice_turn_server *server) const { 1.232 + memset(server, 0, sizeof(nr_ice_turn_server)); 1.233 + 1.234 + nsresult rv = ToNicerStunStruct(&server->turn_server, transport_); 1.235 + if (NS_FAILED(rv)) 1.236 + return rv; 1.237 + 1.238 + if (transport_ == kNrIceTransportUdp) { 1.239 + server->transport = IPPROTO_UDP; 1.240 + } else if (transport_ == kNrIceTransportTcp) { 1.241 + server->transport = IPPROTO_TCP; 1.242 + } else { 1.243 + MOZ_ASSERT(false); 1.244 + return NS_ERROR_FAILURE; 1.245 + } 1.246 + 1.247 + if (username_.empty()) 1.248 + return NS_ERROR_INVALID_ARG; 1.249 + if (password_.empty()) 1.250 + return NS_ERROR_INVALID_ARG; 1.251 + 1.252 + if (!(server->username=r_strdup(username_.c_str()))) 1.253 + return NS_ERROR_OUT_OF_MEMORY; 1.254 + 1.255 + // TODO(ekr@rtfm.com): handle non-ASCII passwords somehow? 1.256 + // STUN requires they be SASLpreped, but we don't know if 1.257 + // they are at this point. 1.258 + 1.259 + // C++03 23.2.4, Paragraph 1 stipulates that the elements 1.260 + // in std::vector must be contiguous, and can therefore be 1.261 + // used as input to functions expecting C arrays. 1.262 + int r = r_data_create(&server->password, 1.263 + const_cast<UCHAR *>(&password_[0]), 1.264 + password_.size()); 1.265 + if (r) { 1.266 + RFREE(server->username); 1.267 + return NS_ERROR_OUT_OF_MEMORY; 1.268 + } 1.269 + 1.270 + return NS_OK; 1.271 +} 1.272 + 1.273 +// Handler callbacks 1.274 +int NrIceCtx::select_pair(void *obj,nr_ice_media_stream *stream, 1.275 + int component_id, nr_ice_cand_pair **potentials, 1.276 + int potential_ct) { 1.277 + MOZ_MTLOG(ML_DEBUG, "select pair called: potential_ct = " 1.278 + << potential_ct); 1.279 + 1.280 + return 0; 1.281 +} 1.282 + 1.283 +int NrIceCtx::stream_ready(void *obj, nr_ice_media_stream *stream) { 1.284 + MOZ_MTLOG(ML_DEBUG, "stream_ready called"); 1.285 + 1.286 + // Get the ICE ctx. 1.287 + NrIceCtx *ctx = static_cast<NrIceCtx *>(obj); 1.288 + 1.289 + RefPtr<NrIceMediaStream> s = ctx->FindStream(stream); 1.290 + 1.291 + // Streams which do not exist should never be ready. 1.292 + MOZ_ASSERT(s); 1.293 + 1.294 + s->Ready(); 1.295 + 1.296 + return 0; 1.297 +} 1.298 + 1.299 +int NrIceCtx::stream_failed(void *obj, nr_ice_media_stream *stream) { 1.300 + MOZ_MTLOG(ML_DEBUG, "stream_failed called"); 1.301 + 1.302 + // Get the ICE ctx 1.303 + NrIceCtx *ctx = static_cast<NrIceCtx *>(obj); 1.304 + RefPtr<NrIceMediaStream> s = ctx->FindStream(stream); 1.305 + 1.306 + // Streams which do not exist should never fail. 1.307 + MOZ_ASSERT(s); 1.308 + 1.309 + ctx->SetConnectionState(ICE_CTX_FAILED); 1.310 + s -> SignalFailed(s); 1.311 + return 0; 1.312 +} 1.313 + 1.314 +int NrIceCtx::ice_completed(void *obj, nr_ice_peer_ctx *pctx) { 1.315 + MOZ_MTLOG(ML_DEBUG, "ice_completed called"); 1.316 + 1.317 + // Get the ICE ctx 1.318 + NrIceCtx *ctx = static_cast<NrIceCtx *>(obj); 1.319 + 1.320 + // This is called even on failed contexts. 1.321 + if (ctx->connection_state() != ICE_CTX_FAILED) { 1.322 + ctx->SetConnectionState(ICE_CTX_OPEN); 1.323 + } 1.324 + 1.325 + return 0; 1.326 +} 1.327 + 1.328 +int NrIceCtx::msg_recvd(void *obj, nr_ice_peer_ctx *pctx, 1.329 + nr_ice_media_stream *stream, int component_id, 1.330 + UCHAR *msg, int len) { 1.331 + // Get the ICE ctx 1.332 + NrIceCtx *ctx = static_cast<NrIceCtx *>(obj); 1.333 + RefPtr<NrIceMediaStream> s = ctx->FindStream(stream); 1.334 + 1.335 + // Streams which do not exist should never have packets. 1.336 + MOZ_ASSERT(s); 1.337 + 1.338 + s->SignalPacketReceived(s, component_id, msg, len); 1.339 + 1.340 + return 0; 1.341 +} 1.342 + 1.343 +void NrIceCtx::trickle_cb(void *arg, nr_ice_ctx *ice_ctx, 1.344 + nr_ice_media_stream *stream, 1.345 + int component_id, 1.346 + nr_ice_candidate *candidate) { 1.347 + // Get the ICE ctx 1.348 + NrIceCtx *ctx = static_cast<NrIceCtx *>(arg); 1.349 + RefPtr<NrIceMediaStream> s = ctx->FindStream(stream); 1.350 + 1.351 + // Streams which do not exist shouldn't have candidates. 1.352 + MOZ_ASSERT(s); 1.353 + 1.354 + // Format the candidate. 1.355 + char candidate_str[NR_ICE_MAX_ATTRIBUTE_SIZE]; 1.356 + int r = nr_ice_format_candidate_attribute(candidate, candidate_str, 1.357 + sizeof(candidate_str)); 1.358 + MOZ_ASSERT(!r); 1.359 + if (r) 1.360 + return; 1.361 + 1.362 + MOZ_MTLOG(ML_INFO, "NrIceCtx(" << ctx->name_ << "): trickling candidate " 1.363 + << candidate_str); 1.364 + 1.365 + s->SignalCandidate(s, candidate_str); 1.366 +} 1.367 + 1.368 +RefPtr<NrIceCtx> NrIceCtx::Create(const std::string& name, 1.369 + bool offerer, 1.370 + bool set_interface_priorities) { 1.371 + 1.372 + RefPtr<NrIceCtx> ctx = new NrIceCtx(name, offerer); 1.373 + 1.374 + // Initialize the crypto callbacks and logging stuff 1.375 + if (!initialized) { 1.376 + NR_reg_init(NR_REG_MODE_LOCAL); 1.377 + RLogRingBuffer::CreateInstance(); 1.378 + nr_crypto_vtbl = &nr_ice_crypto_nss_vtbl; 1.379 + initialized = true; 1.380 + 1.381 + // Set the priorites for candidate type preferences. 1.382 + // These numbers come from RFC 5245 S. 4.1.2.2 1.383 + NR_reg_set_uchar((char *)NR_ICE_REG_PREF_TYPE_SRV_RFLX, 100); 1.384 + NR_reg_set_uchar((char *)NR_ICE_REG_PREF_TYPE_PEER_RFLX, 110); 1.385 + NR_reg_set_uchar((char *)NR_ICE_REG_PREF_TYPE_HOST, 126); 1.386 + NR_reg_set_uchar((char *)NR_ICE_REG_PREF_TYPE_RELAYED, 5); 1.387 + NR_reg_set_uchar((char *)NR_ICE_REG_PREF_TYPE_RELAYED_TCP, 0); 1.388 + 1.389 + if (set_interface_priorities) { 1.390 + NR_reg_set_uchar((char *)"ice.pref.interface.rl0", 255); 1.391 + NR_reg_set_uchar((char *)"ice.pref.interface.wi0", 254); 1.392 + NR_reg_set_uchar((char *)"ice.pref.interface.lo0", 253); 1.393 + NR_reg_set_uchar((char *)"ice.pref.interface.en1", 252); 1.394 + NR_reg_set_uchar((char *)"ice.pref.interface.en0", 251); 1.395 + NR_reg_set_uchar((char *)"ice.pref.interface.eth0", 252); 1.396 + NR_reg_set_uchar((char *)"ice.pref.interface.eth1", 251); 1.397 + NR_reg_set_uchar((char *)"ice.pref.interface.eth2", 249); 1.398 + NR_reg_set_uchar((char *)"ice.pref.interface.ppp", 250); 1.399 + NR_reg_set_uchar((char *)"ice.pref.interface.ppp0", 249); 1.400 + NR_reg_set_uchar((char *)"ice.pref.interface.en2", 248); 1.401 + NR_reg_set_uchar((char *)"ice.pref.interface.en3", 247); 1.402 + NR_reg_set_uchar((char *)"ice.pref.interface.em0", 251); 1.403 + NR_reg_set_uchar((char *)"ice.pref.interface.em1", 252); 1.404 + NR_reg_set_uchar((char *)"ice.pref.interface.vmnet0", 240); 1.405 + NR_reg_set_uchar((char *)"ice.pref.interface.vmnet1", 241); 1.406 + NR_reg_set_uchar((char *)"ice.pref.interface.vmnet3", 239); 1.407 + NR_reg_set_uchar((char *)"ice.pref.interface.vmnet4", 238); 1.408 + NR_reg_set_uchar((char *)"ice.pref.interface.vmnet5", 237); 1.409 + NR_reg_set_uchar((char *)"ice.pref.interface.vmnet6", 236); 1.410 + NR_reg_set_uchar((char *)"ice.pref.interface.vmnet7", 235); 1.411 + NR_reg_set_uchar((char *)"ice.pref.interface.vmnet8", 234); 1.412 + NR_reg_set_uchar((char *)"ice.pref.interface.virbr0", 233); 1.413 + NR_reg_set_uchar((char *)"ice.pref.interface.wlan0", 232); 1.414 + } 1.415 + 1.416 + NR_reg_set_uint4((char *)"stun.client.maximum_transmits",5); 1.417 + } 1.418 + 1.419 + // Create the ICE context 1.420 + int r; 1.421 + 1.422 + UINT4 flags = offerer ? NR_ICE_CTX_FLAGS_OFFERER: 1.423 + NR_ICE_CTX_FLAGS_ANSWERER; 1.424 + flags |= NR_ICE_CTX_FLAGS_AGGRESSIVE_NOMINATION; 1.425 + 1.426 + r = nr_ice_ctx_create(const_cast<char *>(name.c_str()), flags, 1.427 + &ctx->ctx_); 1.428 + if (r) { 1.429 + MOZ_MTLOG(ML_ERROR, "Couldn't create ICE ctx for '" << name << "'"); 1.430 + return nullptr; 1.431 + } 1.432 + 1.433 +#ifdef USE_INTERFACE_PRIORITIZER 1.434 + nr_interface_prioritizer *prioritizer = CreateInterfacePrioritizer(); 1.435 + if (!prioritizer) { 1.436 + MOZ_MTLOG(PR_LOG_ERROR, "Couldn't create interface prioritizer."); 1.437 + return nullptr; 1.438 + } 1.439 + 1.440 + r = nr_ice_ctx_set_interface_prioritizer(ctx->ctx_, prioritizer); 1.441 + if (r) { 1.442 + MOZ_MTLOG(PR_LOG_ERROR, "Couldn't set interface prioritizer."); 1.443 + return nullptr; 1.444 + } 1.445 +#endif // USE_INTERFACE_PRIORITIZER 1.446 + 1.447 + if (ctx->generating_trickle()) { 1.448 + r = nr_ice_ctx_set_trickle_cb(ctx->ctx_, &NrIceCtx::trickle_cb, ctx); 1.449 + if (r) { 1.450 + MOZ_MTLOG(ML_ERROR, "Couldn't set trickle cb for '" << name << "'"); 1.451 + return nullptr; 1.452 + } 1.453 + } 1.454 + 1.455 + // Create the handler objects 1.456 + ctx->ice_handler_vtbl_ = new nr_ice_handler_vtbl(); 1.457 + ctx->ice_handler_vtbl_->select_pair = &NrIceCtx::select_pair; 1.458 + ctx->ice_handler_vtbl_->stream_ready = &NrIceCtx::stream_ready; 1.459 + ctx->ice_handler_vtbl_->stream_failed = &NrIceCtx::stream_failed; 1.460 + ctx->ice_handler_vtbl_->ice_completed = &NrIceCtx::ice_completed; 1.461 + ctx->ice_handler_vtbl_->msg_recvd = &NrIceCtx::msg_recvd; 1.462 + 1.463 + ctx->ice_handler_ = new nr_ice_handler(); 1.464 + ctx->ice_handler_->vtbl = ctx->ice_handler_vtbl_; 1.465 + ctx->ice_handler_->obj = ctx; 1.466 + 1.467 + // Create the peer ctx. Because we do not support parallel forking, we 1.468 + // only have one peer ctx. 1.469 + std::string peer_name = name + ":default"; 1.470 + r = nr_ice_peer_ctx_create(ctx->ctx_, ctx->ice_handler_, 1.471 + const_cast<char *>(peer_name.c_str()), 1.472 + &ctx->peer_); 1.473 + if (r) { 1.474 + MOZ_MTLOG(ML_ERROR, "Couldn't create ICE peer ctx for '" << name << "'"); 1.475 + return nullptr; 1.476 + } 1.477 + 1.478 + nsresult rv; 1.479 + ctx->sts_target_ = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv); 1.480 + 1.481 + if (!NS_SUCCEEDED(rv)) 1.482 + return nullptr; 1.483 + 1.484 + return ctx; 1.485 +} 1.486 + 1.487 + 1.488 +NrIceCtx::~NrIceCtx() { 1.489 + MOZ_MTLOG(ML_DEBUG, "Destroying ICE ctx '" << name_ <<"'"); 1.490 + nr_ice_peer_ctx_destroy(&peer_); 1.491 + nr_ice_ctx_destroy(&ctx_); 1.492 + delete ice_handler_vtbl_; 1.493 + delete ice_handler_; 1.494 +} 1.495 + 1.496 +RefPtr<NrIceMediaStream> 1.497 +NrIceCtx::CreateStream(const std::string& name, int components) { 1.498 + RefPtr<NrIceMediaStream> stream = 1.499 + NrIceMediaStream::Create(this, name, components); 1.500 + 1.501 + streams_.push_back(stream); 1.502 + 1.503 + return stream; 1.504 +} 1.505 + 1.506 +void NrIceCtx::destroy_peer_ctx() { 1.507 + nr_ice_peer_ctx_destroy(&peer_); 1.508 +} 1.509 + 1.510 +nsresult NrIceCtx::SetControlling(Controlling controlling) { 1.511 + peer_->controlling = (controlling == ICE_CONTROLLING)? 1 : 0; 1.512 + 1.513 + MOZ_MTLOG(ML_DEBUG, "ICE ctx " << name_ << " setting controlling to" << 1.514 + controlling); 1.515 + return NS_OK; 1.516 +} 1.517 + 1.518 +nsresult NrIceCtx::SetStunServers(const std::vector<NrIceStunServer>& 1.519 + stun_servers) { 1.520 + if (stun_servers.empty()) 1.521 + return NS_OK; 1.522 + 1.523 + ScopedDeleteArray<nr_ice_stun_server> servers( 1.524 + new nr_ice_stun_server[stun_servers.size()]); 1.525 + 1.526 + for (size_t i=0; i < stun_servers.size(); ++i) { 1.527 + nsresult rv = stun_servers[i].ToNicerStunStruct(&servers[i]); 1.528 + if (NS_FAILED(rv)) { 1.529 + MOZ_MTLOG(ML_ERROR, "Couldn't set STUN server for '" << name_ << "'"); 1.530 + return NS_ERROR_FAILURE; 1.531 + } 1.532 + } 1.533 + 1.534 + int r = nr_ice_ctx_set_stun_servers(ctx_, servers, stun_servers.size()); 1.535 + if (r) { 1.536 + MOZ_MTLOG(ML_ERROR, "Couldn't set STUN server for '" << name_ << "'"); 1.537 + return NS_ERROR_FAILURE; 1.538 + } 1.539 + 1.540 + return NS_OK; 1.541 +} 1.542 + 1.543 +// TODO(ekr@rtfm.com): This is just SetStunServers with s/Stun/Turn 1.544 +// Could we do a template or something? 1.545 +nsresult NrIceCtx::SetTurnServers(const std::vector<NrIceTurnServer>& 1.546 + turn_servers) { 1.547 + if (turn_servers.empty()) 1.548 + return NS_OK; 1.549 + 1.550 + ScopedDeleteArray<nr_ice_turn_server> servers( 1.551 + new nr_ice_turn_server[turn_servers.size()]); 1.552 + 1.553 + for (size_t i=0; i < turn_servers.size(); ++i) { 1.554 + nsresult rv = turn_servers[i].ToNicerTurnStruct(&servers[i]); 1.555 + if (NS_FAILED(rv)) { 1.556 + MOZ_MTLOG(ML_ERROR, "Couldn't set TURN server for '" << name_ << "'"); 1.557 + return NS_ERROR_FAILURE; 1.558 + } 1.559 + } 1.560 + 1.561 + int r = nr_ice_ctx_set_turn_servers(ctx_, servers, turn_servers.size()); 1.562 + if (r) { 1.563 + MOZ_MTLOG(ML_ERROR, "Couldn't set TURN server for '" << name_ << "'"); 1.564 + return NS_ERROR_FAILURE; 1.565 + } 1.566 + 1.567 + // TODO(ekr@rtfm.com): This leaks the username/password. Need to free that. 1.568 + 1.569 + return NS_OK; 1.570 +} 1.571 + 1.572 +nsresult NrIceCtx::SetResolver(nr_resolver *resolver) { 1.573 + int r = nr_ice_ctx_set_resolver(ctx_, resolver); 1.574 + 1.575 + if (r) { 1.576 + MOZ_MTLOG(ML_ERROR, "Couldn't set resolver for '" << name_ << "'"); 1.577 + return NS_ERROR_FAILURE; 1.578 + } 1.579 + 1.580 + return NS_OK; 1.581 +} 1.582 + 1.583 +nsresult NrIceCtx::StartGathering() { 1.584 + MOZ_ASSERT(ctx_->state == ICE_CTX_INIT); 1.585 + if (ctx_->state != ICE_CTX_INIT) { 1.586 + MOZ_MTLOG(ML_ERROR, "ICE ctx in the wrong state for gathering: '" 1.587 + << name_ << "'"); 1.588 + SetConnectionState(ICE_CTX_FAILED); 1.589 + return NS_ERROR_FAILURE; 1.590 + } 1.591 + 1.592 + int r = nr_ice_initialize(ctx_, &NrIceCtx::initialized_cb, 1.593 + this); 1.594 + 1.595 + if (r && r != R_WOULDBLOCK) { 1.596 + MOZ_MTLOG(ML_ERROR, "Couldn't gather ICE candidates for '" 1.597 + << name_ << "'"); 1.598 + SetConnectionState(ICE_CTX_FAILED); 1.599 + return NS_ERROR_FAILURE; 1.600 + } 1.601 + 1.602 + SetGatheringState(ICE_CTX_GATHER_STARTED); 1.603 + 1.604 + return NS_OK; 1.605 +} 1.606 + 1.607 +RefPtr<NrIceMediaStream> NrIceCtx::FindStream( 1.608 + nr_ice_media_stream *stream) { 1.609 + for (size_t i=0; i<streams_.size(); ++i) { 1.610 + if (streams_[i]->stream() == stream) { 1.611 + return streams_[i]; 1.612 + } 1.613 + } 1.614 + 1.615 + return nullptr; 1.616 +} 1.617 + 1.618 +std::vector<std::string> NrIceCtx::GetGlobalAttributes() { 1.619 + char **attrs = 0; 1.620 + int attrct; 1.621 + int r; 1.622 + std::vector<std::string> ret; 1.623 + 1.624 + r = nr_ice_get_global_attributes(ctx_, &attrs, &attrct); 1.625 + if (r) { 1.626 + MOZ_MTLOG(ML_ERROR, "Couldn't get ufrag and password for '" 1.627 + << name_ << "'"); 1.628 + return ret; 1.629 + } 1.630 + 1.631 + for (int i=0; i<attrct; i++) { 1.632 + ret.push_back(std::string(attrs[i])); 1.633 + RFREE(attrs[i]); 1.634 + } 1.635 + RFREE(attrs); 1.636 + 1.637 + return ret; 1.638 +} 1.639 + 1.640 +nsresult NrIceCtx::ParseGlobalAttributes(std::vector<std::string> attrs) { 1.641 + std::vector<char *> attrs_in; 1.642 + 1.643 + for (size_t i=0; i<attrs.size(); ++i) { 1.644 + attrs_in.push_back(const_cast<char *>(attrs[i].c_str())); 1.645 + } 1.646 + 1.647 + int r = nr_ice_peer_ctx_parse_global_attributes(peer_, 1.648 + attrs_in.size() ? 1.649 + &attrs_in[0] : nullptr, 1.650 + attrs_in.size()); 1.651 + if (r) { 1.652 + MOZ_MTLOG(ML_ERROR, "Couldn't parse global attributes for " 1.653 + << name_ << "'"); 1.654 + return NS_ERROR_FAILURE; 1.655 + } 1.656 + 1.657 + return NS_OK; 1.658 +} 1.659 + 1.660 +nsresult NrIceCtx::StartChecks() { 1.661 + int r; 1.662 + 1.663 + r=nr_ice_peer_ctx_pair_candidates(peer_); 1.664 + if (r) { 1.665 + MOZ_MTLOG(ML_ERROR, "Couldn't pair candidates on " 1.666 + << name_ << "'"); 1.667 + SetConnectionState(ICE_CTX_FAILED); 1.668 + return NS_ERROR_FAILURE; 1.669 + } 1.670 + 1.671 + r = nr_ice_peer_ctx_start_checks2(peer_,1); 1.672 + if (r) { 1.673 + if (r == R_NOT_FOUND) { 1.674 + MOZ_MTLOG(ML_ERROR, "Couldn't start peer checks on " 1.675 + << name_ << "' assuming trickle ICE"); 1.676 + } else { 1.677 + MOZ_MTLOG(ML_ERROR, "Couldn't start peer checks on " 1.678 + << name_ << "'"); 1.679 + SetConnectionState(ICE_CTX_FAILED); 1.680 + return NS_ERROR_FAILURE; 1.681 + } 1.682 + } else { 1.683 + SetConnectionState(ICE_CTX_CHECKING); 1.684 + } 1.685 + 1.686 + return NS_OK; 1.687 +} 1.688 + 1.689 + 1.690 +void NrIceCtx::initialized_cb(NR_SOCKET s, int h, void *arg) { 1.691 + NrIceCtx *ctx = static_cast<NrIceCtx *>(arg); 1.692 + 1.693 + ctx->SetGatheringState(ICE_CTX_GATHER_COMPLETE); 1.694 +} 1.695 + 1.696 +nsresult NrIceCtx::Finalize() { 1.697 + int r = nr_ice_ctx_finalize(ctx_, peer_); 1.698 + 1.699 + if (r) { 1.700 + MOZ_MTLOG(ML_ERROR, "Couldn't finalize " 1.701 + << name_ << "'"); 1.702 + return NS_ERROR_FAILURE; 1.703 + } 1.704 + 1.705 + return NS_OK; 1.706 +} 1.707 + 1.708 +void NrIceCtx::SetConnectionState(ConnectionState state) { 1.709 + if (state == connection_state_) 1.710 + return; 1.711 + 1.712 + MOZ_MTLOG(ML_INFO, "NrIceCtx(" << name_ << "): state " << 1.713 + connection_state_ << "->" << state); 1.714 + connection_state_ = state; 1.715 + 1.716 + SignalConnectionStateChange(this, state); 1.717 +} 1.718 + 1.719 +void NrIceCtx::SetGatheringState(GatheringState state) { 1.720 + if (state == gathering_state_) 1.721 + return; 1.722 + 1.723 + MOZ_MTLOG(ML_DEBUG, "NrIceCtx(" << name_ << "): gathering state " << 1.724 + gathering_state_ << "->" << state); 1.725 + gathering_state_ = state; 1.726 + 1.727 + SignalGatheringStateChange(this, state); 1.728 +} 1.729 + 1.730 +} // close namespace 1.731 + 1.732 +// Reimplement nr_ice_compute_codeword to avoid copyright issues 1.733 +void nr_ice_compute_codeword(char *buf, int len,char *codeword) { 1.734 + UINT4 c; 1.735 + 1.736 + r_crc32(buf,len,&c); 1.737 + 1.738 + PL_Base64Encode(reinterpret_cast<char*>(&c), 3, codeword); 1.739 + codeword[4] = 0; 1.740 + 1.741 + return; 1.742 +} 1.743 +