media/mtransport/nricectx.cpp

changeset 0
6474c204b198
     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, &param);
   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 +

mercurial