tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

nricectx.cpp (35570B)


      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 #include <string>
     44 #include <vector>
     45 
     46 #include "ScopedNSSTypes.h"
     47 #include "logging.h"
     48 #include "mozilla/Preferences.h"
     49 #include "nr_socket_proxy_config.h"
     50 #include "nsCOMPtr.h"
     51 #include "nsError.h"
     52 #include "nsIUUIDGenerator.h"
     53 #include "nsNetCID.h"
     54 #include "nsServiceManagerUtils.h"
     55 #include "nsXULAppAPI.h"
     56 #include "pk11pub.h"
     57 #include "runnable_utils.h"
     58 
     59 // nICEr includes
     60 extern "C" {
     61 // clang-format off
     62 #include "nr_api.h"
     63 #include "registry.h"
     64 #include "addrs.h"
     65 #include "async_timer.h"
     66 #include "r_crc32.h"
     67 #include "r_memory.h"
     68 #include "ice_reg.h"
     69 #include "transport_addr.h"
     70 #include "nr_crypto.h"
     71 #include "nr_socket.h"
     72 #include "nr_socket_local.h"
     73 #include "stun_reg.h"
     74 #include "ice_codeword.h"
     75 #include "ice_ctx.h"
     76 #include "ice_candidate.h"
     77 // clang-format on
     78 }
     79 
     80 // Local includes
     81 #include "mozilla/Base64.h"
     82 #include "nr_socket_prsock.h"
     83 #include "nricectx.h"
     84 #include "nricemediastream.h"
     85 #include "nrinterfaceprioritizer.h"
     86 #include "rlogconnector.h"
     87 #include "test_nr_socket.h"
     88 
     89 namespace mozilla {
     90 
     91 using std::shared_ptr;
     92 
     93 TimeStamp nr_socket_short_term_violation_time() {
     94  return NrSocketBase::short_term_violation_time();
     95 }
     96 
     97 TimeStamp nr_socket_long_term_violation_time() {
     98  return NrSocketBase::long_term_violation_time();
     99 }
    100 
    101 MOZ_MTLOG_MODULE("mtransport")
    102 
    103 const char kNrIceTransportUdp[] = "udp";
    104 const char kNrIceTransportTcp[] = "tcp";
    105 const char kNrIceTransportTls[] = "tls";
    106 
    107 static bool initialized = false;
    108 
    109 static int noop(void** obj) { return 0; }
    110 
    111 static nr_socket_factory_vtbl ctx_socket_factory_vtbl = {nr_socket_local_create,
    112                                                         noop};
    113 
    114 // Implement NSPR-based crypto algorithms
    115 static int nr_crypto_nss_random_bytes(UCHAR* buf, size_t len) {
    116  UniquePK11SlotInfo slot(PK11_GetInternalSlot());
    117  if (!slot) return R_INTERNAL;
    118 
    119  SECStatus rv = PK11_GenerateRandomOnSlot(slot.get(), buf, len);
    120  if (rv != SECSuccess) return R_INTERNAL;
    121 
    122  return 0;
    123 }
    124 
    125 static int nr_crypto_nss_hmac(UCHAR* key, size_t keyl, UCHAR* buf, size_t bufl,
    126                              UCHAR* result) {
    127  CK_MECHANISM_TYPE mech = CKM_SHA_1_HMAC;
    128  PK11SlotInfo* slot = nullptr;
    129  MOZ_ASSERT(keyl > 0);
    130  SECItem keyi = {siBuffer, key, static_cast<unsigned int>(keyl)};
    131  PK11SymKey* skey = nullptr;
    132  PK11Context* hmac_ctx = nullptr;
    133  SECStatus status;
    134  unsigned int hmac_len;
    135  SECItem param = {siBuffer, nullptr, 0};
    136  int err = R_INTERNAL;
    137 
    138  slot = PK11_GetInternalKeySlot();
    139  if (!slot) goto abort;
    140 
    141  skey = PK11_ImportSymKey(slot, mech, PK11_OriginUnwrap, CKA_SIGN, &keyi,
    142                           nullptr);
    143  if (!skey) goto abort;
    144 
    145  hmac_ctx = PK11_CreateContextBySymKey(mech, CKA_SIGN, skey, &param);
    146  if (!hmac_ctx) goto abort;
    147 
    148  status = PK11_DigestBegin(hmac_ctx);
    149  if (status != SECSuccess) goto abort;
    150 
    151  status = PK11_DigestOp(hmac_ctx, buf, bufl);
    152  if (status != SECSuccess) goto abort;
    153 
    154  status = PK11_DigestFinal(hmac_ctx, result, &hmac_len, 20);
    155  if (status != SECSuccess) goto abort;
    156 
    157  MOZ_ASSERT(hmac_len == 20);
    158 
    159  err = 0;
    160 
    161 abort:
    162  if (hmac_ctx) PK11_DestroyContext(hmac_ctx, PR_TRUE);
    163  if (skey) PK11_FreeSymKey(skey);
    164  if (slot) PK11_FreeSlot(slot);
    165 
    166  return err;
    167 }
    168 
    169 static int nr_crypto_nss_md5(UCHAR* buf, size_t bufl, UCHAR* result) {
    170  int err = R_INTERNAL;
    171  SECStatus rv;
    172 
    173  const SECHashObject* ho = HASH_GetHashObject(HASH_AlgMD5);
    174  MOZ_ASSERT(ho);
    175  if (!ho) goto abort;
    176 
    177  MOZ_ASSERT(ho->length == 16);
    178 
    179  rv = HASH_HashBuf(ho->type, result, buf, bufl);
    180  if (rv != SECSuccess) goto abort;
    181 
    182  err = 0;
    183 abort:
    184  return err;
    185 }
    186 
    187 static nr_ice_crypto_vtbl nr_ice_crypto_nss_vtbl = {
    188    nr_crypto_nss_random_bytes, nr_crypto_nss_hmac, nr_crypto_nss_md5};
    189 
    190 nsresult NrIceStunServer::ToNicerStunStruct(nr_ice_stun_server* server) const {
    191  int r;
    192 
    193  memset(server, 0, sizeof(nr_ice_stun_server));
    194  uint8_t protocol;
    195  if (transport_ == kNrIceTransportUdp) {
    196    protocol = IPPROTO_UDP;
    197  } else if (transport_ == kNrIceTransportTcp) {
    198    protocol = IPPROTO_TCP;
    199  } else if (transport_ == kNrIceTransportTls) {
    200    protocol = IPPROTO_TCP;
    201  } else {
    202    MOZ_MTLOG(ML_ERROR, "Unsupported STUN server transport: " << transport_);
    203    return NS_ERROR_FAILURE;
    204  }
    205 
    206  if (has_addr_) {
    207    if (transport_ == kNrIceTransportTls) {
    208      // Refuse to try TLS without an FQDN
    209      return NS_ERROR_INVALID_ARG;
    210    }
    211    r = nr_praddr_to_transport_addr(&addr_, &server->addr, protocol, 0);
    212    if (r) {
    213      return NS_ERROR_FAILURE;
    214    }
    215  } else {
    216    MOZ_ASSERT(sizeof(server->addr.fqdn) > host_.size());
    217    // Dummy information to keep nICEr happy
    218    if (use_ipv6_if_fqdn_) {
    219      nr_str_port_to_transport_addr("::", port_, protocol, &server->addr);
    220    } else {
    221      nr_str_port_to_transport_addr("0.0.0.0", port_, protocol, &server->addr);
    222    }
    223    PL_strncpyz(server->addr.fqdn, host_.c_str(), sizeof(server->addr.fqdn));
    224    if (transport_ == kNrIceTransportTls) {
    225      server->addr.tls = 1;
    226    }
    227  }
    228 
    229  nr_transport_addr_fmt_addr_string(&server->addr);
    230 
    231  return NS_OK;
    232 }
    233 
    234 nsresult NrIceTurnServer::ToNicerTurnStruct(nr_ice_turn_server* server) const {
    235  memset(server, 0, sizeof(nr_ice_turn_server));
    236 
    237  nsresult rv = ToNicerStunStruct(&server->turn_server);
    238  if (NS_FAILED(rv)) return rv;
    239 
    240  if (!(server->username = r_strdup(username_.c_str())))
    241    return NS_ERROR_OUT_OF_MEMORY;
    242 
    243  // TODO(ekr@rtfm.com): handle non-ASCII passwords somehow?
    244  // STUN requires they be SASLpreped, but we don't know if
    245  // they are at this point.
    246 
    247  // C++03 23.2.4, Paragraph 1 stipulates that the elements
    248  // in std::vector must be contiguous, and can therefore be
    249  // used as input to functions expecting C arrays.
    250  const UCHAR* data = password_.empty() ? nullptr : &password_[0];
    251  int r = r_data_create(&server->password, data, password_.size());
    252  if (r) {
    253    RFREE(server->username);
    254    return NS_ERROR_OUT_OF_MEMORY;
    255  }
    256 
    257  return NS_OK;
    258 }
    259 
    260 NrIceCtx::NrIceCtx(const std::string& name)
    261    : name_(name),
    262      ice_controlling_set_(false),
    263      ctx_(nullptr),
    264      peer_(nullptr),
    265      ice_handler_vtbl_(nullptr),
    266      ice_handler_(nullptr),
    267      ice_gather_handler_vtbl_(nullptr),
    268      ice_gather_handler_(nullptr),
    269      trickle_(true),
    270      config_(),
    271      nat_(nullptr),
    272      proxy_config_(nullptr) {}
    273 
    274 /* static */
    275 RefPtr<NrIceCtx> NrIceCtx::Create(const std::string& aName) {
    276  RefPtr<NrIceCtx> ctx = new NrIceCtx(aName);
    277 
    278  if (!ctx->Initialize()) {
    279    return nullptr;
    280  }
    281 
    282  return ctx;
    283 }
    284 
    285 nsresult NrIceCtx::SetIceConfig(const Config& aConfig) {
    286  config_ = aConfig;
    287  switch (config_.mPolicy) {
    288    case ICE_POLICY_RELAY:
    289      MOZ_MTLOG(ML_DEBUG, "SetIceConfig: relay only");
    290      nr_ice_ctx_remove_flags(ctx_, NR_ICE_CTX_FLAGS_DISABLE_HOST_CANDIDATES);
    291      nr_ice_ctx_add_flags(ctx_, NR_ICE_CTX_FLAGS_RELAY_ONLY);
    292      break;
    293    case ICE_POLICY_NO_HOST:
    294      MOZ_MTLOG(ML_DEBUG, "SetIceConfig: no host");
    295      nr_ice_ctx_add_flags(ctx_, NR_ICE_CTX_FLAGS_DISABLE_HOST_CANDIDATES);
    296      nr_ice_ctx_remove_flags(ctx_, NR_ICE_CTX_FLAGS_RELAY_ONLY);
    297      break;
    298    case ICE_POLICY_ALL:
    299      MOZ_MTLOG(ML_DEBUG, "SetIceConfig: all");
    300      nr_ice_ctx_remove_flags(ctx_, NR_ICE_CTX_FLAGS_DISABLE_HOST_CANDIDATES);
    301      nr_ice_ctx_remove_flags(ctx_, NR_ICE_CTX_FLAGS_RELAY_ONLY);
    302      break;
    303  }
    304 
    305  if (config_.mAllowLoopback) {
    306    nr_ice_ctx_add_flags(ctx_, NR_ICE_CTX_FLAGS_ALLOW_LOOPBACK);
    307  }
    308 
    309  if (config_.mAllowLinkLocal) {
    310    nr_ice_ctx_add_flags(ctx_, NR_ICE_CTX_FLAGS_ALLOW_LINK_LOCAL);
    311  }
    312 
    313  // TODO: Support re-configuring the test NAT someday?
    314  if (!nat_ && config_.mNatSimulatorConfig.isSome()) {
    315    TestNat* test_nat = new TestNat;
    316    test_nat->filtering_type_ = TestNat::ToNatBehavior(
    317        config_.mNatSimulatorConfig->mFilteringType.get());
    318    test_nat->mapping_type_ =
    319        TestNat::ToNatBehavior(config_.mNatSimulatorConfig->mMappingType.get());
    320    test_nat->block_udp_ = config_.mNatSimulatorConfig->mBlockUdp;
    321    test_nat->block_tcp_ = config_.mNatSimulatorConfig->mBlockTcp;
    322    test_nat->block_tls_ = config_.mNatSimulatorConfig->mBlockTls;
    323    test_nat->error_code_for_drop_ =
    324        config_.mNatSimulatorConfig->mErrorCodeForDrop;
    325    if (config_.mNatSimulatorConfig->mRedirectAddress.Length()) {
    326      test_nat
    327          ->stun_redirect_map_[config_.mNatSimulatorConfig->mRedirectAddress] =
    328          config_.mNatSimulatorConfig->mRedirectTargets;
    329    }
    330    test_nat->network_delay_ms_ = config_.mNatSimulatorConfig->mNetworkDelayMs;
    331    test_nat->enabled_ = true;
    332    SetNat(test_nat);
    333  }
    334 
    335  return NS_OK;
    336 }
    337 
    338 RefPtr<NrIceMediaStream> NrIceCtx::CreateStream(const std::string& id,
    339                                                const std::string& name,
    340                                                int components) {
    341  if (streams_.count(id)) {
    342    MOZ_ASSERT(false);
    343    return nullptr;
    344  }
    345 
    346  RefPtr<NrIceMediaStream> stream =
    347      new NrIceMediaStream(this, id, name, components);
    348  streams_[id] = stream;
    349  return stream;
    350 }
    351 
    352 void NrIceCtx::DestroyStream(const std::string& id) {
    353  auto it = streams_.find(id);
    354  if (it != streams_.end()) {
    355    auto preexisting_stream = it->second;
    356    SignalConnectionStateChange(preexisting_stream, ICE_CTX_CLOSED);
    357    streams_.erase(it);
    358    preexisting_stream->Close();
    359  }
    360 }
    361 
    362 // Handler callbacks
    363 int NrIceCtx::select_pair(void* obj, nr_ice_media_stream* stream,
    364                          int component_id, nr_ice_cand_pair** potentials,
    365                          int potential_ct) {
    366  MOZ_MTLOG(ML_DEBUG, "select pair called: potential_ct = " << potential_ct);
    367  MOZ_ASSERT(stream->local_stream);
    368  MOZ_ASSERT(!stream->local_stream->obsolete);
    369 
    370  return 0;
    371 }
    372 
    373 int NrIceCtx::stream_ready(void* obj, nr_ice_media_stream* stream) {
    374  MOZ_MTLOG(ML_DEBUG, "stream_ready called");
    375  MOZ_ASSERT(!stream->local_stream);
    376  MOZ_ASSERT(!stream->obsolete);
    377 
    378  // Get the ICE ctx.
    379  NrIceCtx* ctx = static_cast<NrIceCtx*>(obj);
    380 
    381  RefPtr<NrIceMediaStream> s = ctx->FindStream(stream);
    382 
    383  // Streams which do not exist should never be ready.
    384  MOZ_ASSERT(s);
    385 
    386  s->Ready(stream);
    387  ctx->SignalConnectionStateChange(s, ICE_CTX_CONNECTED);
    388 
    389  return 0;
    390 }
    391 
    392 int NrIceCtx::stream_failed(void* obj, nr_ice_media_stream* stream) {
    393  MOZ_MTLOG(ML_DEBUG, "stream_failed called");
    394  MOZ_ASSERT(!stream->local_stream);
    395  MOZ_ASSERT(!stream->obsolete);
    396 
    397  // Get the ICE ctx
    398  NrIceCtx* ctx = static_cast<NrIceCtx*>(obj);
    399  RefPtr<NrIceMediaStream> s = ctx->FindStream(stream);
    400 
    401  // Streams which do not exist should never fail.
    402  MOZ_ASSERT(s);
    403 
    404  if (!ctx->dumped_rlog_) {
    405    // Do this at most once per ctx
    406    ctx->dumped_rlog_ = true;
    407    MOZ_MTLOG(ML_INFO,
    408              "NrIceCtx(" << ctx->name_ << "): dumping r_log ringbuffer... ");
    409    std::deque<std::string> logs;
    410    RLogConnector::GetInstance()->GetAny(0, &logs);
    411    for (auto& log : logs) {
    412      MOZ_MTLOG(ML_INFO, log);
    413    }
    414  }
    415 
    416  s->Failed();
    417  ctx->SignalConnectionStateChange(s, ICE_CTX_FAILED);
    418  return 0;
    419 }
    420 
    421 int NrIceCtx::stream_checking(void* obj, nr_ice_media_stream* stream) {
    422  MOZ_MTLOG(ML_DEBUG, "stream_checking called");
    423  MOZ_ASSERT(!stream->local_stream);
    424  MOZ_ASSERT(!stream->obsolete);
    425 
    426  // Get the ICE ctx
    427  NrIceCtx* ctx = static_cast<NrIceCtx*>(obj);
    428  RefPtr<NrIceMediaStream> s = ctx->FindStream(stream);
    429 
    430  MOZ_ASSERT(s);
    431 
    432  if (!s->AnyGenerationIsConnected()) {
    433    // the checking state only applies if we aren't connected
    434    ctx->SignalConnectionStateChange(s, ICE_CTX_CHECKING);
    435  }
    436  return 0;
    437 }
    438 
    439 int NrIceCtx::stream_disconnected(void* obj, nr_ice_media_stream* stream) {
    440  MOZ_MTLOG(ML_DEBUG, "stream_disconnected called");
    441  MOZ_ASSERT(!stream->local_stream);
    442  MOZ_ASSERT(!stream->obsolete);
    443 
    444  // Get the ICE ctx
    445  NrIceCtx* ctx = static_cast<NrIceCtx*>(obj);
    446  RefPtr<NrIceMediaStream> s = ctx->FindStream(stream);
    447 
    448  MOZ_ASSERT(s);
    449 
    450  ctx->SignalConnectionStateChange(s, ICE_CTX_DISCONNECTED);
    451  return 0;
    452 }
    453 
    454 int NrIceCtx::stream_gathering(void* obj, nr_ice_media_stream* stream) {
    455  MOZ_MTLOG(ML_DEBUG, "stream_gathering called");
    456  MOZ_ASSERT(!stream->local_stream);
    457  MOZ_ASSERT(!stream->obsolete);
    458 
    459  // Get the ICE ctx
    460  NrIceCtx* ctx = static_cast<NrIceCtx*>(obj);
    461  RefPtr<NrIceMediaStream> s = ctx->FindStream(stream);
    462 
    463  MOZ_ASSERT(s);
    464 
    465  s->OnGatheringStarted(stream);
    466  return 0;
    467 }
    468 
    469 int NrIceCtx::stream_gathered(void* obj, nr_ice_media_stream* stream) {
    470  MOZ_MTLOG(ML_DEBUG, "stream_gathered called");
    471  MOZ_ASSERT(!stream->local_stream);
    472 
    473  // Get the ICE ctx
    474  NrIceCtx* ctx = static_cast<NrIceCtx*>(obj);
    475  RefPtr<NrIceMediaStream> s = ctx->FindStream(stream);
    476 
    477  // We get this callback for destroyed streams in some cases
    478  if (s) {
    479    s->OnGatheringComplete(stream);
    480  }
    481  return 0;
    482 }
    483 
    484 int NrIceCtx::ice_checking(void* obj, nr_ice_peer_ctx* pctx) {
    485  MOZ_MTLOG(ML_DEBUG, "ice_checking called");
    486  // We don't use this; we react to the stream-specific callbacks instead
    487  return 0;
    488 }
    489 
    490 int NrIceCtx::ice_connected(void* obj, nr_ice_peer_ctx* pctx) {
    491  MOZ_MTLOG(ML_DEBUG, "ice_connected called");
    492  // We don't use this; we react to the stream-specific callbacks instead
    493  return 0;
    494 }
    495 
    496 int NrIceCtx::ice_disconnected(void* obj, nr_ice_peer_ctx* pctx) {
    497  MOZ_MTLOG(ML_DEBUG, "ice_disconnected called");
    498  // We don't use this; we react to the stream-specific callbacks instead
    499  return 0;
    500 }
    501 
    502 int NrIceCtx::msg_recvd(void* obj, nr_ice_peer_ctx* pctx,
    503                        nr_ice_media_stream* stream, int component_id,
    504                        UCHAR* msg, int len) {
    505  // Get the ICE ctx
    506  NrIceCtx* ctx = static_cast<NrIceCtx*>(obj);
    507  RefPtr<NrIceMediaStream> s = ctx->FindStream(stream);
    508 
    509  // Streams which do not exist should never have packets.
    510  MOZ_ASSERT(s);
    511 
    512  s->SignalPacketReceived(s, component_id, msg, len);
    513 
    514  return 0;
    515 }
    516 
    517 void NrIceCtx::trickle_cb(void* arg, nr_ice_ctx* ice_ctx,
    518                          nr_ice_media_stream* stream, int component_id,
    519                          nr_ice_candidate* candidate) {
    520  if (stream->obsolete) {
    521    // Stream was probably just marked obsolete, resulting in this callback
    522    return;
    523  }
    524  // Get the ICE ctx
    525  NrIceCtx* ctx = static_cast<NrIceCtx*>(arg);
    526  RefPtr<NrIceMediaStream> s = ctx->FindStream(stream);
    527 
    528  if (!s) {
    529    // This stream has been removed because it is inactive
    530    return;
    531  }
    532 
    533  if (!candidate) {
    534    return;
    535  }
    536 
    537  std::string actual_addr;
    538  std::string mdns_addr;
    539  ctx->GenerateObfuscatedAddress(candidate, &mdns_addr, &actual_addr);
    540 
    541  // Format the candidate.
    542  char candidate_str[NR_ICE_MAX_ATTRIBUTE_SIZE];
    543  int r = nr_ice_format_candidate_attribute(
    544      candidate, candidate_str, sizeof(candidate_str),
    545      (ctx->ctx()->flags & NR_ICE_CTX_FLAGS_OBFUSCATE_HOST_ADDRESSES) ? 1 : 0);
    546  MOZ_ASSERT(!r);
    547  if (r) return;
    548 
    549  MOZ_MTLOG(ML_INFO, "NrIceCtx(" << ctx->name_ << "): trickling candidate "
    550                                 << candidate_str);
    551 
    552  s->SignalCandidate(s, candidate_str, stream->ufrag, mdns_addr, actual_addr);
    553 }
    554 
    555 void NrIceCtx::InitializeGlobals(const GlobalConfig& aConfig) {
    556  RLogConnector::CreateInstance();
    557  // Initialize the crypto callbacks and logging stuff
    558  if (!initialized) {
    559    NR_reg_init();
    560    nr_crypto_vtbl = &nr_ice_crypto_nss_vtbl;
    561    initialized = true;
    562 
    563    // Set the priorites for candidate type preferences.
    564    // These numbers come from RFC 5245 S. 4.1.2.2
    565    NR_reg_set_uchar((char*)NR_ICE_REG_PREF_TYPE_SRV_RFLX, 100);
    566    NR_reg_set_uchar((char*)NR_ICE_REG_PREF_TYPE_PEER_RFLX, 110);
    567    NR_reg_set_uchar((char*)NR_ICE_REG_PREF_TYPE_HOST, 126);
    568    NR_reg_set_uchar((char*)NR_ICE_REG_PREF_TYPE_RELAYED, 5);
    569    NR_reg_set_uchar((char*)NR_ICE_REG_PREF_TYPE_SRV_RFLX_TCP, 99);
    570    NR_reg_set_uchar((char*)NR_ICE_REG_PREF_TYPE_PEER_RFLX_TCP, 109);
    571    NR_reg_set_uchar((char*)NR_ICE_REG_PREF_TYPE_HOST_TCP, 125);
    572    NR_reg_set_uchar((char*)NR_ICE_REG_PREF_TYPE_RELAYED_TCP, 0);
    573    NR_reg_set_uint4((char*)"stun.client.maximum_transmits",
    574                     aConfig.mStunClientMaxTransmits);
    575    NR_reg_set_uint4((char*)NR_ICE_REG_TRICKLE_GRACE_PERIOD,
    576                     aConfig.mTrickleIceGracePeriod);
    577    NR_reg_set_int4((char*)NR_ICE_REG_ICE_TCP_SO_SOCK_COUNT,
    578                    aConfig.mIceTcpSoSockCount);
    579    NR_reg_set_int4((char*)NR_ICE_REG_ICE_TCP_LISTEN_BACKLOG,
    580                    aConfig.mIceTcpListenBacklog);
    581 
    582    NR_reg_set_char((char*)NR_ICE_REG_ICE_TCP_DISABLE, !aConfig.mTcpEnabled);
    583 
    584    if (!aConfig.mForceNetInterface.Length()) {
    585      NR_reg_set_string((char*)NR_ICE_REG_PREF_FORCE_INTERFACE_NAME,
    586                        const_cast<char*>(aConfig.mForceNetInterface.get()));
    587    }
    588 
    589    // For now, always use nr_resolver for UDP.
    590    NR_reg_set_char((char*)NR_ICE_REG_USE_NR_RESOLVER_FOR_UDP, 1);
    591 
    592    // Use nr_resolver for TCP only when not in e10s mode (for unit-tests)
    593    if (XRE_IsParentProcess()) {
    594      NR_reg_set_char((char*)NR_ICE_REG_USE_NR_RESOLVER_FOR_TCP, 1);
    595    }
    596  }
    597 }
    598 
    599 void NrIceCtx::SetTargetForDefaultLocalAddressLookup(
    600    const std::string& target_ip, uint16_t target_port) {
    601  nr_ice_set_target_for_default_local_address_lookup(ctx_, target_ip.c_str(),
    602                                                     target_port);
    603 }
    604 
    605 #define MAXADDRS 100  // mirrors setting in ice_ctx.c
    606 
    607 /* static */
    608 nsTArray<NrIceStunAddr> NrIceCtx::GetStunAddrs() {
    609  nsTArray<NrIceStunAddr> addrs;
    610 
    611  nr_local_addr local_addrs[MAXADDRS];
    612  int addr_ct = 0;
    613 
    614  // most likely running on parent process and need crypto vtbl
    615  // initialized on Windows (Linux and OSX don't seem to care)
    616  if (!initialized) {
    617    nr_crypto_vtbl = &nr_ice_crypto_nss_vtbl;
    618  }
    619 
    620  MOZ_MTLOG(ML_INFO, "NrIceCtx static call to find local stun addresses");
    621  if (nr_stun_get_addrs(local_addrs, MAXADDRS, &addr_ct)) {
    622    MOZ_MTLOG(ML_INFO, "Error finding local stun addresses");
    623  } else {
    624    for (int i = 0; i < addr_ct; ++i) {
    625      NrIceStunAddr addr(&local_addrs[i]);
    626      addrs.AppendElement(addr);
    627    }
    628  }
    629 
    630  return addrs;
    631 }
    632 
    633 void NrIceCtx::SetStunAddrs(const nsTArray<NrIceStunAddr>& addrs) {
    634  nr_local_addr* local_addrs;
    635  local_addrs = new nr_local_addr[addrs.Length()];
    636 
    637  for (size_t i = 0; i < addrs.Length(); ++i) {
    638    nr_local_addr_copy(&local_addrs[i],
    639                       const_cast<nr_local_addr*>(&addrs[i].localAddr()));
    640  }
    641  nr_ice_set_local_addresses(ctx_, local_addrs, addrs.Length());
    642 
    643  delete[] local_addrs;
    644 }
    645 
    646 bool NrIceCtx::Initialize() {
    647  // Create the gather handler objects
    648  ice_gather_handler_vtbl_ = new nr_ice_gather_handler_vtbl();
    649  ice_gather_handler_vtbl_->stream_gathering = &NrIceCtx::stream_gathering;
    650  ice_gather_handler_vtbl_->stream_gathered = &NrIceCtx::stream_gathered;
    651  ice_gather_handler_ = new nr_ice_gather_handler();
    652  ice_gather_handler_->vtbl = ice_gather_handler_vtbl_;
    653  ice_gather_handler_->obj = this;
    654 
    655  // Create the ICE context
    656  int r;
    657 
    658  UINT4 flags = NR_ICE_CTX_FLAGS_AGGRESSIVE_NOMINATION;
    659 
    660  r = nr_ice_ctx_create(const_cast<char*>(name_.c_str()), flags,
    661                        ice_gather_handler_, &ctx_);
    662 
    663  if (r) {
    664    MOZ_MTLOG(ML_ERROR, "Couldn't create ICE ctx for '" << name_ << "'");
    665    return false;
    666  }
    667 
    668  // override default factory to capture optional proxy config when creating
    669  // sockets.
    670  nr_socket_factory* factory;
    671  r = nr_socket_factory_create_int(this, &ctx_socket_factory_vtbl, &factory);
    672 
    673  if (r) {
    674    MOZ_MTLOG(LogLevel::Error, "Couldn't create ctx socket factory.");
    675    return false;
    676  }
    677  nr_ice_ctx_set_socket_factory(ctx_, factory);
    678 
    679  nr_interface_prioritizer* prioritizer = CreateInterfacePrioritizer();
    680  if (!prioritizer) {
    681    MOZ_MTLOG(LogLevel::Error, "Couldn't create interface prioritizer.");
    682    return false;
    683  }
    684 
    685  r = nr_ice_ctx_set_interface_prioritizer(ctx_, prioritizer);
    686  if (r) {
    687    MOZ_MTLOG(LogLevel::Error, "Couldn't set interface prioritizer.");
    688    return false;
    689  }
    690 
    691  if (generating_trickle()) {
    692    r = nr_ice_ctx_set_trickle_cb(ctx_, &NrIceCtx::trickle_cb, this);
    693    if (r) {
    694      MOZ_MTLOG(ML_ERROR, "Couldn't set trickle cb for '" << name_ << "'");
    695      return false;
    696    }
    697  }
    698 
    699  // Create the handler objects
    700  ice_handler_vtbl_ = new nr_ice_handler_vtbl();
    701  ice_handler_vtbl_->select_pair = &NrIceCtx::select_pair;
    702  ice_handler_vtbl_->stream_ready = &NrIceCtx::stream_ready;
    703  ice_handler_vtbl_->stream_failed = &NrIceCtx::stream_failed;
    704  ice_handler_vtbl_->stream_checking = &NrIceCtx::stream_checking;
    705  ice_handler_vtbl_->stream_disconnected = &NrIceCtx::stream_disconnected;
    706  // stream_gathering and stream_gathered do not go here, since those are tied
    707  // to the _local_ nr_ice_media_stream in nICEr. nICEr allows a local
    708  // nr_ice_media_stream (which has a single set of candidates, and therefore a
    709  // single gathering state) to be associated with multiple remote
    710  // nr_ice_media_streams (which each have their own ICE connection state)
    711  // because it allows forking. We never encounter forking, so these will be
    712  // one-to-one in practice, but the architecture in nICEr means we have to set
    713  // up these callbacks on the nr_ice_ctx, not the nr_ice_peer_ctx.
    714  ice_handler_vtbl_->ice_connected = &NrIceCtx::ice_connected;
    715  ice_handler_vtbl_->msg_recvd = &NrIceCtx::msg_recvd;
    716  ice_handler_vtbl_->ice_checking = &NrIceCtx::ice_checking;
    717  ice_handler_vtbl_->ice_disconnected = &NrIceCtx::ice_disconnected;
    718 
    719  ice_handler_ = new nr_ice_handler();
    720  ice_handler_->vtbl = ice_handler_vtbl_;
    721  ice_handler_->obj = this;
    722 
    723  // Create the peer ctx. Because we do not support parallel forking, we
    724  // only have one peer ctx.
    725  std::string peer_name = name_ + ":default";
    726  r = nr_ice_peer_ctx_create(ctx_, ice_handler_,
    727                             const_cast<char*>(peer_name.c_str()), &peer_);
    728  if (r) {
    729    MOZ_MTLOG(ML_ERROR, "Couldn't create ICE peer ctx for '" << name_ << "'");
    730    return false;
    731  }
    732 
    733  nsresult rv;
    734  sts_target_ = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
    735 
    736  if (!NS_SUCCEEDED(rv)) return false;
    737 
    738  return true;
    739 }
    740 
    741 int NrIceCtx::SetNat(const RefPtr<TestNat>& aNat) {
    742  nat_ = aNat;
    743  nr_socket_factory* fac;
    744  int r = nat_->create_socket_factory(&fac);
    745  if (r) {
    746    return r;
    747  }
    748  nr_ice_ctx_set_socket_factory(ctx_, fac);
    749  return 0;
    750 }
    751 
    752 // ONLY USE THIS FOR TESTING. Will cause totally unpredictable and possibly very
    753 // bad effects if ICE is still live.
    754 void NrIceCtx::internal_DeinitializeGlobal() {
    755  NR_reg_del((char*)"stun");
    756  NR_reg_del((char*)"ice");
    757  RLogConnector::DestroyInstance();
    758  nr_crypto_vtbl = nullptr;
    759  initialized = false;
    760 }
    761 
    762 void NrIceCtx::internal_SetTimerAccelarator(int divider) {
    763  ctx_->test_timer_divider = divider;
    764 }
    765 
    766 void NrIceCtx::AccumulateStats(const NrIceStats& stats) {
    767  nr_accumulate_count(&(ctx_->stats.stun_retransmits), stats.stun_retransmits);
    768  nr_accumulate_count(&(ctx_->stats.turn_401s), stats.turn_401s);
    769  nr_accumulate_count(&(ctx_->stats.turn_403s), stats.turn_403s);
    770  nr_accumulate_count(&(ctx_->stats.turn_438s), stats.turn_438s);
    771 }
    772 
    773 NrIceStats NrIceCtx::Destroy() {
    774  // designed to be called more than once so if stats are desired, this can be
    775  // called just prior to the destructor
    776  MOZ_MTLOG(ML_NOTICE, "NrIceCtx(" << name_ << "): " << __func__);
    777 
    778  for (auto& idAndStream : streams_) {
    779    idAndStream.second->Close();
    780  }
    781 
    782  NrIceStats stats;
    783  if (ctx_) {
    784    stats.stun_retransmits = ctx_->stats.stun_retransmits;
    785    stats.turn_401s = ctx_->stats.turn_401s;
    786    stats.turn_403s = ctx_->stats.turn_403s;
    787    stats.turn_438s = ctx_->stats.turn_438s;
    788  }
    789 
    790  if (peer_) {
    791    nr_ice_peer_ctx_destroy(&peer_);
    792  }
    793  if (ctx_) {
    794    nr_ice_ctx_destroy(&ctx_);
    795  }
    796 
    797  delete ice_handler_vtbl_;
    798  delete ice_handler_;
    799 
    800  delete ice_gather_handler_vtbl_;
    801  delete ice_gather_handler_;
    802 
    803  ice_handler_vtbl_ = nullptr;
    804  ice_handler_ = nullptr;
    805  ice_gather_handler_vtbl_ = nullptr;
    806  ice_gather_handler_ = nullptr;
    807  proxy_config_ = nullptr;
    808  streams_.clear();
    809 
    810  return stats;
    811 }
    812 
    813 NrIceCtx::~NrIceCtx() = default;
    814 
    815 void NrIceCtx::destroy_peer_ctx() { nr_ice_peer_ctx_destroy(&peer_); }
    816 
    817 nsresult NrIceCtx::SetControlling(Controlling controlling) {
    818  if (!ice_controlling_set_) {
    819    peer_->controlling = (controlling == ICE_CONTROLLING) ? 1 : 0;
    820    ice_controlling_set_ = true;
    821 
    822    MOZ_MTLOG(ML_DEBUG,
    823              "ICE ctx " << name_ << " setting controlling to" << controlling);
    824  }
    825  return NS_OK;
    826 }
    827 
    828 NrIceCtx::Controlling NrIceCtx::GetControlling() {
    829  return (peer_->controlling) ? ICE_CONTROLLING : ICE_CONTROLLED;
    830 }
    831 
    832 nsresult NrIceCtx::SetStunServers(
    833    const std::vector<NrIceStunServer>& stun_servers) {
    834  MOZ_MTLOG(ML_NOTICE, "NrIceCtx(" << name_ << "): " << __func__);
    835  // We assume nr_ice_stun_server is memmoveable. That's true right now.
    836  std::vector<nr_ice_stun_server> servers;
    837 
    838  for (size_t i = 0; i < stun_servers.size(); ++i) {
    839    nr_ice_stun_server server;
    840    nsresult rv = stun_servers[i].ToNicerStunStruct(&server);
    841    if (NS_WARN_IF(NS_FAILED(rv))) {
    842      MOZ_MTLOG(ML_ERROR, "Couldn't convert STUN server for '" << name_ << "'");
    843    } else {
    844      servers.push_back(server);
    845    }
    846  }
    847 
    848  int r = nr_ice_ctx_set_stun_servers(ctx_, servers.data(),
    849                                      static_cast<int>(servers.size()));
    850  if (r) {
    851    MOZ_MTLOG(ML_ERROR, "Couldn't set STUN servers for '" << name_ << "'");
    852    return NS_ERROR_FAILURE;
    853  }
    854 
    855  return NS_OK;
    856 }
    857 
    858 // TODO(ekr@rtfm.com): This is just SetStunServers with s/Stun/Turn
    859 // Could we do a template or something?
    860 nsresult NrIceCtx::SetTurnServers(
    861    const std::vector<NrIceTurnServer>& turn_servers) {
    862  MOZ_MTLOG(ML_NOTICE, "NrIceCtx(" << name_ << "): " << __func__);
    863  // We assume nr_ice_turn_server is memmoveable. That's true right now.
    864  std::vector<nr_ice_turn_server> servers;
    865 
    866  for (size_t i = 0; i < turn_servers.size(); ++i) {
    867    nr_ice_turn_server server;
    868    nsresult rv = turn_servers[i].ToNicerTurnStruct(&server);
    869    if (NS_WARN_IF(NS_FAILED(rv))) {
    870      MOZ_MTLOG(ML_ERROR, "Couldn't convert TURN server for '" << name_ << "'");
    871    } else {
    872      servers.push_back(server);
    873    }
    874  }
    875 
    876  int r = nr_ice_ctx_set_turn_servers(ctx_, servers.data(),
    877                                      static_cast<int>(servers.size()));
    878  if (r) {
    879    MOZ_MTLOG(ML_ERROR, "Couldn't set TURN servers for '" << name_ << "'");
    880    // TODO(ekr@rtfm.com): This leaks the username/password. Need to free that.
    881    return NS_ERROR_FAILURE;
    882  }
    883 
    884  return NS_OK;
    885 }
    886 
    887 nsresult NrIceCtx::SetResolver(nr_resolver* resolver) {
    888  int r = nr_ice_ctx_set_resolver(ctx_, resolver);
    889 
    890  if (r) {
    891    MOZ_MTLOG(ML_ERROR, "Couldn't set resolver for '" << name_ << "'");
    892    return NS_ERROR_FAILURE;
    893  }
    894 
    895  return NS_OK;
    896 }
    897 
    898 nsresult NrIceCtx::SetProxyConfig(NrSocketProxyConfig&& config) {
    899  proxy_config_.reset(new NrSocketProxyConfig(std::move(config)));
    900  if (nat_) {
    901    nat_->set_proxy_config(proxy_config_);
    902  }
    903 
    904  if (proxy_config_->GetForceProxy()) {
    905    nr_ice_ctx_add_flags(ctx_, NR_ICE_CTX_FLAGS_ONLY_PROXY);
    906  } else {
    907    nr_ice_ctx_remove_flags(ctx_, NR_ICE_CTX_FLAGS_ONLY_PROXY);
    908  }
    909 
    910  return NS_OK;
    911 }
    912 
    913 void NrIceCtx::SetCtxFlags(bool default_route_only) {
    914  ASSERT_ON_THREAD(sts_target_);
    915 
    916  if (default_route_only) {
    917    nr_ice_ctx_add_flags(ctx_, NR_ICE_CTX_FLAGS_ONLY_DEFAULT_ADDRS);
    918  } else {
    919    nr_ice_ctx_remove_flags(ctx_, NR_ICE_CTX_FLAGS_ONLY_DEFAULT_ADDRS);
    920  }
    921 }
    922 
    923 nsresult NrIceCtx::StartGathering(bool default_route_only,
    924                                  bool obfuscate_host_addresses) {
    925  ASSERT_ON_THREAD(sts_target_);
    926  MOZ_MTLOG(ML_NOTICE, "NrIceCtx(" << name_ << "): " << __func__);
    927 
    928  if (obfuscate_host_addresses) {
    929    nr_ice_ctx_add_flags(ctx_, NR_ICE_CTX_FLAGS_OBFUSCATE_HOST_ADDRESSES);
    930  }
    931 
    932  SetCtxFlags(default_route_only);
    933 
    934  // This might start gathering for the first time, or again after
    935  // renegotiation, or might do nothing at all if gathering has already
    936  // finished.
    937  int r = nr_ice_gather(ctx_, &NrIceCtx::gather_cb, this);
    938 
    939  if (r && r != R_WOULDBLOCK) {
    940    MOZ_MTLOG(ML_ERROR, "ICE FAILED: Couldn't gather ICE candidates for '"
    941                            << name_ << "', error=" << r);
    942    SignalAllStreamsFailed();
    943    return NS_ERROR_FAILURE;
    944  }
    945 
    946  return NS_OK;
    947 }
    948 
    949 RefPtr<NrIceMediaStream> NrIceCtx::FindStream(nr_ice_media_stream* stream) {
    950  for (auto& idAndStream : streams_) {
    951    if (idAndStream.second->HasStream(stream)) {
    952      return idAndStream.second;
    953    }
    954  }
    955 
    956  return nullptr;
    957 }
    958 
    959 std::vector<std::string> NrIceCtx::GetGlobalAttributes() {
    960  char** attrs = nullptr;
    961  int attrct;
    962  int r;
    963  std::vector<std::string> ret;
    964 
    965  r = nr_ice_get_global_attributes(ctx_, &attrs, &attrct);
    966  if (r) {
    967    MOZ_MTLOG(ML_ERROR,
    968              "Couldn't get ufrag and password for '" << name_ << "'");
    969    return ret;
    970  }
    971 
    972  for (int i = 0; i < attrct; i++) {
    973    ret.push_back(std::string(attrs[i]));
    974    RFREE(attrs[i]);
    975  }
    976  RFREE(attrs);
    977 
    978  return ret;
    979 }
    980 
    981 nsresult NrIceCtx::ParseGlobalAttributes(std::vector<std::string> attrs) {
    982  std::vector<char*> attrs_in;
    983  attrs_in.reserve(attrs.size());
    984  for (auto& attr : attrs) {
    985    attrs_in.push_back(const_cast<char*>(attr.c_str()));
    986  }
    987 
    988  int r = nr_ice_peer_ctx_parse_global_attributes(
    989      peer_, attrs_in.empty() ? nullptr : &attrs_in[0], attrs_in.size());
    990  if (r) {
    991    MOZ_MTLOG(ML_ERROR,
    992              "Couldn't parse global attributes for " << name_ << "'");
    993    return NS_ERROR_FAILURE;
    994  }
    995 
    996  return NS_OK;
    997 }
    998 
    999 bool NrIceCtx::HasStreamsToConnect() const {
   1000  for (auto& idAndStream : streams_) {
   1001    if (idAndStream.second->state() != NrIceMediaStream::ICE_CLOSED) {
   1002      return true;
   1003    }
   1004  }
   1005  return false;
   1006 }
   1007 
   1008 nsresult NrIceCtx::StartChecks() {
   1009  int r;
   1010  MOZ_MTLOG(ML_NOTICE, "NrIceCtx(" << name_ << "): " << __func__);
   1011 
   1012  if (!HasStreamsToConnect()) {
   1013    MOZ_MTLOG(ML_NOTICE, "In StartChecks, nothing to do on " << name_);
   1014    return NS_OK;
   1015  }
   1016 
   1017  r = nr_ice_peer_ctx_pair_candidates(peer_);
   1018  if (r) {
   1019    MOZ_MTLOG(ML_ERROR, "ICE FAILED: Couldn't pair candidates on " << name_);
   1020    SignalAllStreamsFailed();
   1021    return NS_ERROR_FAILURE;
   1022  }
   1023 
   1024  r = nr_ice_peer_ctx_start_checks2(peer_, 1);
   1025  if (r) {
   1026    if (r == R_NOT_FOUND) {
   1027      MOZ_MTLOG(ML_INFO, "Couldn't start peer checks on "
   1028                             << name_ << ", assuming trickle ICE");
   1029    } else {
   1030      MOZ_MTLOG(ML_ERROR,
   1031                "ICE FAILED: Couldn't start peer checks on " << name_);
   1032      SignalAllStreamsFailed();
   1033      return NS_ERROR_FAILURE;
   1034    }
   1035  }
   1036 
   1037  return NS_OK;
   1038 }
   1039 
   1040 void NrIceCtx::gather_cb(NR_SOCKET s, int h, void* arg) {
   1041  MOZ_MTLOG(ML_DEBUG, "gather_cb called");
   1042  // We don't use this; we react to the stream-specific callbacks instead
   1043 }
   1044 
   1045 void NrIceCtx::SignalAllStreamsFailed() {
   1046  for (auto& [id, stream] : streams_) {
   1047    (void)id;
   1048    stream->Failed();
   1049    SignalConnectionStateChange(stream, ICE_CTX_FAILED);
   1050  }
   1051 }
   1052 
   1053 void NrIceCtx::UpdateNetworkState(bool online) {
   1054  MOZ_MTLOG(ML_NOTICE, "NrIceCtx(" << name_ << "): updating network state to "
   1055                                   << (online ? "online" : "offline"));
   1056  if (online) {
   1057    nr_ice_peer_ctx_refresh_consent_all_streams(peer_);
   1058  } else {
   1059    nr_ice_peer_ctx_disconnect_all_streams(peer_);
   1060  }
   1061 }
   1062 
   1063 void NrIceCtx::GenerateObfuscatedAddress(nr_ice_candidate* candidate,
   1064                                         std::string* mdns_address,
   1065                                         std::string* actual_address) {
   1066  if (candidate->type == HOST &&
   1067      (ctx_->flags & NR_ICE_CTX_FLAGS_OBFUSCATE_HOST_ADDRESSES)) {
   1068    char addr[64];
   1069    if (nr_transport_addr_get_addrstring(&candidate->addr, addr,
   1070                                         sizeof(addr))) {
   1071      return;
   1072    }
   1073 
   1074    *actual_address = addr;
   1075 
   1076    const auto& iter = obfuscated_host_addresses_.find(*actual_address);
   1077    if (iter != obfuscated_host_addresses_.end()) {
   1078      *mdns_address = iter->second;
   1079    } else {
   1080      nsresult rv;
   1081      nsCOMPtr<nsIUUIDGenerator> uuidgen =
   1082          do_GetService("@mozilla.org/uuid-generator;1", &rv);
   1083      // If this fails, we'll return a zero UUID rather than something
   1084      // unexpected.
   1085      nsID id = {};
   1086      id.Clear();
   1087      if (NS_SUCCEEDED(rv)) {
   1088        rv = uuidgen->GenerateUUIDInPlace(&id);
   1089        if (NS_FAILED(rv)) {
   1090          id.Clear();
   1091        }
   1092      }
   1093 
   1094      char chars[NSID_LENGTH];
   1095      id.ToProvidedString(chars);
   1096      // The string will look like {64888863-a253-424a-9b30-1ed285d20142},
   1097      // we want to trim off the braces.
   1098      const char* ptr_to_id = chars;
   1099      ++ptr_to_id;
   1100      chars[NSID_LENGTH - 2] = 0;
   1101 
   1102      std::ostringstream o;
   1103      o << ptr_to_id << ".local";
   1104      *mdns_address = o.str();
   1105 
   1106      obfuscated_host_addresses_[*actual_address] = *mdns_address;
   1107    }
   1108    candidate->mdns_addr = r_strdup(mdns_address->c_str());
   1109  }
   1110 }
   1111 
   1112 }  // namespace mozilla
   1113 
   1114 // Reimplement nr_ice_compute_codeword to avoid copyright issues
   1115 void nr_ice_compute_codeword(char* buf, int len, char* codeword) {
   1116  UINT4 c;
   1117 
   1118  r_crc32(buf, len, &c);
   1119  [[maybe_unused]] nsresult nr = mozilla::Base64Encode(
   1120      reinterpret_cast<char*>(&c), 3, mozilla::Span(codeword, 5));
   1121  MOZ_ASSERT(NS_SUCCEEDED(nr));
   1122 }
   1123 
   1124 int nr_socket_local_create(void* obj, nr_transport_addr* addr,
   1125                           nr_socket** sockp) {
   1126  using namespace mozilla;
   1127 
   1128  RefPtr<NrSocketBase> sock;
   1129  int r, _status;
   1130  shared_ptr<NrSocketProxyConfig> config = nullptr;
   1131 
   1132  if (obj) {
   1133    config = static_cast<NrIceCtx*>(obj)->GetProxyConfig();
   1134  }
   1135 
   1136  r = NrSocketBase::CreateSocket(addr, &sock, config);
   1137  if (r) {
   1138    ABORT(r);
   1139  }
   1140 
   1141  r = nr_socket_create_int(static_cast<void*>(sock), sock->vtbl(), sockp);
   1142  if (r) ABORT(r);
   1143 
   1144  _status = 0;
   1145 
   1146  {
   1147    // We will release this reference in destroy(), not exactly the normal
   1148    // ownership model, but it is what it is.
   1149    NrSocketBase* dummy = sock.forget().take();
   1150    (void)dummy;
   1151  }
   1152 
   1153 abort:
   1154  return _status;
   1155 }