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/. */
8 // Original author: ekr@rtfm.com
10 // Some of this code is cut-and-pasted from nICEr. Copyright is:
13 Copyright (c) 2007, Adobe Systems, Incorporated
16 Redistribution and use in source and binary forms, with or without
17 modification, are permitted provided that the following conditions are
20 * Redistributions of source code must retain the above copyright
21 notice, this list of conditions and the following disclaimer.
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.
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.
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.
47 #include "mozilla/UniquePtr.h"
56 #include "nsComponentManagerUtils.h"
58 #include "nsIEventTarget.h"
60 #include "nsComponentManagerUtils.h"
61 #include "nsServiceManagerUtils.h"
62 #include "ScopedNSSTypes.h"
68 #include "async_timer.h"
73 #include "transport_addr.h"
74 #include "nr_crypto.h"
75 #include "nr_socket.h"
76 #include "nr_socket_local.h"
77 #include "stun_client_ctx.h"
79 #include "stun_server_ctx.h"
80 #include "ice_codeword.h"
82 #include "ice_candidate.h"
83 #include "ice_handler.h"
88 #include "nricemediastream.h"
89 #include "nr_socket_prsock.h"
90 #include "nrinterfaceprioritizer.h"
91 #include "rlogringbuffer.h"
95 TimeStamp
nr_socket_short_term_violation_time() {
96 return NrSocketBase::short_term_violation_time();
99 TimeStamp
nr_socket_long_term_violation_time() {
100 return NrSocketBase::long_term_violation_time();
103 MOZ_MTLOG_MODULE("mtransport")
105 const char kNrIceTransportUdp
[] = "udp";
106 const char kNrIceTransportTcp
[] = "tcp";
108 static bool initialized
= false;
110 // Implement NSPR-based crypto algorithms
111 static int nr_crypto_nss_random_bytes(UCHAR
*buf
, int len
) {
112 ScopedPK11SlotInfo
slot(PK11_GetInternalSlot());
116 SECStatus rv
= PK11_GenerateRandomOnSlot(slot
, buf
, len
);
117 if (rv
!= SECSuccess
)
123 static int nr_crypto_nss_hmac(UCHAR
*key
, int keyl
, UCHAR
*buf
, int bufl
,
125 CK_MECHANISM_TYPE mech
= CKM_SHA_1_HMAC
;
126 PK11SlotInfo
*slot
= 0;
127 MOZ_ASSERT(keyl
> 0);
128 SECItem keyi
= { siBuffer
, key
, static_cast<unsigned int>(keyl
)};
129 PK11SymKey
*skey
= 0;
130 PK11Context
*hmac_ctx
= 0;
132 unsigned int hmac_len
;
133 SECItem param
= { siBuffer
, nullptr, 0 };
134 int err
= R_INTERNAL
;
136 slot
= PK11_GetInternalKeySlot();
140 skey
= PK11_ImportSymKey(slot
, mech
, PK11_OriginUnwrap
,
141 CKA_SIGN
, &keyi
, nullptr);
146 hmac_ctx
= PK11_CreateContextBySymKey(mech
, CKA_SIGN
,
151 status
= PK11_DigestBegin(hmac_ctx
);
152 if (status
!= SECSuccess
)
155 status
= PK11_DigestOp(hmac_ctx
, buf
, bufl
);
156 if (status
!= SECSuccess
)
159 status
= PK11_DigestFinal(hmac_ctx
, result
, &hmac_len
, 20);
160 if (status
!= SECSuccess
)
163 MOZ_ASSERT(hmac_len
== 20);
168 if(hmac_ctx
) PK11_DestroyContext(hmac_ctx
, PR_TRUE
);
169 if (skey
) PK11_FreeSymKey(skey
);
170 if (slot
) PK11_FreeSlot(slot
);
175 static int nr_crypto_nss_md5(UCHAR
*buf
, int bufl
, UCHAR
*result
) {
176 int err
= R_INTERNAL
;
179 const SECHashObject
*ho
= HASH_GetHashObject(HASH_AlgMD5
);
184 MOZ_ASSERT(ho
->length
== 16);
186 rv
= HASH_HashBuf(ho
->type
, result
, buf
, bufl
);
187 if (rv
!= SECSuccess
)
195 static nr_ice_crypto_vtbl nr_ice_crypto_nss_vtbl
= {
196 nr_crypto_nss_random_bytes
,
204 nsresult
NrIceStunServer::ToNicerStunStruct(nr_ice_stun_server
*server
,
205 const std::string
&transport
) const {
209 memset(server
, 0, sizeof(nr_ice_stun_server
));
210 if (transport
== kNrIceTransportUdp
) {
211 transport_int
= IPPROTO_UDP
;
212 } else if (transport
== kNrIceTransportTcp
) {
213 transport_int
= IPPROTO_TCP
;
216 return NS_ERROR_FAILURE
;
220 r
= nr_praddr_to_transport_addr(&addr_
, &server
->u
.addr
,
223 return NS_ERROR_FAILURE
;
225 server
->type
=NR_ICE_STUN_SERVER_TYPE_ADDR
;
228 MOZ_ASSERT(sizeof(server
->u
.dnsname
.host
) > host_
.size());
229 PL_strncpyz(server
->u
.dnsname
.host
, host_
.c_str(),
230 sizeof(server
->u
.dnsname
.host
));
231 server
->u
.dnsname
.port
= port_
;
232 server
->type
=NR_ICE_STUN_SERVER_TYPE_DNSNAME
;
239 nsresult
NrIceTurnServer::ToNicerTurnStruct(nr_ice_turn_server
*server
) const {
240 memset(server
, 0, sizeof(nr_ice_turn_server
));
242 nsresult rv
= ToNicerStunStruct(&server
->turn_server
, transport_
);
246 if (transport_
== kNrIceTransportUdp
) {
247 server
->transport
= IPPROTO_UDP
;
248 } else if (transport_
== kNrIceTransportTcp
) {
249 server
->transport
= IPPROTO_TCP
;
252 return NS_ERROR_FAILURE
;
255 if (username_
.empty())
256 return NS_ERROR_INVALID_ARG
;
257 if (password_
.empty())
258 return NS_ERROR_INVALID_ARG
;
260 if (!(server
->username
=r_strdup(username_
.c_str())))
261 return NS_ERROR_OUT_OF_MEMORY
;
263 // TODO(ekr@rtfm.com): handle non-ASCII passwords somehow?
264 // STUN requires they be SASLpreped, but we don't know if
265 // they are at this point.
267 // C++03 23.2.4, Paragraph 1 stipulates that the elements
268 // in std::vector must be contiguous, and can therefore be
269 // used as input to functions expecting C arrays.
270 int r
= r_data_create(&server
->password
,
271 const_cast<UCHAR
*>(&password_
[0]),
274 RFREE(server
->username
);
275 return NS_ERROR_OUT_OF_MEMORY
;
282 int NrIceCtx::select_pair(void *obj
,nr_ice_media_stream
*stream
,
283 int component_id
, nr_ice_cand_pair
**potentials
,
285 MOZ_MTLOG(ML_DEBUG
, "select pair called: potential_ct = "
291 int NrIceCtx::stream_ready(void *obj
, nr_ice_media_stream
*stream
) {
292 MOZ_MTLOG(ML_DEBUG
, "stream_ready called");
295 NrIceCtx
*ctx
= static_cast<NrIceCtx
*>(obj
);
297 RefPtr
<NrIceMediaStream
> s
= ctx
->FindStream(stream
);
299 // Streams which do not exist should never be ready.
307 int NrIceCtx::stream_failed(void *obj
, nr_ice_media_stream
*stream
) {
308 MOZ_MTLOG(ML_DEBUG
, "stream_failed called");
311 NrIceCtx
*ctx
= static_cast<NrIceCtx
*>(obj
);
312 RefPtr
<NrIceMediaStream
> s
= ctx
->FindStream(stream
);
314 // Streams which do not exist should never fail.
317 ctx
->SetConnectionState(ICE_CTX_FAILED
);
318 s
-> SignalFailed(s
);
322 int NrIceCtx::ice_checking(void *obj
, nr_ice_peer_ctx
*pctx
) {
323 MOZ_MTLOG(ML_DEBUG
, "ice_checking called");
326 NrIceCtx
*ctx
= static_cast<NrIceCtx
*>(obj
);
328 ctx
->SetConnectionState(ICE_CTX_CHECKING
);
333 int NrIceCtx::ice_completed(void *obj
, nr_ice_peer_ctx
*pctx
) {
334 MOZ_MTLOG(ML_DEBUG
, "ice_completed called");
337 NrIceCtx
*ctx
= static_cast<NrIceCtx
*>(obj
);
339 // This is called even on failed contexts.
340 if (ctx
->connection_state() != ICE_CTX_FAILED
) {
341 ctx
->SetConnectionState(ICE_CTX_OPEN
);
347 int NrIceCtx::msg_recvd(void *obj
, nr_ice_peer_ctx
*pctx
,
348 nr_ice_media_stream
*stream
, int component_id
,
349 UCHAR
*msg
, int len
) {
351 NrIceCtx
*ctx
= static_cast<NrIceCtx
*>(obj
);
352 RefPtr
<NrIceMediaStream
> s
= ctx
->FindStream(stream
);
354 // Streams which do not exist should never have packets.
357 s
->SignalPacketReceived(s
, component_id
, msg
, len
);
362 void NrIceCtx::trickle_cb(void *arg
, nr_ice_ctx
*ice_ctx
,
363 nr_ice_media_stream
*stream
,
365 nr_ice_candidate
*candidate
) {
367 NrIceCtx
*ctx
= static_cast<NrIceCtx
*>(arg
);
368 RefPtr
<NrIceMediaStream
> s
= ctx
->FindStream(stream
);
370 // Streams which do not exist shouldn't have candidates.
373 // Format the candidate.
374 char candidate_str
[NR_ICE_MAX_ATTRIBUTE_SIZE
];
375 int r
= nr_ice_format_candidate_attribute(candidate
, candidate_str
,
376 sizeof(candidate_str
));
381 MOZ_MTLOG(ML_INFO
, "NrIceCtx(" << ctx
->name_
<< "): trickling candidate "
384 s
->SignalCandidate(s
, candidate_str
);
387 RefPtr
<NrIceCtx
> NrIceCtx::Create(const std::string
& name
,
389 bool set_interface_priorities
,
390 bool allow_loopback
) {
392 RefPtr
<NrIceCtx
> ctx
= new NrIceCtx(name
, offerer
);
394 // Initialize the crypto callbacks and logging stuff
396 NR_reg_init(NR_REG_MODE_LOCAL
);
397 RLogRingBuffer::CreateInstance();
398 nr_crypto_vtbl
= &nr_ice_crypto_nss_vtbl
;
401 // Set the priorites for candidate type preferences.
402 // These numbers come from RFC 5245 S. 4.1.2.2
403 NR_reg_set_uchar((char *)NR_ICE_REG_PREF_TYPE_SRV_RFLX
, 100);
404 NR_reg_set_uchar((char *)NR_ICE_REG_PREF_TYPE_PEER_RFLX
, 110);
405 NR_reg_set_uchar((char *)NR_ICE_REG_PREF_TYPE_HOST
, 126);
406 NR_reg_set_uchar((char *)NR_ICE_REG_PREF_TYPE_RELAYED
, 5);
407 NR_reg_set_uchar((char *)NR_ICE_REG_PREF_TYPE_RELAYED_TCP
, 0);
409 if (set_interface_priorities
) {
410 NR_reg_set_uchar((char *)"ice.pref.interface.rl0", 255);
411 NR_reg_set_uchar((char *)"ice.pref.interface.wi0", 254);
412 NR_reg_set_uchar((char *)"ice.pref.interface.lo0", 253);
413 NR_reg_set_uchar((char *)"ice.pref.interface.en1", 252);
414 NR_reg_set_uchar((char *)"ice.pref.interface.en0", 251);
415 NR_reg_set_uchar((char *)"ice.pref.interface.eth0", 252);
416 NR_reg_set_uchar((char *)"ice.pref.interface.eth1", 251);
417 NR_reg_set_uchar((char *)"ice.pref.interface.eth2", 249);
418 NR_reg_set_uchar((char *)"ice.pref.interface.ppp", 250);
419 NR_reg_set_uchar((char *)"ice.pref.interface.ppp0", 249);
420 NR_reg_set_uchar((char *)"ice.pref.interface.en2", 248);
421 NR_reg_set_uchar((char *)"ice.pref.interface.en3", 247);
422 NR_reg_set_uchar((char *)"ice.pref.interface.em0", 251);
423 NR_reg_set_uchar((char *)"ice.pref.interface.em1", 252);
424 NR_reg_set_uchar((char *)"ice.pref.interface.vmnet0", 240);
425 NR_reg_set_uchar((char *)"ice.pref.interface.vmnet1", 241);
426 NR_reg_set_uchar((char *)"ice.pref.interface.vmnet3", 239);
427 NR_reg_set_uchar((char *)"ice.pref.interface.vmnet4", 238);
428 NR_reg_set_uchar((char *)"ice.pref.interface.vmnet5", 237);
429 NR_reg_set_uchar((char *)"ice.pref.interface.vmnet6", 236);
430 NR_reg_set_uchar((char *)"ice.pref.interface.vmnet7", 235);
431 NR_reg_set_uchar((char *)"ice.pref.interface.vmnet8", 234);
432 NR_reg_set_uchar((char *)"ice.pref.interface.virbr0", 233);
433 NR_reg_set_uchar((char *)"ice.pref.interface.wlan0", 232);
436 NR_reg_set_uint4((char *)"stun.client.maximum_transmits",7);
437 NR_reg_set_uint4((char *)NR_ICE_REG_TRICKLE_GRACE_PERIOD
, 5000);
439 if (allow_loopback
) {
440 NR_reg_set_char((char *)NR_STUN_REG_PREF_ALLOW_LOOPBACK_ADDRS
, 1);
444 // Create the ICE context
447 UINT4 flags
= offerer
? NR_ICE_CTX_FLAGS_OFFERER
:
448 NR_ICE_CTX_FLAGS_ANSWERER
;
449 flags
|= NR_ICE_CTX_FLAGS_AGGRESSIVE_NOMINATION
;
451 r
= nr_ice_ctx_create(const_cast<char *>(name
.c_str()), flags
,
454 MOZ_MTLOG(ML_ERROR
, "Couldn't create ICE ctx for '" << name
<< "'");
458 #ifdef USE_INTERFACE_PRIORITIZER
459 nr_interface_prioritizer
*prioritizer
= CreateInterfacePrioritizer();
461 MOZ_MTLOG(PR_LOG_ERROR
, "Couldn't create interface prioritizer.");
465 r
= nr_ice_ctx_set_interface_prioritizer(ctx
->ctx_
, prioritizer
);
467 MOZ_MTLOG(PR_LOG_ERROR
, "Couldn't set interface prioritizer.");
470 #endif // USE_INTERFACE_PRIORITIZER
472 if (ctx
->generating_trickle()) {
473 r
= nr_ice_ctx_set_trickle_cb(ctx
->ctx_
, &NrIceCtx::trickle_cb
, ctx
);
475 MOZ_MTLOG(ML_ERROR
, "Couldn't set trickle cb for '" << name
<< "'");
480 // Create the handler objects
481 ctx
->ice_handler_vtbl_
= new nr_ice_handler_vtbl();
482 ctx
->ice_handler_vtbl_
->select_pair
= &NrIceCtx::select_pair
;
483 ctx
->ice_handler_vtbl_
->stream_ready
= &NrIceCtx::stream_ready
;
484 ctx
->ice_handler_vtbl_
->stream_failed
= &NrIceCtx::stream_failed
;
485 ctx
->ice_handler_vtbl_
->ice_completed
= &NrIceCtx::ice_completed
;
486 ctx
->ice_handler_vtbl_
->msg_recvd
= &NrIceCtx::msg_recvd
;
487 ctx
->ice_handler_vtbl_
->ice_checking
= &NrIceCtx::ice_checking
;
489 ctx
->ice_handler_
= new nr_ice_handler();
490 ctx
->ice_handler_
->vtbl
= ctx
->ice_handler_vtbl_
;
491 ctx
->ice_handler_
->obj
= ctx
;
493 // Create the peer ctx. Because we do not support parallel forking, we
494 // only have one peer ctx.
495 std::string peer_name
= name
+ ":default";
496 r
= nr_ice_peer_ctx_create(ctx
->ctx_
, ctx
->ice_handler_
,
497 const_cast<char *>(peer_name
.c_str()),
500 MOZ_MTLOG(ML_ERROR
, "Couldn't create ICE peer ctx for '" << name
<< "'");
505 ctx
->sts_target_
= do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID
, &rv
);
507 if (!NS_SUCCEEDED(rv
))
513 // ONLY USE THIS FOR TESTING. Will cause totally unpredictable and possibly very
514 // bad effects if ICE is still live.
515 void NrIceCtx::internal_DeinitializeGlobal() {
516 NR_reg_del((char *)"stun");
517 NR_reg_del((char *)"ice");
518 RLogRingBuffer::DestroyInstance();
519 nr_crypto_vtbl
= nullptr;
523 NrIceCtx::~NrIceCtx() {
524 MOZ_MTLOG(ML_DEBUG
, "Destroying ICE ctx '" << name_
<<"'");
525 nr_ice_peer_ctx_destroy(&peer_
);
526 nr_ice_ctx_destroy(&ctx_
);
527 delete ice_handler_vtbl_
;
531 RefPtr
<NrIceMediaStream
>
532 NrIceCtx::CreateStream(const std::string
& name
, int components
) {
533 RefPtr
<NrIceMediaStream
> stream
=
534 NrIceMediaStream::Create(this, name
, components
);
537 streams_
.push_back(stream
);
543 std::string
NrIceCtx::ufrag() const {
547 std::string
NrIceCtx::pwd() const {
551 void NrIceCtx::destroy_peer_ctx() {
552 nr_ice_peer_ctx_destroy(&peer_
);
555 nsresult
NrIceCtx::SetControlling(Controlling controlling
) {
556 peer_
->controlling
= (controlling
== ICE_CONTROLLING
)? 1 : 0;
558 MOZ_MTLOG(ML_DEBUG
, "ICE ctx " << name_
<< " setting controlling to" <<
563 NrIceCtx::Controlling
NrIceCtx::GetControlling() {
564 return (peer_
->controlling
) ? ICE_CONTROLLING
: ICE_CONTROLLED
;
567 nsresult
NrIceCtx::SetStunServers(const std::vector
<NrIceStunServer
>&
569 if (stun_servers
.empty())
572 auto servers
= MakeUnique
<nr_ice_stun_server
[]>(stun_servers
.size());
574 for (size_t i
=0; i
< stun_servers
.size(); ++i
) {
575 nsresult rv
= stun_servers
[i
].ToNicerStunStruct(&servers
[i
]);
577 MOZ_MTLOG(ML_ERROR
, "Couldn't set STUN server for '" << name_
<< "'");
578 return NS_ERROR_FAILURE
;
582 int r
= nr_ice_ctx_set_stun_servers(ctx_
, servers
.get(), stun_servers
.size());
584 MOZ_MTLOG(ML_ERROR
, "Couldn't set STUN server for '" << name_
<< "'");
585 return NS_ERROR_FAILURE
;
591 // TODO(ekr@rtfm.com): This is just SetStunServers with s/Stun/Turn
592 // Could we do a template or something?
593 nsresult
NrIceCtx::SetTurnServers(const std::vector
<NrIceTurnServer
>&
595 if (turn_servers
.empty())
598 auto servers
= MakeUnique
<nr_ice_turn_server
[]>(turn_servers
.size());
600 for (size_t i
=0; i
< turn_servers
.size(); ++i
) {
601 nsresult rv
= turn_servers
[i
].ToNicerTurnStruct(&servers
[i
]);
603 MOZ_MTLOG(ML_ERROR
, "Couldn't set TURN server for '" << name_
<< "'");
604 return NS_ERROR_FAILURE
;
608 int r
= nr_ice_ctx_set_turn_servers(ctx_
, servers
.get(), turn_servers
.size());
610 MOZ_MTLOG(ML_ERROR
, "Couldn't set TURN server for '" << name_
<< "'");
611 return NS_ERROR_FAILURE
;
614 // TODO(ekr@rtfm.com): This leaks the username/password. Need to free that.
619 nsresult
NrIceCtx::SetResolver(nr_resolver
*resolver
) {
620 int r
= nr_ice_ctx_set_resolver(ctx_
, resolver
);
623 MOZ_MTLOG(ML_ERROR
, "Couldn't set resolver for '" << name_
<< "'");
624 return NS_ERROR_FAILURE
;
630 nsresult
NrIceCtx::StartGathering() {
631 MOZ_ASSERT(ctx_
->state
== ICE_CTX_INIT
);
632 if (ctx_
->state
!= ICE_CTX_INIT
) {
633 MOZ_MTLOG(ML_ERROR
, "ICE ctx in the wrong state for gathering: '"
635 SetConnectionState(ICE_CTX_FAILED
);
636 return NS_ERROR_FAILURE
;
639 int r
= nr_ice_initialize(ctx_
, &NrIceCtx::initialized_cb
,
642 if (r
&& r
!= R_WOULDBLOCK
) {
643 MOZ_MTLOG(ML_ERROR
, "Couldn't gather ICE candidates for '"
645 SetConnectionState(ICE_CTX_FAILED
);
646 return NS_ERROR_FAILURE
;
649 SetGatheringState(ICE_CTX_GATHER_STARTED
);
654 RefPtr
<NrIceMediaStream
> NrIceCtx::FindStream(
655 nr_ice_media_stream
*stream
) {
656 for (size_t i
=0; i
<streams_
.size(); ++i
) {
657 if (streams_
[i
]->stream() == stream
) {
665 std::vector
<std::string
> NrIceCtx::GetGlobalAttributes() {
669 std::vector
<std::string
> ret
;
671 r
= nr_ice_get_global_attributes(ctx_
, &attrs
, &attrct
);
673 MOZ_MTLOG(ML_ERROR
, "Couldn't get ufrag and password for '"
678 for (int i
=0; i
<attrct
; i
++) {
679 ret
.push_back(std::string(attrs
[i
]));
687 nsresult
NrIceCtx::ParseGlobalAttributes(std::vector
<std::string
> attrs
) {
688 std::vector
<char *> attrs_in
;
690 for (size_t i
=0; i
<attrs
.size(); ++i
) {
691 attrs_in
.push_back(const_cast<char *>(attrs
[i
].c_str()));
694 int r
= nr_ice_peer_ctx_parse_global_attributes(peer_
,
696 &attrs_in
[0] : nullptr,
699 MOZ_MTLOG(ML_ERROR
, "Couldn't parse global attributes for "
701 return NS_ERROR_FAILURE
;
707 nsresult
NrIceCtx::StartChecks() {
710 r
=nr_ice_peer_ctx_pair_candidates(peer_
);
712 MOZ_MTLOG(ML_ERROR
, "Couldn't pair candidates on "
714 SetConnectionState(ICE_CTX_FAILED
);
715 return NS_ERROR_FAILURE
;
718 r
= nr_ice_peer_ctx_start_checks2(peer_
,1);
720 if (r
== R_NOT_FOUND
) {
721 MOZ_MTLOG(ML_ERROR
, "Couldn't start peer checks on "
722 << name_
<< "' assuming trickle ICE");
724 MOZ_MTLOG(ML_ERROR
, "Couldn't start peer checks on "
726 SetConnectionState(ICE_CTX_FAILED
);
727 return NS_ERROR_FAILURE
;
735 void NrIceCtx::initialized_cb(NR_SOCKET s
, int h
, void *arg
) {
736 NrIceCtx
*ctx
= static_cast<NrIceCtx
*>(arg
);
738 ctx
->SetGatheringState(ICE_CTX_GATHER_COMPLETE
);
741 nsresult
NrIceCtx::Finalize() {
742 int r
= nr_ice_ctx_finalize(ctx_
, peer_
);
745 MOZ_MTLOG(ML_ERROR
, "Couldn't finalize "
747 return NS_ERROR_FAILURE
;
753 void NrIceCtx::SetConnectionState(ConnectionState state
) {
754 if (state
== connection_state_
)
757 MOZ_MTLOG(ML_INFO
, "NrIceCtx(" << name_
<< "): state " <<
758 connection_state_
<< "->" << state
);
759 connection_state_
= state
;
761 if (connection_state_
== ICE_CTX_FAILED
) {
762 MOZ_MTLOG(ML_INFO
, "NrIceCtx(" << name_
<< "): dumping r_log ringbuffer... ");
763 std::deque
<std::string
> logs
;
764 RLogRingBuffer::GetInstance()->GetAny(0, &logs
);
765 for (auto l
= logs
.begin(); l
!= logs
.end(); ++l
) {
766 MOZ_MTLOG(ML_INFO
, *l
);
770 SignalConnectionStateChange(this, state
);
773 void NrIceCtx::SetGatheringState(GatheringState state
) {
774 if (state
== gathering_state_
)
777 MOZ_MTLOG(ML_DEBUG
, "NrIceCtx(" << name_
<< "): gathering state " <<
778 gathering_state_
<< "->" << state
);
779 gathering_state_
= state
;
781 SignalGatheringStateChange(this, state
);
786 // Reimplement nr_ice_compute_codeword to avoid copyright issues
787 void nr_ice_compute_codeword(char *buf
, int len
,char *codeword
) {
792 PL_Base64Encode(reinterpret_cast<char*>(&c
), 3, codeword
);