Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
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:
12 /*
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.
42 */
44 #include <string>
45 #include <vector>
47 #include "logging.h"
48 #include "nspr.h"
49 #include "nss.h"
50 #include "pk11pub.h"
51 #include "plbase64.h"
53 #include "nsCOMPtr.h"
54 #include "nsComponentManagerUtils.h"
55 #include "nsError.h"
56 #include "nsIEventTarget.h"
57 #include "nsNetCID.h"
58 #include "nsComponentManagerUtils.h"
59 #include "nsServiceManagerUtils.h"
60 #include "ScopedNSSTypes.h"
62 // nICEr includes
63 extern "C" {
64 #include "nr_api.h"
65 #include "registry.h"
66 #include "async_timer.h"
67 #include "r_crc32.h"
68 #include "r_memory.h"
69 #include "ice_reg.h"
70 #include "ice_util.h"
71 #include "transport_addr.h"
72 #include "nr_crypto.h"
73 #include "nr_socket.h"
74 #include "nr_socket_local.h"
75 #include "stun_client_ctx.h"
76 #include "stun_server_ctx.h"
77 #include "ice_codeword.h"
78 #include "ice_ctx.h"
79 #include "ice_candidate.h"
80 #include "ice_handler.h"
81 }
83 // Local includes
84 #include "nricectx.h"
85 #include "nricemediastream.h"
86 #include "nr_socket_prsock.h"
87 #include "nrinterfaceprioritizer.h"
88 #include "rlogringbuffer.h"
90 namespace mozilla {
92 MOZ_MTLOG_MODULE("mtransport")
94 const char kNrIceTransportUdp[] = "udp";
95 const char kNrIceTransportTcp[] = "tcp";
97 static bool initialized = false;
99 // Implement NSPR-based crypto algorithms
100 static int nr_crypto_nss_random_bytes(UCHAR *buf, int len) {
101 ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
102 if (!slot)
103 return R_INTERNAL;
105 SECStatus rv = PK11_GenerateRandomOnSlot(slot, buf, len);
106 if (rv != SECSuccess)
107 return R_INTERNAL;
109 return 0;
110 }
112 static int nr_crypto_nss_hmac(UCHAR *key, int keyl, UCHAR *buf, int bufl,
113 UCHAR *result) {
114 CK_MECHANISM_TYPE mech = CKM_SHA_1_HMAC;
115 PK11SlotInfo *slot = 0;
116 MOZ_ASSERT(keyl > 0);
117 SECItem keyi = { siBuffer, key, static_cast<unsigned int>(keyl)};
118 PK11SymKey *skey = 0;
119 PK11Context *hmac_ctx = 0;
120 SECStatus status;
121 unsigned int hmac_len;
122 SECItem param = { siBuffer, nullptr, 0 };
123 int err = R_INTERNAL;
125 slot = PK11_GetInternalKeySlot();
126 if (!slot)
127 goto abort;
129 skey = PK11_ImportSymKey(slot, mech, PK11_OriginUnwrap,
130 CKA_SIGN, &keyi, nullptr);
131 if (!skey)
132 goto abort;
135 hmac_ctx = PK11_CreateContextBySymKey(mech, CKA_SIGN,
136 skey, ¶m);
137 if (!hmac_ctx)
138 goto abort;
140 status = PK11_DigestBegin(hmac_ctx);
141 if (status != SECSuccess)
142 goto abort;
144 status = PK11_DigestOp(hmac_ctx, buf, bufl);
145 if (status != SECSuccess)
146 goto abort;
148 status = PK11_DigestFinal(hmac_ctx, result, &hmac_len, 20);
149 if (status != SECSuccess)
150 goto abort;
152 MOZ_ASSERT(hmac_len == 20);
154 err = 0;
156 abort:
157 if(hmac_ctx) PK11_DestroyContext(hmac_ctx, PR_TRUE);
158 if (skey) PK11_FreeSymKey(skey);
159 if (slot) PK11_FreeSlot(slot);
161 return err;
162 }
164 static int nr_crypto_nss_md5(UCHAR *buf, int bufl, UCHAR *result) {
165 int err = R_INTERNAL;
166 SECStatus rv;
168 const SECHashObject *ho = HASH_GetHashObject(HASH_AlgMD5);
169 MOZ_ASSERT(ho);
170 if (!ho)
171 goto abort;
173 MOZ_ASSERT(ho->length == 16);
175 rv = HASH_HashBuf(ho->type, result, buf, bufl);
176 if (rv != SECSuccess)
177 goto abort;
179 err = 0;
180 abort:
181 return err;
182 }
184 static nr_ice_crypto_vtbl nr_ice_crypto_nss_vtbl = {
185 nr_crypto_nss_random_bytes,
186 nr_crypto_nss_hmac,
187 nr_crypto_nss_md5
188 };
193 nsresult NrIceStunServer::ToNicerStunStruct(nr_ice_stun_server *server,
194 const std::string &transport) const {
195 int r;
196 int transport_int;
198 memset(server, 0, sizeof(nr_ice_stun_server));
199 if (transport == kNrIceTransportUdp) {
200 transport_int = IPPROTO_UDP;
201 } else if (transport == kNrIceTransportTcp) {
202 transport_int = IPPROTO_TCP;
203 } else {
204 MOZ_ASSERT(false);
205 return NS_ERROR_FAILURE;
206 }
208 if (has_addr_) {
209 r = nr_praddr_to_transport_addr(&addr_, &server->u.addr,
210 transport_int, 0);
211 if (r) {
212 return NS_ERROR_FAILURE;
213 }
214 server->type=NR_ICE_STUN_SERVER_TYPE_ADDR;
215 }
216 else {
217 MOZ_ASSERT(sizeof(server->u.dnsname.host) > host_.size());
218 PL_strncpyz(server->u.dnsname.host, host_.c_str(),
219 sizeof(server->u.dnsname.host));
220 server->u.dnsname.port = port_;
221 server->type=NR_ICE_STUN_SERVER_TYPE_DNSNAME;
222 }
224 return NS_OK;
225 }
228 nsresult NrIceTurnServer::ToNicerTurnStruct(nr_ice_turn_server *server) const {
229 memset(server, 0, sizeof(nr_ice_turn_server));
231 nsresult rv = ToNicerStunStruct(&server->turn_server, transport_);
232 if (NS_FAILED(rv))
233 return rv;
235 if (transport_ == kNrIceTransportUdp) {
236 server->transport = IPPROTO_UDP;
237 } else if (transport_ == kNrIceTransportTcp) {
238 server->transport = IPPROTO_TCP;
239 } else {
240 MOZ_ASSERT(false);
241 return NS_ERROR_FAILURE;
242 }
244 if (username_.empty())
245 return NS_ERROR_INVALID_ARG;
246 if (password_.empty())
247 return NS_ERROR_INVALID_ARG;
249 if (!(server->username=r_strdup(username_.c_str())))
250 return NS_ERROR_OUT_OF_MEMORY;
252 // TODO(ekr@rtfm.com): handle non-ASCII passwords somehow?
253 // STUN requires they be SASLpreped, but we don't know if
254 // they are at this point.
256 // C++03 23.2.4, Paragraph 1 stipulates that the elements
257 // in std::vector must be contiguous, and can therefore be
258 // used as input to functions expecting C arrays.
259 int r = r_data_create(&server->password,
260 const_cast<UCHAR *>(&password_[0]),
261 password_.size());
262 if (r) {
263 RFREE(server->username);
264 return NS_ERROR_OUT_OF_MEMORY;
265 }
267 return NS_OK;
268 }
270 // Handler callbacks
271 int NrIceCtx::select_pair(void *obj,nr_ice_media_stream *stream,
272 int component_id, nr_ice_cand_pair **potentials,
273 int potential_ct) {
274 MOZ_MTLOG(ML_DEBUG, "select pair called: potential_ct = "
275 << potential_ct);
277 return 0;
278 }
280 int NrIceCtx::stream_ready(void *obj, nr_ice_media_stream *stream) {
281 MOZ_MTLOG(ML_DEBUG, "stream_ready called");
283 // Get the ICE ctx.
284 NrIceCtx *ctx = static_cast<NrIceCtx *>(obj);
286 RefPtr<NrIceMediaStream> s = ctx->FindStream(stream);
288 // Streams which do not exist should never be ready.
289 MOZ_ASSERT(s);
291 s->Ready();
293 return 0;
294 }
296 int NrIceCtx::stream_failed(void *obj, nr_ice_media_stream *stream) {
297 MOZ_MTLOG(ML_DEBUG, "stream_failed called");
299 // Get the ICE ctx
300 NrIceCtx *ctx = static_cast<NrIceCtx *>(obj);
301 RefPtr<NrIceMediaStream> s = ctx->FindStream(stream);
303 // Streams which do not exist should never fail.
304 MOZ_ASSERT(s);
306 ctx->SetConnectionState(ICE_CTX_FAILED);
307 s -> SignalFailed(s);
308 return 0;
309 }
311 int NrIceCtx::ice_completed(void *obj, nr_ice_peer_ctx *pctx) {
312 MOZ_MTLOG(ML_DEBUG, "ice_completed called");
314 // Get the ICE ctx
315 NrIceCtx *ctx = static_cast<NrIceCtx *>(obj);
317 // This is called even on failed contexts.
318 if (ctx->connection_state() != ICE_CTX_FAILED) {
319 ctx->SetConnectionState(ICE_CTX_OPEN);
320 }
322 return 0;
323 }
325 int NrIceCtx::msg_recvd(void *obj, nr_ice_peer_ctx *pctx,
326 nr_ice_media_stream *stream, int component_id,
327 UCHAR *msg, int len) {
328 // Get the ICE ctx
329 NrIceCtx *ctx = static_cast<NrIceCtx *>(obj);
330 RefPtr<NrIceMediaStream> s = ctx->FindStream(stream);
332 // Streams which do not exist should never have packets.
333 MOZ_ASSERT(s);
335 s->SignalPacketReceived(s, component_id, msg, len);
337 return 0;
338 }
340 void NrIceCtx::trickle_cb(void *arg, nr_ice_ctx *ice_ctx,
341 nr_ice_media_stream *stream,
342 int component_id,
343 nr_ice_candidate *candidate) {
344 // Get the ICE ctx
345 NrIceCtx *ctx = static_cast<NrIceCtx *>(arg);
346 RefPtr<NrIceMediaStream> s = ctx->FindStream(stream);
348 // Streams which do not exist shouldn't have candidates.
349 MOZ_ASSERT(s);
351 // Format the candidate.
352 char candidate_str[NR_ICE_MAX_ATTRIBUTE_SIZE];
353 int r = nr_ice_format_candidate_attribute(candidate, candidate_str,
354 sizeof(candidate_str));
355 MOZ_ASSERT(!r);
356 if (r)
357 return;
359 MOZ_MTLOG(ML_INFO, "NrIceCtx(" << ctx->name_ << "): trickling candidate "
360 << candidate_str);
362 s->SignalCandidate(s, candidate_str);
363 }
365 RefPtr<NrIceCtx> NrIceCtx::Create(const std::string& name,
366 bool offerer,
367 bool set_interface_priorities) {
369 RefPtr<NrIceCtx> ctx = new NrIceCtx(name, offerer);
371 // Initialize the crypto callbacks and logging stuff
372 if (!initialized) {
373 NR_reg_init(NR_REG_MODE_LOCAL);
374 RLogRingBuffer::CreateInstance();
375 nr_crypto_vtbl = &nr_ice_crypto_nss_vtbl;
376 initialized = true;
378 // Set the priorites for candidate type preferences.
379 // These numbers come from RFC 5245 S. 4.1.2.2
380 NR_reg_set_uchar((char *)NR_ICE_REG_PREF_TYPE_SRV_RFLX, 100);
381 NR_reg_set_uchar((char *)NR_ICE_REG_PREF_TYPE_PEER_RFLX, 110);
382 NR_reg_set_uchar((char *)NR_ICE_REG_PREF_TYPE_HOST, 126);
383 NR_reg_set_uchar((char *)NR_ICE_REG_PREF_TYPE_RELAYED, 5);
384 NR_reg_set_uchar((char *)NR_ICE_REG_PREF_TYPE_RELAYED_TCP, 0);
386 if (set_interface_priorities) {
387 NR_reg_set_uchar((char *)"ice.pref.interface.rl0", 255);
388 NR_reg_set_uchar((char *)"ice.pref.interface.wi0", 254);
389 NR_reg_set_uchar((char *)"ice.pref.interface.lo0", 253);
390 NR_reg_set_uchar((char *)"ice.pref.interface.en1", 252);
391 NR_reg_set_uchar((char *)"ice.pref.interface.en0", 251);
392 NR_reg_set_uchar((char *)"ice.pref.interface.eth0", 252);
393 NR_reg_set_uchar((char *)"ice.pref.interface.eth1", 251);
394 NR_reg_set_uchar((char *)"ice.pref.interface.eth2", 249);
395 NR_reg_set_uchar((char *)"ice.pref.interface.ppp", 250);
396 NR_reg_set_uchar((char *)"ice.pref.interface.ppp0", 249);
397 NR_reg_set_uchar((char *)"ice.pref.interface.en2", 248);
398 NR_reg_set_uchar((char *)"ice.pref.interface.en3", 247);
399 NR_reg_set_uchar((char *)"ice.pref.interface.em0", 251);
400 NR_reg_set_uchar((char *)"ice.pref.interface.em1", 252);
401 NR_reg_set_uchar((char *)"ice.pref.interface.vmnet0", 240);
402 NR_reg_set_uchar((char *)"ice.pref.interface.vmnet1", 241);
403 NR_reg_set_uchar((char *)"ice.pref.interface.vmnet3", 239);
404 NR_reg_set_uchar((char *)"ice.pref.interface.vmnet4", 238);
405 NR_reg_set_uchar((char *)"ice.pref.interface.vmnet5", 237);
406 NR_reg_set_uchar((char *)"ice.pref.interface.vmnet6", 236);
407 NR_reg_set_uchar((char *)"ice.pref.interface.vmnet7", 235);
408 NR_reg_set_uchar((char *)"ice.pref.interface.vmnet8", 234);
409 NR_reg_set_uchar((char *)"ice.pref.interface.virbr0", 233);
410 NR_reg_set_uchar((char *)"ice.pref.interface.wlan0", 232);
411 }
413 NR_reg_set_uint4((char *)"stun.client.maximum_transmits",5);
414 }
416 // Create the ICE context
417 int r;
419 UINT4 flags = offerer ? NR_ICE_CTX_FLAGS_OFFERER:
420 NR_ICE_CTX_FLAGS_ANSWERER;
421 flags |= NR_ICE_CTX_FLAGS_AGGRESSIVE_NOMINATION;
423 r = nr_ice_ctx_create(const_cast<char *>(name.c_str()), flags,
424 &ctx->ctx_);
425 if (r) {
426 MOZ_MTLOG(ML_ERROR, "Couldn't create ICE ctx for '" << name << "'");
427 return nullptr;
428 }
430 #ifdef USE_INTERFACE_PRIORITIZER
431 nr_interface_prioritizer *prioritizer = CreateInterfacePrioritizer();
432 if (!prioritizer) {
433 MOZ_MTLOG(PR_LOG_ERROR, "Couldn't create interface prioritizer.");
434 return nullptr;
435 }
437 r = nr_ice_ctx_set_interface_prioritizer(ctx->ctx_, prioritizer);
438 if (r) {
439 MOZ_MTLOG(PR_LOG_ERROR, "Couldn't set interface prioritizer.");
440 return nullptr;
441 }
442 #endif // USE_INTERFACE_PRIORITIZER
444 if (ctx->generating_trickle()) {
445 r = nr_ice_ctx_set_trickle_cb(ctx->ctx_, &NrIceCtx::trickle_cb, ctx);
446 if (r) {
447 MOZ_MTLOG(ML_ERROR, "Couldn't set trickle cb for '" << name << "'");
448 return nullptr;
449 }
450 }
452 // Create the handler objects
453 ctx->ice_handler_vtbl_ = new nr_ice_handler_vtbl();
454 ctx->ice_handler_vtbl_->select_pair = &NrIceCtx::select_pair;
455 ctx->ice_handler_vtbl_->stream_ready = &NrIceCtx::stream_ready;
456 ctx->ice_handler_vtbl_->stream_failed = &NrIceCtx::stream_failed;
457 ctx->ice_handler_vtbl_->ice_completed = &NrIceCtx::ice_completed;
458 ctx->ice_handler_vtbl_->msg_recvd = &NrIceCtx::msg_recvd;
460 ctx->ice_handler_ = new nr_ice_handler();
461 ctx->ice_handler_->vtbl = ctx->ice_handler_vtbl_;
462 ctx->ice_handler_->obj = ctx;
464 // Create the peer ctx. Because we do not support parallel forking, we
465 // only have one peer ctx.
466 std::string peer_name = name + ":default";
467 r = nr_ice_peer_ctx_create(ctx->ctx_, ctx->ice_handler_,
468 const_cast<char *>(peer_name.c_str()),
469 &ctx->peer_);
470 if (r) {
471 MOZ_MTLOG(ML_ERROR, "Couldn't create ICE peer ctx for '" << name << "'");
472 return nullptr;
473 }
475 nsresult rv;
476 ctx->sts_target_ = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
478 if (!NS_SUCCEEDED(rv))
479 return nullptr;
481 return ctx;
482 }
485 NrIceCtx::~NrIceCtx() {
486 MOZ_MTLOG(ML_DEBUG, "Destroying ICE ctx '" << name_ <<"'");
487 nr_ice_peer_ctx_destroy(&peer_);
488 nr_ice_ctx_destroy(&ctx_);
489 delete ice_handler_vtbl_;
490 delete ice_handler_;
491 }
493 RefPtr<NrIceMediaStream>
494 NrIceCtx::CreateStream(const std::string& name, int components) {
495 RefPtr<NrIceMediaStream> stream =
496 NrIceMediaStream::Create(this, name, components);
498 streams_.push_back(stream);
500 return stream;
501 }
503 void NrIceCtx::destroy_peer_ctx() {
504 nr_ice_peer_ctx_destroy(&peer_);
505 }
507 nsresult NrIceCtx::SetControlling(Controlling controlling) {
508 peer_->controlling = (controlling == ICE_CONTROLLING)? 1 : 0;
510 MOZ_MTLOG(ML_DEBUG, "ICE ctx " << name_ << " setting controlling to" <<
511 controlling);
512 return NS_OK;
513 }
515 nsresult NrIceCtx::SetStunServers(const std::vector<NrIceStunServer>&
516 stun_servers) {
517 if (stun_servers.empty())
518 return NS_OK;
520 ScopedDeleteArray<nr_ice_stun_server> servers(
521 new nr_ice_stun_server[stun_servers.size()]);
523 for (size_t i=0; i < stun_servers.size(); ++i) {
524 nsresult rv = stun_servers[i].ToNicerStunStruct(&servers[i]);
525 if (NS_FAILED(rv)) {
526 MOZ_MTLOG(ML_ERROR, "Couldn't set STUN server for '" << name_ << "'");
527 return NS_ERROR_FAILURE;
528 }
529 }
531 int r = nr_ice_ctx_set_stun_servers(ctx_, servers, stun_servers.size());
532 if (r) {
533 MOZ_MTLOG(ML_ERROR, "Couldn't set STUN server for '" << name_ << "'");
534 return NS_ERROR_FAILURE;
535 }
537 return NS_OK;
538 }
540 // TODO(ekr@rtfm.com): This is just SetStunServers with s/Stun/Turn
541 // Could we do a template or something?
542 nsresult NrIceCtx::SetTurnServers(const std::vector<NrIceTurnServer>&
543 turn_servers) {
544 if (turn_servers.empty())
545 return NS_OK;
547 ScopedDeleteArray<nr_ice_turn_server> servers(
548 new nr_ice_turn_server[turn_servers.size()]);
550 for (size_t i=0; i < turn_servers.size(); ++i) {
551 nsresult rv = turn_servers[i].ToNicerTurnStruct(&servers[i]);
552 if (NS_FAILED(rv)) {
553 MOZ_MTLOG(ML_ERROR, "Couldn't set TURN server for '" << name_ << "'");
554 return NS_ERROR_FAILURE;
555 }
556 }
558 int r = nr_ice_ctx_set_turn_servers(ctx_, servers, turn_servers.size());
559 if (r) {
560 MOZ_MTLOG(ML_ERROR, "Couldn't set TURN server for '" << name_ << "'");
561 return NS_ERROR_FAILURE;
562 }
564 // TODO(ekr@rtfm.com): This leaks the username/password. Need to free that.
566 return NS_OK;
567 }
569 nsresult NrIceCtx::SetResolver(nr_resolver *resolver) {
570 int r = nr_ice_ctx_set_resolver(ctx_, resolver);
572 if (r) {
573 MOZ_MTLOG(ML_ERROR, "Couldn't set resolver for '" << name_ << "'");
574 return NS_ERROR_FAILURE;
575 }
577 return NS_OK;
578 }
580 nsresult NrIceCtx::StartGathering() {
581 MOZ_ASSERT(ctx_->state == ICE_CTX_INIT);
582 if (ctx_->state != ICE_CTX_INIT) {
583 MOZ_MTLOG(ML_ERROR, "ICE ctx in the wrong state for gathering: '"
584 << name_ << "'");
585 SetConnectionState(ICE_CTX_FAILED);
586 return NS_ERROR_FAILURE;
587 }
589 int r = nr_ice_initialize(ctx_, &NrIceCtx::initialized_cb,
590 this);
592 if (r && r != R_WOULDBLOCK) {
593 MOZ_MTLOG(ML_ERROR, "Couldn't gather ICE candidates for '"
594 << name_ << "'");
595 SetConnectionState(ICE_CTX_FAILED);
596 return NS_ERROR_FAILURE;
597 }
599 SetGatheringState(ICE_CTX_GATHER_STARTED);
601 return NS_OK;
602 }
604 RefPtr<NrIceMediaStream> NrIceCtx::FindStream(
605 nr_ice_media_stream *stream) {
606 for (size_t i=0; i<streams_.size(); ++i) {
607 if (streams_[i]->stream() == stream) {
608 return streams_[i];
609 }
610 }
612 return nullptr;
613 }
615 std::vector<std::string> NrIceCtx::GetGlobalAttributes() {
616 char **attrs = 0;
617 int attrct;
618 int r;
619 std::vector<std::string> ret;
621 r = nr_ice_get_global_attributes(ctx_, &attrs, &attrct);
622 if (r) {
623 MOZ_MTLOG(ML_ERROR, "Couldn't get ufrag and password for '"
624 << name_ << "'");
625 return ret;
626 }
628 for (int i=0; i<attrct; i++) {
629 ret.push_back(std::string(attrs[i]));
630 RFREE(attrs[i]);
631 }
632 RFREE(attrs);
634 return ret;
635 }
637 nsresult NrIceCtx::ParseGlobalAttributes(std::vector<std::string> attrs) {
638 std::vector<char *> attrs_in;
640 for (size_t i=0; i<attrs.size(); ++i) {
641 attrs_in.push_back(const_cast<char *>(attrs[i].c_str()));
642 }
644 int r = nr_ice_peer_ctx_parse_global_attributes(peer_,
645 attrs_in.size() ?
646 &attrs_in[0] : nullptr,
647 attrs_in.size());
648 if (r) {
649 MOZ_MTLOG(ML_ERROR, "Couldn't parse global attributes for "
650 << name_ << "'");
651 return NS_ERROR_FAILURE;
652 }
654 return NS_OK;
655 }
657 nsresult NrIceCtx::StartChecks() {
658 int r;
660 r=nr_ice_peer_ctx_pair_candidates(peer_);
661 if (r) {
662 MOZ_MTLOG(ML_ERROR, "Couldn't pair candidates on "
663 << name_ << "'");
664 SetConnectionState(ICE_CTX_FAILED);
665 return NS_ERROR_FAILURE;
666 }
668 r = nr_ice_peer_ctx_start_checks2(peer_,1);
669 if (r) {
670 if (r == R_NOT_FOUND) {
671 MOZ_MTLOG(ML_ERROR, "Couldn't start peer checks on "
672 << name_ << "' assuming trickle ICE");
673 } else {
674 MOZ_MTLOG(ML_ERROR, "Couldn't start peer checks on "
675 << name_ << "'");
676 SetConnectionState(ICE_CTX_FAILED);
677 return NS_ERROR_FAILURE;
678 }
679 } else {
680 SetConnectionState(ICE_CTX_CHECKING);
681 }
683 return NS_OK;
684 }
687 void NrIceCtx::initialized_cb(NR_SOCKET s, int h, void *arg) {
688 NrIceCtx *ctx = static_cast<NrIceCtx *>(arg);
690 ctx->SetGatheringState(ICE_CTX_GATHER_COMPLETE);
691 }
693 nsresult NrIceCtx::Finalize() {
694 int r = nr_ice_ctx_finalize(ctx_, peer_);
696 if (r) {
697 MOZ_MTLOG(ML_ERROR, "Couldn't finalize "
698 << name_ << "'");
699 return NS_ERROR_FAILURE;
700 }
702 return NS_OK;
703 }
705 void NrIceCtx::SetConnectionState(ConnectionState state) {
706 if (state == connection_state_)
707 return;
709 MOZ_MTLOG(ML_INFO, "NrIceCtx(" << name_ << "): state " <<
710 connection_state_ << "->" << state);
711 connection_state_ = state;
713 SignalConnectionStateChange(this, state);
714 }
716 void NrIceCtx::SetGatheringState(GatheringState state) {
717 if (state == gathering_state_)
718 return;
720 MOZ_MTLOG(ML_DEBUG, "NrIceCtx(" << name_ << "): gathering state " <<
721 gathering_state_ << "->" << state);
722 gathering_state_ = state;
724 SignalGatheringStateChange(this, state);
725 }
727 } // close namespace
729 // Reimplement nr_ice_compute_codeword to avoid copyright issues
730 void nr_ice_compute_codeword(char *buf, int len,char *codeword) {
731 UINT4 c;
733 r_crc32(buf,len,&c);
735 PL_Base64Encode(reinterpret_cast<char*>(&c), 3, codeword);
736 codeword[4] = 0;
738 return;
739 }