media/mtransport/nricectx.cpp

branch
TOR_BUG_9701
changeset 8
97036ab72558
equal deleted inserted replaced
-1:000000000000 0:6dbf669c0c7c
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 "logging.h"
48 #include "nspr.h"
49 #include "nss.h"
50 #include "pk11pub.h"
51 #include "plbase64.h"
52
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"
61
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 }
82
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"
89
90 namespace mozilla {
91
92 MOZ_MTLOG_MODULE("mtransport")
93
94 const char kNrIceTransportUdp[] = "udp";
95 const char kNrIceTransportTcp[] = "tcp";
96
97 static bool initialized = false;
98
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;
104
105 SECStatus rv = PK11_GenerateRandomOnSlot(slot, buf, len);
106 if (rv != SECSuccess)
107 return R_INTERNAL;
108
109 return 0;
110 }
111
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;
124
125 slot = PK11_GetInternalKeySlot();
126 if (!slot)
127 goto abort;
128
129 skey = PK11_ImportSymKey(slot, mech, PK11_OriginUnwrap,
130 CKA_SIGN, &keyi, nullptr);
131 if (!skey)
132 goto abort;
133
134
135 hmac_ctx = PK11_CreateContextBySymKey(mech, CKA_SIGN,
136 skey, &param);
137 if (!hmac_ctx)
138 goto abort;
139
140 status = PK11_DigestBegin(hmac_ctx);
141 if (status != SECSuccess)
142 goto abort;
143
144 status = PK11_DigestOp(hmac_ctx, buf, bufl);
145 if (status != SECSuccess)
146 goto abort;
147
148 status = PK11_DigestFinal(hmac_ctx, result, &hmac_len, 20);
149 if (status != SECSuccess)
150 goto abort;
151
152 MOZ_ASSERT(hmac_len == 20);
153
154 err = 0;
155
156 abort:
157 if(hmac_ctx) PK11_DestroyContext(hmac_ctx, PR_TRUE);
158 if (skey) PK11_FreeSymKey(skey);
159 if (slot) PK11_FreeSlot(slot);
160
161 return err;
162 }
163
164 static int nr_crypto_nss_md5(UCHAR *buf, int bufl, UCHAR *result) {
165 int err = R_INTERNAL;
166 SECStatus rv;
167
168 const SECHashObject *ho = HASH_GetHashObject(HASH_AlgMD5);
169 MOZ_ASSERT(ho);
170 if (!ho)
171 goto abort;
172
173 MOZ_ASSERT(ho->length == 16);
174
175 rv = HASH_HashBuf(ho->type, result, buf, bufl);
176 if (rv != SECSuccess)
177 goto abort;
178
179 err = 0;
180 abort:
181 return err;
182 }
183
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 };
189
190
191
192
193 nsresult NrIceStunServer::ToNicerStunStruct(nr_ice_stun_server *server,
194 const std::string &transport) const {
195 int r;
196 int transport_int;
197
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 }
207
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 }
223
224 return NS_OK;
225 }
226
227
228 nsresult NrIceTurnServer::ToNicerTurnStruct(nr_ice_turn_server *server) const {
229 memset(server, 0, sizeof(nr_ice_turn_server));
230
231 nsresult rv = ToNicerStunStruct(&server->turn_server, transport_);
232 if (NS_FAILED(rv))
233 return rv;
234
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 }
243
244 if (username_.empty())
245 return NS_ERROR_INVALID_ARG;
246 if (password_.empty())
247 return NS_ERROR_INVALID_ARG;
248
249 if (!(server->username=r_strdup(username_.c_str())))
250 return NS_ERROR_OUT_OF_MEMORY;
251
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.
255
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 }
266
267 return NS_OK;
268 }
269
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);
276
277 return 0;
278 }
279
280 int NrIceCtx::stream_ready(void *obj, nr_ice_media_stream *stream) {
281 MOZ_MTLOG(ML_DEBUG, "stream_ready called");
282
283 // Get the ICE ctx.
284 NrIceCtx *ctx = static_cast<NrIceCtx *>(obj);
285
286 RefPtr<NrIceMediaStream> s = ctx->FindStream(stream);
287
288 // Streams which do not exist should never be ready.
289 MOZ_ASSERT(s);
290
291 s->Ready();
292
293 return 0;
294 }
295
296 int NrIceCtx::stream_failed(void *obj, nr_ice_media_stream *stream) {
297 MOZ_MTLOG(ML_DEBUG, "stream_failed called");
298
299 // Get the ICE ctx
300 NrIceCtx *ctx = static_cast<NrIceCtx *>(obj);
301 RefPtr<NrIceMediaStream> s = ctx->FindStream(stream);
302
303 // Streams which do not exist should never fail.
304 MOZ_ASSERT(s);
305
306 ctx->SetConnectionState(ICE_CTX_FAILED);
307 s -> SignalFailed(s);
308 return 0;
309 }
310
311 int NrIceCtx::ice_completed(void *obj, nr_ice_peer_ctx *pctx) {
312 MOZ_MTLOG(ML_DEBUG, "ice_completed called");
313
314 // Get the ICE ctx
315 NrIceCtx *ctx = static_cast<NrIceCtx *>(obj);
316
317 // This is called even on failed contexts.
318 if (ctx->connection_state() != ICE_CTX_FAILED) {
319 ctx->SetConnectionState(ICE_CTX_OPEN);
320 }
321
322 return 0;
323 }
324
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);
331
332 // Streams which do not exist should never have packets.
333 MOZ_ASSERT(s);
334
335 s->SignalPacketReceived(s, component_id, msg, len);
336
337 return 0;
338 }
339
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);
347
348 // Streams which do not exist shouldn't have candidates.
349 MOZ_ASSERT(s);
350
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;
358
359 MOZ_MTLOG(ML_INFO, "NrIceCtx(" << ctx->name_ << "): trickling candidate "
360 << candidate_str);
361
362 s->SignalCandidate(s, candidate_str);
363 }
364
365 RefPtr<NrIceCtx> NrIceCtx::Create(const std::string& name,
366 bool offerer,
367 bool set_interface_priorities) {
368
369 RefPtr<NrIceCtx> ctx = new NrIceCtx(name, offerer);
370
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;
377
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);
385
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 }
412
413 NR_reg_set_uint4((char *)"stun.client.maximum_transmits",5);
414 }
415
416 // Create the ICE context
417 int r;
418
419 UINT4 flags = offerer ? NR_ICE_CTX_FLAGS_OFFERER:
420 NR_ICE_CTX_FLAGS_ANSWERER;
421 flags |= NR_ICE_CTX_FLAGS_AGGRESSIVE_NOMINATION;
422
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 }
429
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 }
436
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
443
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 }
451
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;
459
460 ctx->ice_handler_ = new nr_ice_handler();
461 ctx->ice_handler_->vtbl = ctx->ice_handler_vtbl_;
462 ctx->ice_handler_->obj = ctx;
463
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 }
474
475 nsresult rv;
476 ctx->sts_target_ = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
477
478 if (!NS_SUCCEEDED(rv))
479 return nullptr;
480
481 return ctx;
482 }
483
484
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 }
492
493 RefPtr<NrIceMediaStream>
494 NrIceCtx::CreateStream(const std::string& name, int components) {
495 RefPtr<NrIceMediaStream> stream =
496 NrIceMediaStream::Create(this, name, components);
497
498 streams_.push_back(stream);
499
500 return stream;
501 }
502
503 void NrIceCtx::destroy_peer_ctx() {
504 nr_ice_peer_ctx_destroy(&peer_);
505 }
506
507 nsresult NrIceCtx::SetControlling(Controlling controlling) {
508 peer_->controlling = (controlling == ICE_CONTROLLING)? 1 : 0;
509
510 MOZ_MTLOG(ML_DEBUG, "ICE ctx " << name_ << " setting controlling to" <<
511 controlling);
512 return NS_OK;
513 }
514
515 nsresult NrIceCtx::SetStunServers(const std::vector<NrIceStunServer>&
516 stun_servers) {
517 if (stun_servers.empty())
518 return NS_OK;
519
520 ScopedDeleteArray<nr_ice_stun_server> servers(
521 new nr_ice_stun_server[stun_servers.size()]);
522
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 }
530
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 }
536
537 return NS_OK;
538 }
539
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;
546
547 ScopedDeleteArray<nr_ice_turn_server> servers(
548 new nr_ice_turn_server[turn_servers.size()]);
549
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 }
557
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 }
563
564 // TODO(ekr@rtfm.com): This leaks the username/password. Need to free that.
565
566 return NS_OK;
567 }
568
569 nsresult NrIceCtx::SetResolver(nr_resolver *resolver) {
570 int r = nr_ice_ctx_set_resolver(ctx_, resolver);
571
572 if (r) {
573 MOZ_MTLOG(ML_ERROR, "Couldn't set resolver for '" << name_ << "'");
574 return NS_ERROR_FAILURE;
575 }
576
577 return NS_OK;
578 }
579
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 }
588
589 int r = nr_ice_initialize(ctx_, &NrIceCtx::initialized_cb,
590 this);
591
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 }
598
599 SetGatheringState(ICE_CTX_GATHER_STARTED);
600
601 return NS_OK;
602 }
603
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 }
611
612 return nullptr;
613 }
614
615 std::vector<std::string> NrIceCtx::GetGlobalAttributes() {
616 char **attrs = 0;
617 int attrct;
618 int r;
619 std::vector<std::string> ret;
620
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 }
627
628 for (int i=0; i<attrct; i++) {
629 ret.push_back(std::string(attrs[i]));
630 RFREE(attrs[i]);
631 }
632 RFREE(attrs);
633
634 return ret;
635 }
636
637 nsresult NrIceCtx::ParseGlobalAttributes(std::vector<std::string> attrs) {
638 std::vector<char *> attrs_in;
639
640 for (size_t i=0; i<attrs.size(); ++i) {
641 attrs_in.push_back(const_cast<char *>(attrs[i].c_str()));
642 }
643
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 }
653
654 return NS_OK;
655 }
656
657 nsresult NrIceCtx::StartChecks() {
658 int r;
659
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 }
667
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 }
682
683 return NS_OK;
684 }
685
686
687 void NrIceCtx::initialized_cb(NR_SOCKET s, int h, void *arg) {
688 NrIceCtx *ctx = static_cast<NrIceCtx *>(arg);
689
690 ctx->SetGatheringState(ICE_CTX_GATHER_COMPLETE);
691 }
692
693 nsresult NrIceCtx::Finalize() {
694 int r = nr_ice_ctx_finalize(ctx_, peer_);
695
696 if (r) {
697 MOZ_MTLOG(ML_ERROR, "Couldn't finalize "
698 << name_ << "'");
699 return NS_ERROR_FAILURE;
700 }
701
702 return NS_OK;
703 }
704
705 void NrIceCtx::SetConnectionState(ConnectionState state) {
706 if (state == connection_state_)
707 return;
708
709 MOZ_MTLOG(ML_INFO, "NrIceCtx(" << name_ << "): state " <<
710 connection_state_ << "->" << state);
711 connection_state_ = state;
712
713 SignalConnectionStateChange(this, state);
714 }
715
716 void NrIceCtx::SetGatheringState(GatheringState state) {
717 if (state == gathering_state_)
718 return;
719
720 MOZ_MTLOG(ML_DEBUG, "NrIceCtx(" << name_ << "): gathering state " <<
721 gathering_state_ << "->" << state);
722 gathering_state_ = state;
723
724 SignalGatheringStateChange(this, state);
725 }
726
727 } // close namespace
728
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;
732
733 r_crc32(buf,len,&c);
734
735 PL_Base64Encode(reinterpret_cast<char*>(&c), 3, codeword);
736 codeword[4] = 0;
737
738 return;
739 }
740

mercurial