Bumping manifests a=b2g-bump
[gecko.git] / media / mtransport / nricectx.cpp
blob331c26b50c79126f54d35d9a8ed4cebd2dca298a
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
14 All rights reserved.
16 Redistribution and use in source and binary forms, with or without
17 modification, are permitted provided that the following conditions are
18 met:
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.
44 #include <string>
45 #include <vector>
47 #include "mozilla/UniquePtr.h"
49 #include "logging.h"
50 #include "nspr.h"
51 #include "nss.h"
52 #include "pk11pub.h"
53 #include "plbase64.h"
55 #include "nsCOMPtr.h"
56 #include "nsComponentManagerUtils.h"
57 #include "nsError.h"
58 #include "nsIEventTarget.h"
59 #include "nsNetCID.h"
60 #include "nsComponentManagerUtils.h"
61 #include "nsServiceManagerUtils.h"
62 #include "ScopedNSSTypes.h"
64 // nICEr includes
65 extern "C" {
66 #include "nr_api.h"
67 #include "registry.h"
68 #include "async_timer.h"
69 #include "r_crc32.h"
70 #include "r_memory.h"
71 #include "ice_reg.h"
72 #include "ice_util.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"
78 #include "stun_reg.h"
79 #include "stun_server_ctx.h"
80 #include "ice_codeword.h"
81 #include "ice_ctx.h"
82 #include "ice_candidate.h"
83 #include "ice_handler.h"
86 // Local includes
87 #include "nricectx.h"
88 #include "nricemediastream.h"
89 #include "nr_socket_prsock.h"
90 #include "nrinterfaceprioritizer.h"
91 #include "rlogringbuffer.h"
93 namespace mozilla {
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());
113 if (!slot)
114 return R_INTERNAL;
116 SECStatus rv = PK11_GenerateRandomOnSlot(slot, buf, len);
117 if (rv != SECSuccess)
118 return R_INTERNAL;
120 return 0;
123 static int nr_crypto_nss_hmac(UCHAR *key, int keyl, UCHAR *buf, int bufl,
124 UCHAR *result) {
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;
131 SECStatus status;
132 unsigned int hmac_len;
133 SECItem param = { siBuffer, nullptr, 0 };
134 int err = R_INTERNAL;
136 slot = PK11_GetInternalKeySlot();
137 if (!slot)
138 goto abort;
140 skey = PK11_ImportSymKey(slot, mech, PK11_OriginUnwrap,
141 CKA_SIGN, &keyi, nullptr);
142 if (!skey)
143 goto abort;
146 hmac_ctx = PK11_CreateContextBySymKey(mech, CKA_SIGN,
147 skey, &param);
148 if (!hmac_ctx)
149 goto abort;
151 status = PK11_DigestBegin(hmac_ctx);
152 if (status != SECSuccess)
153 goto abort;
155 status = PK11_DigestOp(hmac_ctx, buf, bufl);
156 if (status != SECSuccess)
157 goto abort;
159 status = PK11_DigestFinal(hmac_ctx, result, &hmac_len, 20);
160 if (status != SECSuccess)
161 goto abort;
163 MOZ_ASSERT(hmac_len == 20);
165 err = 0;
167 abort:
168 if(hmac_ctx) PK11_DestroyContext(hmac_ctx, PR_TRUE);
169 if (skey) PK11_FreeSymKey(skey);
170 if (slot) PK11_FreeSlot(slot);
172 return err;
175 static int nr_crypto_nss_md5(UCHAR *buf, int bufl, UCHAR *result) {
176 int err = R_INTERNAL;
177 SECStatus rv;
179 const SECHashObject *ho = HASH_GetHashObject(HASH_AlgMD5);
180 MOZ_ASSERT(ho);
181 if (!ho)
182 goto abort;
184 MOZ_ASSERT(ho->length == 16);
186 rv = HASH_HashBuf(ho->type, result, buf, bufl);
187 if (rv != SECSuccess)
188 goto abort;
190 err = 0;
191 abort:
192 return err;
195 static nr_ice_crypto_vtbl nr_ice_crypto_nss_vtbl = {
196 nr_crypto_nss_random_bytes,
197 nr_crypto_nss_hmac,
198 nr_crypto_nss_md5
204 nsresult NrIceStunServer::ToNicerStunStruct(nr_ice_stun_server *server,
205 const std::string &transport) const {
206 int r;
207 int transport_int;
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;
214 } else {
215 MOZ_ASSERT(false);
216 return NS_ERROR_FAILURE;
219 if (has_addr_) {
220 r = nr_praddr_to_transport_addr(&addr_, &server->u.addr,
221 transport_int, 0);
222 if (r) {
223 return NS_ERROR_FAILURE;
225 server->type=NR_ICE_STUN_SERVER_TYPE_ADDR;
227 else {
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;
235 return NS_OK;
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_);
243 if (NS_FAILED(rv))
244 return rv;
246 if (transport_ == kNrIceTransportUdp) {
247 server->transport = IPPROTO_UDP;
248 } else if (transport_ == kNrIceTransportTcp) {
249 server->transport = IPPROTO_TCP;
250 } else {
251 MOZ_ASSERT(false);
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]),
272 password_.size());
273 if (r) {
274 RFREE(server->username);
275 return NS_ERROR_OUT_OF_MEMORY;
278 return NS_OK;
281 // Handler callbacks
282 int NrIceCtx::select_pair(void *obj,nr_ice_media_stream *stream,
283 int component_id, nr_ice_cand_pair **potentials,
284 int potential_ct) {
285 MOZ_MTLOG(ML_DEBUG, "select pair called: potential_ct = "
286 << potential_ct);
288 return 0;
291 int NrIceCtx::stream_ready(void *obj, nr_ice_media_stream *stream) {
292 MOZ_MTLOG(ML_DEBUG, "stream_ready called");
294 // Get the ICE ctx.
295 NrIceCtx *ctx = static_cast<NrIceCtx *>(obj);
297 RefPtr<NrIceMediaStream> s = ctx->FindStream(stream);
299 // Streams which do not exist should never be ready.
300 MOZ_ASSERT(s);
302 s->Ready();
304 return 0;
307 int NrIceCtx::stream_failed(void *obj, nr_ice_media_stream *stream) {
308 MOZ_MTLOG(ML_DEBUG, "stream_failed called");
310 // Get the ICE ctx
311 NrIceCtx *ctx = static_cast<NrIceCtx *>(obj);
312 RefPtr<NrIceMediaStream> s = ctx->FindStream(stream);
314 // Streams which do not exist should never fail.
315 MOZ_ASSERT(s);
317 ctx->SetConnectionState(ICE_CTX_FAILED);
318 s -> SignalFailed(s);
319 return 0;
322 int NrIceCtx::ice_checking(void *obj, nr_ice_peer_ctx *pctx) {
323 MOZ_MTLOG(ML_DEBUG, "ice_checking called");
325 // Get the ICE ctx
326 NrIceCtx *ctx = static_cast<NrIceCtx *>(obj);
328 ctx->SetConnectionState(ICE_CTX_CHECKING);
330 return 0;
333 int NrIceCtx::ice_completed(void *obj, nr_ice_peer_ctx *pctx) {
334 MOZ_MTLOG(ML_DEBUG, "ice_completed called");
336 // Get the ICE ctx
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);
344 return 0;
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) {
350 // Get the ICE ctx
351 NrIceCtx *ctx = static_cast<NrIceCtx *>(obj);
352 RefPtr<NrIceMediaStream> s = ctx->FindStream(stream);
354 // Streams which do not exist should never have packets.
355 MOZ_ASSERT(s);
357 s->SignalPacketReceived(s, component_id, msg, len);
359 return 0;
362 void NrIceCtx::trickle_cb(void *arg, nr_ice_ctx *ice_ctx,
363 nr_ice_media_stream *stream,
364 int component_id,
365 nr_ice_candidate *candidate) {
366 // Get the ICE ctx
367 NrIceCtx *ctx = static_cast<NrIceCtx *>(arg);
368 RefPtr<NrIceMediaStream> s = ctx->FindStream(stream);
370 // Streams which do not exist shouldn't have candidates.
371 MOZ_ASSERT(s);
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));
377 MOZ_ASSERT(!r);
378 if (r)
379 return;
381 MOZ_MTLOG(ML_INFO, "NrIceCtx(" << ctx->name_ << "): trickling candidate "
382 << candidate_str);
384 s->SignalCandidate(s, candidate_str);
387 RefPtr<NrIceCtx> NrIceCtx::Create(const std::string& name,
388 bool offerer,
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
395 if (!initialized) {
396 NR_reg_init(NR_REG_MODE_LOCAL);
397 RLogRingBuffer::CreateInstance();
398 nr_crypto_vtbl = &nr_ice_crypto_nss_vtbl;
399 initialized = true;
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
445 int r;
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,
452 &ctx->ctx_);
453 if (r) {
454 MOZ_MTLOG(ML_ERROR, "Couldn't create ICE ctx for '" << name << "'");
455 return nullptr;
458 #ifdef USE_INTERFACE_PRIORITIZER
459 nr_interface_prioritizer *prioritizer = CreateInterfacePrioritizer();
460 if (!prioritizer) {
461 MOZ_MTLOG(PR_LOG_ERROR, "Couldn't create interface prioritizer.");
462 return nullptr;
465 r = nr_ice_ctx_set_interface_prioritizer(ctx->ctx_, prioritizer);
466 if (r) {
467 MOZ_MTLOG(PR_LOG_ERROR, "Couldn't set interface prioritizer.");
468 return nullptr;
470 #endif // USE_INTERFACE_PRIORITIZER
472 if (ctx->generating_trickle()) {
473 r = nr_ice_ctx_set_trickle_cb(ctx->ctx_, &NrIceCtx::trickle_cb, ctx);
474 if (r) {
475 MOZ_MTLOG(ML_ERROR, "Couldn't set trickle cb for '" << name << "'");
476 return nullptr;
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()),
498 &ctx->peer_);
499 if (r) {
500 MOZ_MTLOG(ML_ERROR, "Couldn't create ICE peer ctx for '" << name << "'");
501 return nullptr;
504 nsresult rv;
505 ctx->sts_target_ = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
507 if (!NS_SUCCEEDED(rv))
508 return nullptr;
510 return ctx;
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;
520 initialized = false;
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_;
528 delete ice_handler_;
531 RefPtr<NrIceMediaStream>
532 NrIceCtx::CreateStream(const std::string& name, int components) {
533 RefPtr<NrIceMediaStream> stream =
534 NrIceMediaStream::Create(this, name, components);
536 if (stream) {
537 streams_.push_back(stream);
540 return stream;
543 std::string NrIceCtx::ufrag() const {
544 return ctx_->ufrag;
547 std::string NrIceCtx::pwd() const {
548 return ctx_->pwd;
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" <<
559 controlling);
560 return NS_OK;
563 NrIceCtx::Controlling NrIceCtx::GetControlling() {
564 return (peer_->controlling) ? ICE_CONTROLLING : ICE_CONTROLLED;
567 nsresult NrIceCtx::SetStunServers(const std::vector<NrIceStunServer>&
568 stun_servers) {
569 if (stun_servers.empty())
570 return NS_OK;
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]);
576 if (NS_FAILED(rv)) {
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());
583 if (r) {
584 MOZ_MTLOG(ML_ERROR, "Couldn't set STUN server for '" << name_ << "'");
585 return NS_ERROR_FAILURE;
588 return NS_OK;
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>&
594 turn_servers) {
595 if (turn_servers.empty())
596 return NS_OK;
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]);
602 if (NS_FAILED(rv)) {
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());
609 if (r) {
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.
616 return NS_OK;
619 nsresult NrIceCtx::SetResolver(nr_resolver *resolver) {
620 int r = nr_ice_ctx_set_resolver(ctx_, resolver);
622 if (r) {
623 MOZ_MTLOG(ML_ERROR, "Couldn't set resolver for '" << name_ << "'");
624 return NS_ERROR_FAILURE;
627 return NS_OK;
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: '"
634 << name_ << "'");
635 SetConnectionState(ICE_CTX_FAILED);
636 return NS_ERROR_FAILURE;
639 int r = nr_ice_initialize(ctx_, &NrIceCtx::initialized_cb,
640 this);
642 if (r && r != R_WOULDBLOCK) {
643 MOZ_MTLOG(ML_ERROR, "Couldn't gather ICE candidates for '"
644 << name_ << "'");
645 SetConnectionState(ICE_CTX_FAILED);
646 return NS_ERROR_FAILURE;
649 SetGatheringState(ICE_CTX_GATHER_STARTED);
651 return NS_OK;
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) {
658 return streams_[i];
662 return nullptr;
665 std::vector<std::string> NrIceCtx::GetGlobalAttributes() {
666 char **attrs = 0;
667 int attrct;
668 int r;
669 std::vector<std::string> ret;
671 r = nr_ice_get_global_attributes(ctx_, &attrs, &attrct);
672 if (r) {
673 MOZ_MTLOG(ML_ERROR, "Couldn't get ufrag and password for '"
674 << name_ << "'");
675 return ret;
678 for (int i=0; i<attrct; i++) {
679 ret.push_back(std::string(attrs[i]));
680 RFREE(attrs[i]);
682 RFREE(attrs);
684 return ret;
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_,
695 attrs_in.size() ?
696 &attrs_in[0] : nullptr,
697 attrs_in.size());
698 if (r) {
699 MOZ_MTLOG(ML_ERROR, "Couldn't parse global attributes for "
700 << name_ << "'");
701 return NS_ERROR_FAILURE;
704 return NS_OK;
707 nsresult NrIceCtx::StartChecks() {
708 int r;
710 r=nr_ice_peer_ctx_pair_candidates(peer_);
711 if (r) {
712 MOZ_MTLOG(ML_ERROR, "Couldn't pair candidates on "
713 << name_ << "'");
714 SetConnectionState(ICE_CTX_FAILED);
715 return NS_ERROR_FAILURE;
718 r = nr_ice_peer_ctx_start_checks2(peer_,1);
719 if (r) {
720 if (r == R_NOT_FOUND) {
721 MOZ_MTLOG(ML_ERROR, "Couldn't start peer checks on "
722 << name_ << "' assuming trickle ICE");
723 } else {
724 MOZ_MTLOG(ML_ERROR, "Couldn't start peer checks on "
725 << name_ << "'");
726 SetConnectionState(ICE_CTX_FAILED);
727 return NS_ERROR_FAILURE;
731 return NS_OK;
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_);
744 if (r) {
745 MOZ_MTLOG(ML_ERROR, "Couldn't finalize "
746 << name_ << "'");
747 return NS_ERROR_FAILURE;
750 return NS_OK;
753 void NrIceCtx::SetConnectionState(ConnectionState state) {
754 if (state == connection_state_)
755 return;
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_)
775 return;
777 MOZ_MTLOG(ML_DEBUG, "NrIceCtx(" << name_ << "): gathering state " <<
778 gathering_state_ << "->" << state);
779 gathering_state_ = state;
781 SignalGatheringStateChange(this, state);
784 } // close namespace
786 // Reimplement nr_ice_compute_codeword to avoid copyright issues
787 void nr_ice_compute_codeword(char *buf, int len,char *codeword) {
788 UINT4 c;
790 r_crc32(buf,len,&c);
792 PL_Base64Encode(reinterpret_cast<char*>(&c), 3, codeword);
793 codeword[4] = 0;
795 return;