Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/media/mtransport/nricectx.cpp
Line
Count
Source (jump to first uncovered line)
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
8
// Original author: ekr@rtfm.com
9
10
// Some of this code is cut-and-pasted from nICEr. Copyright is:
11
12
/*
13
Copyright (c) 2007, Adobe Systems, Incorporated
14
All rights reserved.
15
16
Redistribution and use in source and binary forms, with or without
17
modification, are permitted provided that the following conditions are
18
met:
19
20
* Redistributions of source code must retain the above copyright
21
  notice, this list of conditions and the following disclaimer.
22
23
* Redistributions in binary form must reproduce the above copyright
24
  notice, this list of conditions and the following disclaimer in the
25
  documentation and/or other materials provided with the distribution.
26
27
* Neither the name of Adobe Systems, Network Resonance nor the names of its
28
  contributors may be used to endorse or promote products derived from
29
  this software without specific prior written permission.
30
31
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
34
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
36
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
37
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
38
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
39
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
40
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
41
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42
*/
43
44
#include <string>
45
#include <vector>
46
47
#include "mozilla/Telemetry.h"
48
#include "mozilla/UniquePtr.h"
49
#include "mozilla/Unused.h"
50
51
#include "logging.h"
52
#include "nspr.h"
53
#include "nss.h"
54
#include "pk11pub.h"
55
#include "plbase64.h"
56
57
#include "nsCOMPtr.h"
58
#include "nsComponentManagerUtils.h"
59
#include "nsError.h"
60
#include "nsIEventTarget.h"
61
#include "nsNetCID.h"
62
#include "nsComponentManagerUtils.h"
63
#include "nsServiceManagerUtils.h"
64
#include "ScopedNSSTypes.h"
65
#include "runnable_utils.h"
66
#include "nsIPrefService.h"
67
#include "nsIPrefBranch.h"
68
69
// nICEr includes
70
extern "C" {
71
#include "nr_api.h"
72
#include "registry.h"
73
#include "async_timer.h"
74
#include "r_crc32.h"
75
#include "r_memory.h"
76
#include "ice_reg.h"
77
#include "ice_util.h"
78
#include "transport_addr.h"
79
#include "nr_crypto.h"
80
#include "nr_socket.h"
81
#include "nr_socket_local.h"
82
#include "nr_proxy_tunnel.h"
83
#include "stun_client_ctx.h"
84
#include "stun_reg.h"
85
#include "stun_server_ctx.h"
86
#include "stun_util.h"
87
#include "ice_codeword.h"
88
#include "ice_ctx.h"
89
#include "ice_candidate.h"
90
#include "ice_handler.h"
91
}
92
93
// Local includes
94
#include "nricectx.h"
95
#include "nricemediastream.h"
96
#include "nr_socket_prsock.h"
97
#include "nrinterfaceprioritizer.h"
98
#include "rlogconnector.h"
99
#include "test_nr_socket.h"
100
101
namespace mozilla {
102
103
0
TimeStamp nr_socket_short_term_violation_time() {
104
0
  return NrSocketBase::short_term_violation_time();
105
0
}
106
107
0
TimeStamp nr_socket_long_term_violation_time() {
108
0
  return NrSocketBase::long_term_violation_time();
109
0
}
110
111
MOZ_MTLOG_MODULE("mtransport")
112
113
const char kNrIceTransportUdp[] = "udp";
114
const char kNrIceTransportTcp[] = "tcp";
115
const char kNrIceTransportTls[] = "tls";
116
117
static bool initialized = false;
118
119
// Implement NSPR-based crypto algorithms
120
0
static int nr_crypto_nss_random_bytes(UCHAR *buf, size_t len) {
121
0
  UniquePK11SlotInfo slot(PK11_GetInternalSlot());
122
0
  if (!slot)
123
0
    return R_INTERNAL;
124
0
125
0
  SECStatus rv = PK11_GenerateRandomOnSlot(slot.get(), buf, len);
126
0
  if (rv != SECSuccess)
127
0
    return R_INTERNAL;
128
0
129
0
  return 0;
130
0
}
131
132
static int nr_crypto_nss_hmac(UCHAR *key, size_t keyl, UCHAR *buf, size_t bufl,
133
0
                              UCHAR *result) {
134
0
  CK_MECHANISM_TYPE mech = CKM_SHA_1_HMAC;
135
0
  PK11SlotInfo *slot = nullptr;
136
0
  MOZ_ASSERT(keyl > 0);
137
0
  SECItem keyi = { siBuffer, key, static_cast<unsigned int>(keyl)};
138
0
  PK11SymKey *skey = nullptr;
139
0
  PK11Context *hmac_ctx = nullptr;
140
0
  SECStatus status;
141
0
  unsigned int hmac_len;
142
0
  SECItem param = { siBuffer, nullptr, 0 };
143
0
  int err = R_INTERNAL;
144
0
145
0
  slot = PK11_GetInternalKeySlot();
146
0
  if (!slot)
147
0
    goto abort;
148
0
149
0
  skey = PK11_ImportSymKey(slot, mech, PK11_OriginUnwrap,
150
0
                          CKA_SIGN, &keyi, nullptr);
151
0
  if (!skey)
152
0
    goto abort;
153
0
154
0
155
0
  hmac_ctx = PK11_CreateContextBySymKey(mech, CKA_SIGN,
156
0
                                        skey, &param);
157
0
  if (!hmac_ctx)
158
0
    goto abort;
159
0
160
0
  status = PK11_DigestBegin(hmac_ctx);
161
0
  if (status != SECSuccess)
162
0
    goto abort;
163
0
164
0
  status = PK11_DigestOp(hmac_ctx, buf, bufl);
165
0
  if (status != SECSuccess)
166
0
    goto abort;
167
0
168
0
  status = PK11_DigestFinal(hmac_ctx, result, &hmac_len, 20);
169
0
  if (status != SECSuccess)
170
0
    goto abort;
171
0
172
0
  MOZ_ASSERT(hmac_len == 20);
173
0
174
0
  err = 0;
175
0
176
0
 abort:
177
0
  if(hmac_ctx) PK11_DestroyContext(hmac_ctx, PR_TRUE);
178
0
  if (skey) PK11_FreeSymKey(skey);
179
0
  if (slot) PK11_FreeSlot(slot);
180
0
181
0
  return err;
182
0
}
183
184
0
static int nr_crypto_nss_md5(UCHAR *buf, size_t bufl, UCHAR *result) {
185
0
  int err = R_INTERNAL;
186
0
  SECStatus rv;
187
0
188
0
  const SECHashObject *ho = HASH_GetHashObject(HASH_AlgMD5);
189
0
  MOZ_ASSERT(ho);
190
0
  if (!ho)
191
0
    goto abort;
192
0
193
0
  MOZ_ASSERT(ho->length == 16);
194
0
195
0
  rv = HASH_HashBuf(ho->type, result, buf, bufl);
196
0
  if (rv != SECSuccess)
197
0
    goto abort;
198
0
199
0
  err = 0;
200
0
abort:
201
0
  return err;
202
0
}
203
204
static nr_ice_crypto_vtbl nr_ice_crypto_nss_vtbl = {
205
  nr_crypto_nss_random_bytes,
206
  nr_crypto_nss_hmac,
207
  nr_crypto_nss_md5
208
};
209
210
0
nsresult NrIceStunServer::ToNicerStunStruct(nr_ice_stun_server *server) const {
211
0
  int r;
212
0
213
0
  memset(server, 0, sizeof(nr_ice_stun_server));
214
0
  if (transport_ == kNrIceTransportUdp) {
215
0
    server->transport = IPPROTO_UDP;
216
0
  } else if (transport_ == kNrIceTransportTcp) {
217
0
    server->transport = IPPROTO_TCP;
218
0
  } else if (transport_ == kNrIceTransportTls) {
219
0
    server->transport = IPPROTO_TCP;
220
0
    if (has_addr_) {
221
0
      // Refuse to try TLS without an FQDN
222
0
      return NS_ERROR_INVALID_ARG;
223
0
    }
224
0
    server->tls = 1;
225
0
  } else {
226
0
    MOZ_MTLOG(ML_ERROR, "Unsupported STUN server transport: " << transport_);
227
0
    return NS_ERROR_FAILURE;
228
0
  }
229
0
230
0
  if (has_addr_) {
231
0
    r = nr_praddr_to_transport_addr(&addr_, &server->u.addr,
232
0
                                    server->transport, 0);
233
0
    if (r) {
234
0
      return NS_ERROR_FAILURE;
235
0
    }
236
0
    server->type=NR_ICE_STUN_SERVER_TYPE_ADDR;
237
0
  }
238
0
  else {
239
0
    MOZ_ASSERT(sizeof(server->u.dnsname.host) > host_.size());
240
0
    PL_strncpyz(server->u.dnsname.host, host_.c_str(),
241
0
                sizeof(server->u.dnsname.host));
242
0
    server->u.dnsname.port = port_;
243
0
    server->type=NR_ICE_STUN_SERVER_TYPE_DNSNAME;
244
0
  }
245
0
246
0
  return NS_OK;
247
0
}
248
249
250
0
nsresult NrIceTurnServer::ToNicerTurnStruct(nr_ice_turn_server *server) const {
251
0
  memset(server, 0, sizeof(nr_ice_turn_server));
252
0
253
0
  nsresult rv = ToNicerStunStruct(&server->turn_server);
254
0
  if (NS_FAILED(rv))
255
0
    return rv;
256
0
257
0
  if (!(server->username=r_strdup(username_.c_str())))
258
0
    return NS_ERROR_OUT_OF_MEMORY;
259
0
260
0
  // TODO(ekr@rtfm.com): handle non-ASCII passwords somehow?
261
0
  // STUN requires they be SASLpreped, but we don't know if
262
0
  // they are at this point.
263
0
264
0
  // C++03 23.2.4, Paragraph 1 stipulates that the elements
265
0
  // in std::vector must be contiguous, and can therefore be
266
0
  // used as input to functions expecting C arrays.
267
0
  int r = r_data_create(&server->password,
268
0
                        const_cast<UCHAR *>(&password_[0]),
269
0
                        password_.size());
270
0
  if (r) {
271
0
    RFREE(server->username);
272
0
    return NS_ERROR_OUT_OF_MEMORY;
273
0
  }
274
0
275
0
  return NS_OK;
276
0
}
277
278
NrIceCtx::NrIceCtx(const std::string& name, Policy policy)
279
  : connection_state_(ICE_CTX_INIT),
280
    gathering_state_(ICE_CTX_GATHER_INIT),
281
    name_(name),
282
    offerer_(false),
283
    ice_controlling_set_(false),
284
    streams_(),
285
    ctx_(nullptr),
286
    peer_(nullptr),
287
    ice_handler_vtbl_(nullptr),
288
    ice_handler_(nullptr),
289
    trickle_(true),
290
    policy_(policy),
291
0
    nat_ (nullptr) {
292
0
}
293
294
/* static */
295
RefPtr<NrIceCtx>
296
NrIceCtx::Create(const std::string& name,
297
                 bool allow_loopback,
298
                 bool tcp_enabled,
299
                 bool allow_link_local,
300
                 Policy policy)
301
0
{
302
0
  // InitializeGlobals only executes once
303
0
  NrIceCtx::InitializeGlobals(allow_loopback, tcp_enabled, allow_link_local);
304
0
305
0
  RefPtr<NrIceCtx> ctx = new NrIceCtx(name, policy);
306
0
307
0
  if (!ctx->Initialize()) {
308
0
    return nullptr;
309
0
  }
310
0
311
0
  return ctx;
312
0
}
313
314
RefPtr<NrIceMediaStream>
315
NrIceCtx::CreateStream(const std::string& id,
316
                       const std::string& name,
317
                       int components)
318
0
{
319
0
  if (streams_.count(id)) {
320
0
    MOZ_ASSERT(false);
321
0
    return nullptr;
322
0
  }
323
0
324
0
  RefPtr<NrIceMediaStream> stream =
325
0
    new NrIceMediaStream(this, id, name, components);
326
0
  streams_[id] = stream;
327
0
  return stream;
328
0
}
329
330
void
331
0
NrIceCtx::DestroyStream(const std::string& id) {
332
0
  auto it = streams_.find(id);
333
0
  if (it != streams_.end()) {
334
0
    auto preexisting_stream = it->second;
335
0
    streams_.erase(it);
336
0
    preexisting_stream->Close();
337
0
  }
338
0
}
339
340
// Handler callbacks
341
int NrIceCtx::select_pair(void *obj,nr_ice_media_stream *stream,
342
                   int component_id, nr_ice_cand_pair **potentials,
343
0
                   int potential_ct) {
344
0
  MOZ_MTLOG(ML_DEBUG, "select pair called: potential_ct = "
345
0
            << potential_ct);
346
0
  MOZ_ASSERT(stream->local_stream);
347
0
  MOZ_ASSERT(!stream->local_stream->obsolete);
348
0
349
0
  return 0;
350
0
}
351
352
0
int NrIceCtx::stream_ready(void *obj, nr_ice_media_stream *stream) {
353
0
  MOZ_MTLOG(ML_DEBUG, "stream_ready called");
354
0
  MOZ_ASSERT(!stream->local_stream);
355
0
  MOZ_ASSERT(!stream->obsolete);
356
0
357
0
  // Get the ICE ctx.
358
0
  NrIceCtx *ctx = static_cast<NrIceCtx *>(obj);
359
0
360
0
  RefPtr<NrIceMediaStream> s = ctx->FindStream(stream);
361
0
362
0
  // Streams which do not exist should never be ready.
363
0
  MOZ_ASSERT(s);
364
0
365
0
  s->Ready();
366
0
367
0
  return 0;
368
0
}
369
370
0
int NrIceCtx::stream_failed(void *obj, nr_ice_media_stream *stream) {
371
0
  MOZ_MTLOG(ML_DEBUG, "stream_failed called");
372
0
  MOZ_ASSERT(!stream->local_stream);
373
0
  MOZ_ASSERT(!stream->obsolete);
374
0
375
0
  // Get the ICE ctx
376
0
  NrIceCtx *ctx = static_cast<NrIceCtx *>(obj);
377
0
  RefPtr<NrIceMediaStream> s = ctx->FindStream(stream);
378
0
379
0
  // Streams which do not exist should never fail.
380
0
  MOZ_ASSERT(s);
381
0
382
0
  ctx->SetConnectionState(ICE_CTX_FAILED);
383
0
  s -> Failed();
384
0
  return 0;
385
0
}
386
387
0
int NrIceCtx::ice_checking(void *obj, nr_ice_peer_ctx *pctx) {
388
0
  MOZ_MTLOG(ML_DEBUG, "ice_checking called");
389
0
390
0
  // Get the ICE ctx
391
0
  NrIceCtx *ctx = static_cast<NrIceCtx *>(obj);
392
0
393
0
  ctx->SetConnectionState(ICE_CTX_CHECKING);
394
0
395
0
  return 0;
396
0
}
397
398
0
int NrIceCtx::ice_connected(void *obj, nr_ice_peer_ctx *pctx) {
399
0
  MOZ_MTLOG(ML_DEBUG, "ice_connected called");
400
0
401
0
  // Get the ICE ctx
402
0
  NrIceCtx *ctx = static_cast<NrIceCtx *>(obj);
403
0
404
0
  // This is called even on failed contexts.
405
0
  if (ctx->connection_state() != ICE_CTX_FAILED) {
406
0
    ctx->SetConnectionState(ICE_CTX_CONNECTED);
407
0
  }
408
0
409
0
  return 0;
410
0
}
411
412
0
int NrIceCtx::ice_disconnected(void *obj, nr_ice_peer_ctx *pctx) {
413
0
  MOZ_MTLOG(ML_DEBUG, "ice_disconnected called");
414
0
415
0
  // Get the ICE ctx
416
0
  NrIceCtx *ctx = static_cast<NrIceCtx *>(obj);
417
0
418
0
  ctx->SetConnectionState(ICE_CTX_DISCONNECTED);
419
0
420
0
  return 0;
421
0
}
422
423
int NrIceCtx::msg_recvd(void *obj, nr_ice_peer_ctx *pctx,
424
                        nr_ice_media_stream *stream, int component_id,
425
0
                        UCHAR *msg, int len) {
426
0
  // Get the ICE ctx
427
0
  NrIceCtx *ctx = static_cast<NrIceCtx *>(obj);
428
0
  RefPtr<NrIceMediaStream> s = ctx->FindStream(stream);
429
0
430
0
  // Streams which do not exist should never have packets.
431
0
  MOZ_ASSERT(s);
432
0
433
0
  s->SignalPacketReceived(s, component_id, msg, len);
434
0
435
0
  return 0;
436
0
}
437
438
void NrIceCtx::trickle_cb(void *arg, nr_ice_ctx *ice_ctx,
439
                          nr_ice_media_stream *stream,
440
                          int component_id,
441
0
                          nr_ice_candidate *candidate) {
442
0
  MOZ_ASSERT(!stream->obsolete);
443
0
  // Get the ICE ctx
444
0
  NrIceCtx *ctx = static_cast<NrIceCtx *>(arg);
445
0
  RefPtr<NrIceMediaStream> s = ctx->FindStream(stream);
446
0
447
0
  if (!s) {
448
0
    // This stream has been removed because it is inactive
449
0
    return;
450
0
  }
451
0
452
0
  // Format the candidate.
453
0
  char candidate_str[NR_ICE_MAX_ATTRIBUTE_SIZE];
454
0
  int r = nr_ice_format_candidate_attribute(candidate, candidate_str,
455
0
                                            sizeof(candidate_str));
456
0
  MOZ_ASSERT(!r);
457
0
  if (r)
458
0
    return;
459
0
460
0
  MOZ_MTLOG(ML_INFO, "NrIceCtx(" << ctx->name_ << "): trickling candidate "
461
0
            << candidate_str);
462
0
463
0
  s->SignalCandidate(s, candidate_str);
464
0
}
465
466
467
void
468
NrIceCtx::InitializeGlobals(bool allow_loopback,
469
                            bool tcp_enabled,
470
0
                            bool allow_link_local) {
471
0
  // Initialize the crypto callbacks and logging stuff
472
0
  if (!initialized) {
473
0
    NR_reg_init(NR_REG_MODE_LOCAL);
474
0
    nr_crypto_vtbl = &nr_ice_crypto_nss_vtbl;
475
0
    initialized = true;
476
0
477
0
    // Set the priorites for candidate type preferences.
478
0
    // These numbers come from RFC 5245 S. 4.1.2.2
479
0
    NR_reg_set_uchar((char *)NR_ICE_REG_PREF_TYPE_SRV_RFLX, 100);
480
0
    NR_reg_set_uchar((char *)NR_ICE_REG_PREF_TYPE_PEER_RFLX, 110);
481
0
    NR_reg_set_uchar((char *)NR_ICE_REG_PREF_TYPE_HOST, 126);
482
0
    NR_reg_set_uchar((char *)NR_ICE_REG_PREF_TYPE_RELAYED, 5);
483
0
    NR_reg_set_uchar((char *)NR_ICE_REG_PREF_TYPE_SRV_RFLX_TCP, 99);
484
0
    NR_reg_set_uchar((char *)NR_ICE_REG_PREF_TYPE_PEER_RFLX_TCP, 109);
485
0
    NR_reg_set_uchar((char *)NR_ICE_REG_PREF_TYPE_HOST_TCP, 125);
486
0
    NR_reg_set_uchar((char *)NR_ICE_REG_PREF_TYPE_RELAYED_TCP, 0);
487
0
488
0
    int32_t stun_client_maximum_transmits = 7;
489
0
    int32_t ice_trickle_grace_period = 5000;
490
0
    int32_t ice_tcp_so_sock_count = 3;
491
0
    int32_t ice_tcp_listen_backlog = 10;
492
0
    nsAutoCString force_net_interface;
493
0
    nsresult res;
494
0
    nsCOMPtr<nsIPrefService> prefs =
495
0
      do_GetService("@mozilla.org/preferences-service;1", &res);
496
0
497
0
    if (NS_SUCCEEDED(res)) {
498
0
      nsCOMPtr<nsIPrefBranch> branch = do_QueryInterface(prefs);
499
0
      if (branch) {
500
0
        branch->GetIntPref(
501
0
            "media.peerconnection.ice.stun_client_maximum_transmits",
502
0
            &stun_client_maximum_transmits);
503
0
        branch->GetIntPref(
504
0
            "media.peerconnection.ice.trickle_grace_period",
505
0
            &ice_trickle_grace_period);
506
0
        branch->GetIntPref(
507
0
            "media.peerconnection.ice.tcp_so_sock_count",
508
0
            &ice_tcp_so_sock_count);
509
0
        branch->GetIntPref(
510
0
            "media.peerconnection.ice.tcp_listen_backlog",
511
0
            &ice_tcp_listen_backlog);
512
0
        branch->GetCharPref(
513
0
            "media.peerconnection.ice.force_interface",
514
0
            force_net_interface);
515
0
      }
516
0
    }
517
0
518
0
    NR_reg_set_uint4((char *)"stun.client.maximum_transmits",
519
0
                     stun_client_maximum_transmits);
520
0
    NR_reg_set_uint4((char *)NR_ICE_REG_TRICKLE_GRACE_PERIOD,
521
0
                     ice_trickle_grace_period);
522
0
    NR_reg_set_int4((char *)NR_ICE_REG_ICE_TCP_SO_SOCK_COUNT,
523
0
                     ice_tcp_so_sock_count);
524
0
    NR_reg_set_int4((char *)NR_ICE_REG_ICE_TCP_LISTEN_BACKLOG,
525
0
                     ice_tcp_listen_backlog);
526
0
527
0
    NR_reg_set_char((char *)NR_ICE_REG_ICE_TCP_DISABLE, !tcp_enabled);
528
0
529
0
    if (allow_loopback) {
530
0
      NR_reg_set_char((char *)NR_STUN_REG_PREF_ALLOW_LOOPBACK_ADDRS, 1);
531
0
    }
532
0
533
0
    if (allow_link_local) {
534
0
      NR_reg_set_char((char *)NR_STUN_REG_PREF_ALLOW_LINK_LOCAL_ADDRS, 1);
535
0
    }
536
0
    if (force_net_interface.Length() > 0) {
537
0
      // Stupid cast.... but needed
538
0
      const nsCString& flat = PromiseFlatCString(static_cast<nsACString&>(force_net_interface));
539
0
      NR_reg_set_string((char *)NR_ICE_REG_PREF_FORCE_INTERFACE_NAME, const_cast<char*>(flat.get()));
540
0
    }
541
0
  }
542
0
}
543
544
0
#define MAXADDRS 100 // mirrors setting in ice_ctx.c
545
546
/* static */
547
nsTArray<NrIceStunAddr>
548
NrIceCtx::GetStunAddrs()
549
0
{
550
0
  nsTArray<NrIceStunAddr> addrs;
551
0
552
0
  nr_local_addr local_addrs[MAXADDRS];
553
0
  int addr_ct=0;
554
0
555
0
  // most likely running on parent process and need crypto vtbl
556
0
  // initialized on Windows (Linux and OSX don't seem to care)
557
0
  if (!initialized) {
558
0
    nr_crypto_vtbl = &nr_ice_crypto_nss_vtbl;
559
0
  }
560
0
561
0
  MOZ_MTLOG(ML_INFO, "NrIceCtx static call to find local stun addresses");
562
0
  if (nr_stun_find_local_addresses(local_addrs, MAXADDRS, &addr_ct)) {
563
0
    MOZ_MTLOG(ML_INFO, "Error finding local stun addresses");
564
0
  } else {
565
0
    for(int i=0; i<addr_ct; ++i) {
566
0
      NrIceStunAddr addr(&local_addrs[i]);
567
0
      addrs.AppendElement(addr);
568
0
    }
569
0
  }
570
0
571
0
  return addrs;
572
0
}
573
574
void
575
NrIceCtx::SetStunAddrs(const nsTArray<NrIceStunAddr>& addrs)
576
0
{
577
0
  nr_local_addr* local_addrs;
578
0
  local_addrs = new nr_local_addr[addrs.Length()];
579
0
580
0
  for(size_t i=0; i<addrs.Length(); ++i) {
581
0
    nr_local_addr_copy(&local_addrs[i],
582
0
                       const_cast<nr_local_addr*>(&addrs[i].localAddr()));
583
0
  }
584
0
  nr_ice_set_local_addresses(ctx_, local_addrs, addrs.Length());
585
0
586
0
  delete[] local_addrs;
587
0
}
588
589
bool
590
NrIceCtx::Initialize()
591
0
{
592
0
  // Create the ICE context
593
0
  int r;
594
0
595
0
  UINT4 flags = NR_ICE_CTX_FLAGS_AGGRESSIVE_NOMINATION;
596
0
  switch (policy_) {
597
0
    case ICE_POLICY_RELAY:
598
0
      flags |= NR_ICE_CTX_FLAGS_RELAY_ONLY;
599
0
      break;
600
0
    case ICE_POLICY_NO_HOST:
601
0
      flags |= NR_ICE_CTX_FLAGS_HIDE_HOST_CANDIDATES;
602
0
      break;
603
0
    case ICE_POLICY_ALL:
604
0
      break;
605
0
  }
606
0
607
0
  r = nr_ice_ctx_create(const_cast<char *>(name_.c_str()), flags, &ctx_);
608
0
609
0
  if (r) {
610
0
    MOZ_MTLOG(ML_ERROR, "Couldn't create ICE ctx for '" << name_ << "'");
611
0
    return false;
612
0
  }
613
0
614
0
  nr_interface_prioritizer *prioritizer = CreateInterfacePrioritizer();
615
0
  if (!prioritizer) {
616
0
    MOZ_MTLOG(LogLevel::Error, "Couldn't create interface prioritizer.");
617
0
    return false;
618
0
  }
619
0
620
0
  r = nr_ice_ctx_set_interface_prioritizer(ctx_, prioritizer);
621
0
  if (r) {
622
0
    MOZ_MTLOG(LogLevel::Error, "Couldn't set interface prioritizer.");
623
0
    return false;
624
0
  }
625
0
626
0
  if (generating_trickle()) {
627
0
    r = nr_ice_ctx_set_trickle_cb(ctx_, &NrIceCtx::trickle_cb, this);
628
0
    if (r) {
629
0
      MOZ_MTLOG(ML_ERROR, "Couldn't set trickle cb for '" << name_ << "'");
630
0
      return false;
631
0
    }
632
0
  }
633
0
634
0
  nsAutoCString mapping_type;
635
0
  nsAutoCString filtering_type;
636
0
  bool block_udp = false;
637
0
  bool block_tcp = false;
638
0
639
0
  nsresult rv;
640
0
  nsCOMPtr<nsIPrefService> pref_service =
641
0
    do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
642
0
643
0
  if (NS_SUCCEEDED(rv)) {
644
0
    nsCOMPtr<nsIPrefBranch> pref_branch;
645
0
    rv = pref_service->GetBranch(nullptr, getter_AddRefs(pref_branch));
646
0
    if (NS_SUCCEEDED(rv)) {
647
0
      Unused << pref_branch->GetCharPref(
648
0
          "media.peerconnection.nat_simulator.mapping_type",
649
0
          mapping_type);
650
0
      Unused << pref_branch->GetCharPref(
651
0
          "media.peerconnection.nat_simulator.filtering_type",
652
0
          filtering_type);
653
0
      Unused << pref_branch->GetBoolPref(
654
0
          "media.peerconnection.nat_simulator.block_udp",
655
0
          &block_udp);
656
0
      Unused << pref_branch->GetBoolPref(
657
0
          "media.peerconnection.nat_simulator.block_tcp",
658
0
          &block_tcp);
659
0
    }
660
0
  }
661
0
662
0
  if (!mapping_type.IsEmpty() && !filtering_type.IsEmpty()) {
663
0
    MOZ_MTLOG(ML_DEBUG, "NAT filtering type: " << filtering_type.get());
664
0
    MOZ_MTLOG(ML_DEBUG, "NAT mapping type: " << mapping_type.get());
665
0
    TestNat* test_nat = new TestNat;
666
0
    test_nat->filtering_type_ = TestNat::ToNatBehavior(filtering_type.get());
667
0
    test_nat->mapping_type_ = TestNat::ToNatBehavior(mapping_type.get());
668
0
    test_nat->block_udp_ = block_udp;
669
0
    test_nat->block_tcp_ = block_tcp;
670
0
    test_nat->enabled_ = true;
671
0
    SetNat(test_nat);
672
0
  }
673
0
674
0
  // Create the handler objects
675
0
  ice_handler_vtbl_ = new nr_ice_handler_vtbl();
676
0
  ice_handler_vtbl_->select_pair = &NrIceCtx::select_pair;
677
0
  ice_handler_vtbl_->stream_ready = &NrIceCtx::stream_ready;
678
0
  ice_handler_vtbl_->stream_failed = &NrIceCtx::stream_failed;
679
0
  ice_handler_vtbl_->ice_connected = &NrIceCtx::ice_connected;
680
0
  ice_handler_vtbl_->msg_recvd = &NrIceCtx::msg_recvd;
681
0
  ice_handler_vtbl_->ice_checking = &NrIceCtx::ice_checking;
682
0
  ice_handler_vtbl_->ice_disconnected = &NrIceCtx::ice_disconnected;
683
0
684
0
  ice_handler_ = new nr_ice_handler();
685
0
  ice_handler_->vtbl = ice_handler_vtbl_;
686
0
  ice_handler_->obj = this;
687
0
688
0
  // Create the peer ctx. Because we do not support parallel forking, we
689
0
  // only have one peer ctx.
690
0
  std::string peer_name = name_ + ":default";
691
0
  r = nr_ice_peer_ctx_create(ctx_, ice_handler_,
692
0
                             const_cast<char *>(peer_name.c_str()),
693
0
                             &peer_);
694
0
  if (r) {
695
0
    MOZ_MTLOG(ML_ERROR, "Couldn't create ICE peer ctx for '" << name_ << "'");
696
0
    return false;
697
0
  }
698
0
699
0
  sts_target_ = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
700
0
701
0
  if (!NS_SUCCEEDED(rv))
702
0
    return false;
703
0
704
0
  return true;
705
0
}
706
707
0
int NrIceCtx::SetNat(const RefPtr<TestNat>& aNat) {
708
0
  nat_ = aNat;
709
0
  nr_socket_factory *fac;
710
0
  int r = nat_->create_socket_factory(&fac);
711
0
  if (r) {
712
0
    return r;
713
0
  }
714
0
  nr_ice_ctx_set_socket_factory(ctx_, fac);
715
0
  return 0;
716
0
}
717
718
// ONLY USE THIS FOR TESTING. Will cause totally unpredictable and possibly very
719
// bad effects if ICE is still live.
720
0
void NrIceCtx::internal_DeinitializeGlobal() {
721
0
  NR_reg_del((char *)"stun");
722
0
  NR_reg_del((char *)"ice");
723
0
  RLogConnector::DestroyInstance();
724
0
  nr_crypto_vtbl = nullptr;
725
0
  initialized = false;
726
0
}
727
728
0
void NrIceCtx::internal_SetTimerAccelarator(int divider) {
729
0
  ctx_->test_timer_divider = divider;
730
0
}
731
732
0
void NrIceCtx::AccumulateStats(const NrIceStats& stats) {
733
0
  nr_accumulate_count(&(ctx_->stats.stun_retransmits),
734
0
                      stats.stun_retransmits);
735
0
  nr_accumulate_count(&(ctx_->stats.turn_401s), stats.turn_401s);
736
0
  nr_accumulate_count(&(ctx_->stats.turn_403s), stats.turn_403s);
737
0
  nr_accumulate_count(&(ctx_->stats.turn_438s), stats.turn_438s);
738
0
}
739
740
0
NrIceStats NrIceCtx::Destroy() {
741
0
  // designed to be called more than once so if stats are desired, this can be
742
0
  // called just prior to the destructor
743
0
  MOZ_MTLOG(ML_DEBUG, "Destroying ICE ctx '" << name_ <<"'");
744
0
  for (auto& idAndStream : streams_) {
745
0
    idAndStream.second->Close();
746
0
  }
747
0
748
0
  NrIceStats stats;
749
0
  if (ctx_) {
750
0
    stats.stun_retransmits = ctx_->stats.stun_retransmits;
751
0
    stats.turn_401s = ctx_->stats.turn_401s;
752
0
    stats.turn_403s = ctx_->stats.turn_403s;
753
0
    stats.turn_438s = ctx_->stats.turn_438s;
754
0
  }
755
0
756
0
  if (!ice_start_time_.IsNull()) {
757
0
    TimeDuration time_delta = TimeStamp::Now() - ice_start_time_;
758
0
    ice_start_time_ = TimeStamp(); // null out
759
0
760
0
    if (offerer_) {
761
0
      Telemetry::Accumulate(
762
0
          Telemetry::WEBRTC_ICE_OFFERER_ABORT_TIME,
763
0
          time_delta.ToMilliseconds());
764
0
    } else {
765
0
      Telemetry::Accumulate(
766
0
          Telemetry::WEBRTC_ICE_ANSWERER_ABORT_TIME,
767
0
          time_delta.ToMilliseconds());
768
0
    }
769
0
  }
770
0
771
0
  if (peer_) {
772
0
    nr_ice_peer_ctx_destroy(&peer_);
773
0
  }
774
0
  if (ctx_) {
775
0
    nr_ice_ctx_destroy(&ctx_);
776
0
  }
777
0
778
0
  delete ice_handler_vtbl_;
779
0
  delete ice_handler_;
780
0
781
0
  ice_handler_vtbl_ = nullptr;
782
0
  ice_handler_ = nullptr;
783
0
  streams_.clear();
784
0
785
0
  return stats;
786
0
}
787
788
0
NrIceCtx::~NrIceCtx() {
789
0
  Destroy();
790
0
}
791
792
0
void NrIceCtx::destroy_peer_ctx() {
793
0
  nr_ice_peer_ctx_destroy(&peer_);
794
0
}
795
796
0
nsresult NrIceCtx::SetControlling(Controlling controlling) {
797
0
  if (!ice_controlling_set_) {
798
0
    peer_->controlling = (controlling == ICE_CONTROLLING)? 1 : 0;
799
0
    ice_controlling_set_ = true;
800
0
801
0
    MOZ_MTLOG(ML_DEBUG, "ICE ctx " << name_ << " setting controlling to" <<
802
0
              controlling);
803
0
  }
804
0
  return NS_OK;
805
0
}
806
807
0
NrIceCtx::Controlling NrIceCtx::GetControlling() {
808
0
  return (peer_->controlling) ? ICE_CONTROLLING : ICE_CONTROLLED;
809
0
}
810
811
0
nsresult NrIceCtx::SetPolicy(Policy policy) {
812
0
  policy_ = policy;
813
0
  return NS_OK;
814
0
}
815
816
nsresult NrIceCtx::SetStunServers(const std::vector<NrIceStunServer>&
817
0
                                  stun_servers) {
818
0
  if (stun_servers.empty())
819
0
    return NS_OK;
820
0
821
0
  auto servers = MakeUnique<nr_ice_stun_server[]>(stun_servers.size());
822
0
823
0
  for (size_t i=0; i < stun_servers.size(); ++i) {
824
0
    nsresult rv = stun_servers[i].ToNicerStunStruct(&servers[i]);
825
0
    if (NS_FAILED(rv)) {
826
0
      MOZ_MTLOG(ML_ERROR, "Couldn't set STUN server for '" << name_ << "'");
827
0
      return NS_ERROR_FAILURE;
828
0
    }
829
0
  }
830
0
831
0
  int r = nr_ice_ctx_set_stun_servers(ctx_, servers.get(), stun_servers.size());
832
0
  if (r) {
833
0
    MOZ_MTLOG(ML_ERROR, "Couldn't set STUN server for '" << name_ << "'");
834
0
    return NS_ERROR_FAILURE;
835
0
  }
836
0
837
0
  return NS_OK;
838
0
}
839
840
// TODO(ekr@rtfm.com): This is just SetStunServers with s/Stun/Turn
841
// Could we do a template or something?
842
nsresult NrIceCtx::SetTurnServers(const std::vector<NrIceTurnServer>&
843
0
                                  turn_servers) {
844
0
  if (turn_servers.empty())
845
0
    return NS_OK;
846
0
847
0
  auto servers = MakeUnique<nr_ice_turn_server[]>(turn_servers.size());
848
0
849
0
  for (size_t i=0; i < turn_servers.size(); ++i) {
850
0
    nsresult rv = turn_servers[i].ToNicerTurnStruct(&servers[i]);
851
0
    if (NS_FAILED(rv)) {
852
0
      MOZ_MTLOG(ML_ERROR, "Couldn't set TURN server for '" << name_ << "'");
853
0
      return NS_ERROR_FAILURE;
854
0
    }
855
0
  }
856
0
857
0
  int r = nr_ice_ctx_set_turn_servers(ctx_, servers.get(), turn_servers.size());
858
0
  if (r) {
859
0
    MOZ_MTLOG(ML_ERROR, "Couldn't set TURN server for '" << name_ << "'");
860
0
    return NS_ERROR_FAILURE;
861
0
  }
862
0
863
0
  // TODO(ekr@rtfm.com): This leaks the username/password. Need to free that.
864
0
865
0
  return NS_OK;
866
0
}
867
868
0
nsresult NrIceCtx::SetResolver(nr_resolver *resolver) {
869
0
  int r = nr_ice_ctx_set_resolver(ctx_, resolver);
870
0
871
0
  if (r) {
872
0
    MOZ_MTLOG(ML_ERROR, "Couldn't set resolver for '" << name_ << "'");
873
0
    return NS_ERROR_FAILURE;
874
0
  }
875
0
876
0
  return NS_OK;
877
0
}
878
879
0
nsresult NrIceCtx::SetProxyServer(const NrIceProxyServer& proxy_server) {
880
0
  int r,_status;
881
0
  nr_proxy_tunnel_config *config = nullptr;
882
0
  nr_socket_wrapper_factory *wrapper = nullptr;
883
0
884
0
  if ((r = nr_proxy_tunnel_config_create(&config))) {
885
0
    ABORT(r);
886
0
  }
887
0
888
0
  if ((r = nr_proxy_tunnel_config_set_proxy(config,
889
0
                                            proxy_server.host().c_str(),
890
0
                                            proxy_server.port()))) {
891
0
    ABORT(r);
892
0
  }
893
0
894
0
  if ((r = nr_proxy_tunnel_config_set_resolver(config, ctx_->resolver))) {
895
0
    ABORT(r);
896
0
  }
897
0
898
0
  if ((r = nr_socket_wrapper_factory_proxy_tunnel_create(config, &wrapper))) {
899
0
    MOZ_MTLOG(LogLevel::Error, "Couldn't create proxy tunnel wrapper.");
900
0
    ABORT(r);
901
0
  }
902
0
903
0
  // nr_ice_ctx will own the wrapper after this call
904
0
  if ((r = nr_ice_ctx_set_turn_tcp_socket_wrapper(ctx_, wrapper))) {
905
0
    MOZ_MTLOG(ML_ERROR, "Couldn't set proxy for '" << name_ << "': " << r);
906
0
    ABORT(r);
907
0
  }
908
0
909
0
  _status = 0;
910
0
abort:
911
0
  nr_proxy_tunnel_config_destroy(&config);
912
0
  if (_status) {
913
0
    nr_socket_wrapper_factory_destroy(&wrapper);
914
0
    return NS_ERROR_FAILURE;
915
0
  }
916
0
  return NS_OK;
917
0
}
918
919
0
void NrIceCtx::SetCtxFlags(bool default_route_only, bool proxy_only) {
920
0
  ASSERT_ON_THREAD(sts_target_);
921
0
922
0
  if (default_route_only) {
923
0
    nr_ice_ctx_add_flags(ctx_, NR_ICE_CTX_FLAGS_ONLY_DEFAULT_ADDRS);
924
0
  } else {
925
0
    nr_ice_ctx_remove_flags(ctx_, NR_ICE_CTX_FLAGS_ONLY_DEFAULT_ADDRS);
926
0
  }
927
0
928
0
  if (proxy_only) {
929
0
    nr_ice_ctx_add_flags(ctx_, NR_ICE_CTX_FLAGS_ONLY_PROXY);
930
0
  } else {
931
0
    nr_ice_ctx_remove_flags(ctx_, NR_ICE_CTX_FLAGS_ONLY_PROXY);
932
0
  }
933
0
}
934
935
0
nsresult NrIceCtx::StartGathering(bool default_route_only, bool proxy_only) {
936
0
  ASSERT_ON_THREAD(sts_target_);
937
0
  SetGatheringState(ICE_CTX_GATHER_STARTED);
938
0
939
0
  SetCtxFlags(default_route_only, proxy_only);
940
0
941
0
  TimeStamp start = TimeStamp::Now();
942
0
  // This might start gathering for the first time, or again after
943
0
  // renegotiation, or might do nothing at all if gathering has already
944
0
  // finished.
945
0
  int r = nr_ice_gather(ctx_, &NrIceCtx::gather_cb, this);
946
0
947
0
948
0
  if (!r) {
949
0
    SetGatheringState(ICE_CTX_GATHER_COMPLETE);
950
0
    Telemetry::AccumulateTimeDelta(
951
0
        Telemetry::WEBRTC_ICE_NR_ICE_GATHER_TIME_IMMEDIATE_SUCCESS, start);
952
0
  } else if (r != R_WOULDBLOCK) {
953
0
    MOZ_MTLOG(ML_ERROR, "ICE FAILED: Couldn't gather ICE candidates for '"
954
0
                        << name_ << "', error=" << r);
955
0
    SetConnectionState(ICE_CTX_FAILED);
956
0
    Telemetry::AccumulateTimeDelta(
957
0
        Telemetry::WEBRTC_ICE_NR_ICE_GATHER_TIME_IMMEDIATE_FAILURE, start);
958
0
    return NS_ERROR_FAILURE;
959
0
  } else {
960
0
    Telemetry::AccumulateTimeDelta(
961
0
        Telemetry::WEBRTC_ICE_NR_ICE_GATHER_TIME, start);
962
0
  }
963
0
964
0
  return NS_OK;
965
0
}
966
967
0
RefPtr<NrIceMediaStream> NrIceCtx::FindStream(nr_ice_media_stream *stream) {
968
0
  for (auto& idAndStream : streams_) {
969
0
    if (idAndStream.second->HasStream(stream)) {
970
0
      return idAndStream.second;
971
0
    }
972
0
  }
973
0
974
0
  return nullptr;
975
0
}
976
977
0
std::vector<std::string> NrIceCtx::GetGlobalAttributes() {
978
0
  char **attrs = nullptr;
979
0
  int attrct;
980
0
  int r;
981
0
  std::vector<std::string> ret;
982
0
983
0
  r = nr_ice_get_global_attributes(ctx_, &attrs, &attrct);
984
0
  if (r) {
985
0
    MOZ_MTLOG(ML_ERROR, "Couldn't get ufrag and password for '"
986
0
              << name_ << "'");
987
0
    return ret;
988
0
  }
989
0
990
0
  for (int i=0; i<attrct; i++) {
991
0
    ret.push_back(std::string(attrs[i]));
992
0
    RFREE(attrs[i]);
993
0
  }
994
0
  RFREE(attrs);
995
0
996
0
  return ret;
997
0
}
998
999
0
nsresult NrIceCtx::ParseGlobalAttributes(std::vector<std::string> attrs) {
1000
0
  std::vector<char *> attrs_in;
1001
0
  attrs_in.reserve(attrs.size());
1002
0
  for (auto& attr : attrs) {
1003
0
    attrs_in.push_back(const_cast<char *>(attr.c_str()));
1004
0
  }
1005
0
1006
0
  int r = nr_ice_peer_ctx_parse_global_attributes(peer_,
1007
0
                                                  attrs_in.empty() ?
1008
0
                                                  nullptr : &attrs_in[0],
1009
0
                                                  attrs_in.size());
1010
0
  if (r) {
1011
0
    MOZ_MTLOG(ML_ERROR, "Couldn't parse global attributes for "
1012
0
              << name_ << "'");
1013
0
    return NS_ERROR_FAILURE;
1014
0
  }
1015
0
1016
0
  return NS_OK;
1017
0
}
1018
1019
0
bool NrIceCtx::HasStreamsToConnect() const {
1020
0
  for (auto& idAndStream : streams_) {
1021
0
    if (idAndStream.second->state() != NrIceMediaStream::ICE_CLOSED) {
1022
0
      return true;
1023
0
    }
1024
0
  }
1025
0
  return false;
1026
0
}
1027
1028
0
nsresult NrIceCtx::StartChecks(bool offerer) {
1029
0
  int r;
1030
0
  if (!HasStreamsToConnect()) {
1031
0
    // Nothing to do
1032
0
    return NS_OK;
1033
0
  }
1034
0
1035
0
  offerer_ = offerer;
1036
0
  ice_start_time_ = TimeStamp::Now();
1037
0
1038
0
  r=nr_ice_peer_ctx_pair_candidates(peer_);
1039
0
  if (r) {
1040
0
    MOZ_MTLOG(ML_ERROR, "ICE FAILED: Couldn't pair candidates on " << name_);
1041
0
    SetConnectionState(ICE_CTX_FAILED);
1042
0
    return NS_ERROR_FAILURE;
1043
0
  }
1044
0
1045
0
  r = nr_ice_peer_ctx_start_checks2(peer_,1);
1046
0
  if (r) {
1047
0
    if (r == R_NOT_FOUND) {
1048
0
      MOZ_MTLOG(ML_INFO, "Couldn't start peer checks on "
1049
0
                << name_ << ", assuming trickle ICE");
1050
0
    } else {
1051
0
      MOZ_MTLOG(ML_ERROR, "ICE FAILED: Couldn't start peer checks on "
1052
0
                << name_);
1053
0
      SetConnectionState(ICE_CTX_FAILED);
1054
0
      return NS_ERROR_FAILURE;
1055
0
    }
1056
0
  }
1057
0
1058
0
  return NS_OK;
1059
0
}
1060
1061
1062
0
void NrIceCtx::gather_cb(NR_SOCKET s, int h, void *arg) {
1063
0
  NrIceCtx *ctx = static_cast<NrIceCtx *>(arg);
1064
0
1065
0
  ctx->SetGatheringState(ICE_CTX_GATHER_COMPLETE);
1066
0
}
1067
1068
0
nsresult NrIceCtx::Finalize() {
1069
0
  int r = nr_ice_ctx_finalize(ctx_, peer_);
1070
0
1071
0
  if (r) {
1072
0
    MOZ_MTLOG(ML_ERROR, "Couldn't finalize "
1073
0
         << name_ << "'");
1074
0
    return NS_ERROR_FAILURE;
1075
0
  }
1076
0
1077
0
  return NS_OK;
1078
0
}
1079
1080
0
void NrIceCtx::UpdateNetworkState(bool online) {
1081
0
  MOZ_MTLOG(ML_INFO, "NrIceCtx(" << name_ << "): updating network state to " <<
1082
0
            (online ? "online" : "offline"));
1083
0
  if (online) {
1084
0
    nr_ice_peer_ctx_refresh_consent_all_streams(peer_);
1085
0
  } else {
1086
0
    nr_ice_peer_ctx_disconnect_all_streams(peer_);
1087
0
  }
1088
0
}
1089
1090
0
void NrIceCtx::SetConnectionState(ConnectionState state) {
1091
0
  if (state == connection_state_)
1092
0
    return;
1093
0
1094
0
  if (!ice_start_time_.IsNull() && (state > ICE_CTX_CHECKING)) {
1095
0
    TimeDuration time_delta = TimeStamp::Now() - ice_start_time_;
1096
0
    ice_start_time_ = TimeStamp();
1097
0
1098
0
    switch (state) {
1099
0
      case ICE_CTX_INIT:
1100
0
      case ICE_CTX_CHECKING:
1101
0
        MOZ_CRASH();
1102
0
        break;
1103
0
      case ICE_CTX_CONNECTED:
1104
0
      case ICE_CTX_COMPLETED:
1105
0
        if (offerer_) {
1106
0
          Telemetry::Accumulate(
1107
0
              Telemetry::WEBRTC_ICE_OFFERER_SUCCESS_TIME,
1108
0
              time_delta.ToMilliseconds());
1109
0
        } else {
1110
0
          Telemetry::Accumulate(
1111
0
              Telemetry::WEBRTC_ICE_ANSWERER_SUCCESS_TIME,
1112
0
              time_delta.ToMilliseconds());
1113
0
        }
1114
0
        break;
1115
0
      case ICE_CTX_FAILED:
1116
0
        if (offerer_) {
1117
0
          Telemetry::Accumulate(
1118
0
              Telemetry::WEBRTC_ICE_OFFERER_FAILURE_TIME,
1119
0
              time_delta.ToMilliseconds());
1120
0
        } else {
1121
0
          Telemetry::Accumulate(
1122
0
              Telemetry::WEBRTC_ICE_ANSWERER_FAILURE_TIME,
1123
0
              time_delta.ToMilliseconds());
1124
0
        }
1125
0
        break;
1126
0
      case ICE_CTX_DISCONNECTED:
1127
0
        // We get this every time an ICE disconnect gets reported.
1128
0
        // Do we want a Telemetry probe counting how often this happens?
1129
0
        break;
1130
0
      case ICE_CTX_CLOSED:
1131
0
        // This doesn't seem to be used...
1132
0
        break;
1133
0
    }
1134
0
  }
1135
0
1136
0
  MOZ_MTLOG(ML_INFO, "NrIceCtx(" << name_ << "): state " <<
1137
0
            connection_state_ << "->" << state);
1138
0
  connection_state_ = state;
1139
0
1140
0
  if (connection_state_ == ICE_CTX_FAILED) {
1141
0
    MOZ_MTLOG(ML_INFO, "NrIceCtx(" << name_ << "): dumping r_log ringbuffer... ");
1142
0
    std::deque<std::string> logs;
1143
0
    RLogConnector::GetInstance()->GetAny(0, &logs);
1144
0
    for (auto& log : logs) {
1145
0
      MOZ_MTLOG(ML_INFO, log);
1146
0
    }
1147
0
  }
1148
0
1149
0
  SignalConnectionStateChange(this, state);
1150
0
}
1151
1152
0
void NrIceCtx::SetGatheringState(GatheringState state) {
1153
0
  if (state == gathering_state_)
1154
0
    return;
1155
0
1156
0
  MOZ_MTLOG(ML_DEBUG, "NrIceCtx(" << name_ << "): gathering state " <<
1157
0
            gathering_state_ << "->" << state);
1158
0
  gathering_state_ = state;
1159
0
1160
0
  SignalGatheringStateChange(this, state);
1161
0
}
1162
1163
}  // close namespace
1164
1165
// Reimplement nr_ice_compute_codeword to avoid copyright issues
1166
0
void nr_ice_compute_codeword(char *buf, int len,char *codeword) {
1167
0
    UINT4 c;
1168
0
1169
0
    r_crc32(buf,len,&c);
1170
0
1171
0
    PL_Base64Encode(reinterpret_cast<char*>(&c), 3, codeword);
1172
0
    codeword[4] = 0;
1173
0
}