1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/media/mtransport/third_party/nICEr/src/ice/ice_ctx.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,748 @@ 1.4 +/* 1.5 +Copyright (c) 2007, Adobe Systems, Incorporated 1.6 +All rights reserved. 1.7 + 1.8 +Redistribution and use in source and binary forms, with or without 1.9 +modification, are permitted provided that the following conditions are 1.10 +met: 1.11 + 1.12 +* Redistributions of source code must retain the above copyright 1.13 + notice, this list of conditions and the following disclaimer. 1.14 + 1.15 +* Redistributions in binary form must reproduce the above copyright 1.16 + notice, this list of conditions and the following disclaimer in the 1.17 + documentation and/or other materials provided with the distribution. 1.18 + 1.19 +* Neither the name of Adobe Systems, Network Resonance nor the names of its 1.20 + contributors may be used to endorse or promote products derived from 1.21 + this software without specific prior written permission. 1.22 + 1.23 +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1.24 +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1.25 +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1.26 +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 1.27 +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 1.28 +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 1.29 +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1.30 +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 1.31 +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 1.32 +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 1.33 +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1.34 +*/ 1.35 + 1.36 + 1.37 + 1.38 +static char *RCSSTRING __UNUSED__="$Id: ice_ctx.c,v 1.2 2008/04/28 17:59:01 ekr Exp $"; 1.39 + 1.40 +#include <csi_platform.h> 1.41 +#include <assert.h> 1.42 +#include <sys/types.h> 1.43 +#ifdef WIN32 1.44 +#include <winsock2.h> 1.45 +#else 1.46 +#include <sys/socket.h> 1.47 +#include <netinet/in.h> 1.48 +#include <arpa/inet.h> 1.49 +#endif 1.50 +#include <sys/queue.h> 1.51 +#include <string.h> 1.52 +#include <nr_api.h> 1.53 +#include <registry.h> 1.54 +#include "stun.h" 1.55 +#include "ice_ctx.h" 1.56 +#include "ice_reg.h" 1.57 +#include "nr_crypto.h" 1.58 +#include "async_timer.h" 1.59 +#include "util.h" 1.60 + 1.61 + 1.62 +int LOG_ICE = 0; 1.63 + 1.64 +static int nr_ice_random_string(char *str, int len); 1.65 +static int nr_ice_fetch_stun_servers(int ct, nr_ice_stun_server **out); 1.66 +#ifdef USE_TURN 1.67 +static int nr_ice_fetch_turn_servers(int ct, nr_ice_turn_server **out); 1.68 +#endif /* USE_TURN */ 1.69 +static void nr_ice_ctx_destroy_cb(NR_SOCKET s, int how, void *cb_arg); 1.70 +static int nr_ice_ctx_pair_new_trickle_candidates(nr_ice_ctx *ctx, nr_ice_candidate *cand); 1.71 + 1.72 +int nr_ice_fetch_stun_servers(int ct, nr_ice_stun_server **out) 1.73 + { 1.74 + int r,_status; 1.75 + nr_ice_stun_server *servers = 0; 1.76 + int i; 1.77 + NR_registry child; 1.78 + char *addr=0; 1.79 + UINT2 port; 1.80 + in_addr_t addr_int; 1.81 + 1.82 + if(!(servers=RCALLOC(sizeof(nr_ice_stun_server)*ct))) 1.83 + ABORT(R_NO_MEMORY); 1.84 + 1.85 + for(i=0;i<ct;i++){ 1.86 + if(r=NR_reg_get_child_registry(NR_ICE_REG_STUN_SRV_PRFX,i,child)) 1.87 + ABORT(r); 1.88 + /* Assume we have a v4 addr for now */ 1.89 + if(r=NR_reg_alloc2_string(child,"addr",&addr)) 1.90 + ABORT(r); 1.91 + addr_int=inet_addr(addr); 1.92 + if(addr_int==INADDR_NONE){ 1.93 + r_log(LOG_ICE,LOG_ERR,"Invalid address %s;",addr); 1.94 + ABORT(R_BAD_ARGS); 1.95 + } 1.96 + if(r=NR_reg_get2_uint2(child,"port",&port)) { 1.97 + if (r != R_NOT_FOUND) 1.98 + ABORT(r); 1.99 + port = 3478; 1.100 + } 1.101 + if(r=nr_ip4_port_to_transport_addr(ntohl(addr_int), port, IPPROTO_UDP, 1.102 + &servers[i].u.addr)) 1.103 + ABORT(r); 1.104 + servers[i].index=i; 1.105 + servers[i].type = NR_ICE_STUN_SERVER_TYPE_ADDR; 1.106 + RFREE(addr); 1.107 + addr=0; 1.108 + } 1.109 + 1.110 + *out = servers; 1.111 + 1.112 + _status=0; 1.113 + abort: 1.114 + RFREE(addr); 1.115 + if (_status) RFREE(servers); 1.116 + return(_status); 1.117 + } 1.118 + 1.119 +int nr_ice_ctx_set_stun_servers(nr_ice_ctx *ctx,nr_ice_stun_server *servers,int ct) 1.120 + { 1.121 + int _status; 1.122 + 1.123 + if(ctx->stun_servers){ 1.124 + RFREE(ctx->stun_servers); 1.125 + ctx->stun_server_ct=0; 1.126 + } 1.127 + 1.128 + if (ct) { 1.129 + if(!(ctx->stun_servers=RCALLOC(sizeof(nr_ice_stun_server)*ct))) 1.130 + ABORT(R_NO_MEMORY); 1.131 + 1.132 + memcpy(ctx->stun_servers,servers,sizeof(nr_ice_stun_server)*ct); 1.133 + ctx->stun_server_ct = ct; 1.134 + } 1.135 + 1.136 + _status=0; 1.137 + abort: 1.138 + return(_status); 1.139 + } 1.140 + 1.141 +int nr_ice_ctx_set_turn_servers(nr_ice_ctx *ctx,nr_ice_turn_server *servers,int ct) 1.142 + { 1.143 + int _status; 1.144 + 1.145 + if(ctx->turn_servers){ 1.146 + RFREE(ctx->turn_servers); 1.147 + ctx->turn_server_ct=0; 1.148 + } 1.149 + 1.150 + if(ct) { 1.151 + if(!(ctx->turn_servers=RCALLOC(sizeof(nr_ice_turn_server)*ct))) 1.152 + ABORT(R_NO_MEMORY); 1.153 + 1.154 + memcpy(ctx->turn_servers,servers,sizeof(nr_ice_turn_server)*ct); 1.155 + ctx->turn_server_ct = ct; 1.156 + } 1.157 + 1.158 + _status=0; 1.159 + abort: 1.160 + return(_status); 1.161 + } 1.162 + 1.163 +int nr_ice_ctx_set_local_addrs(nr_ice_ctx *ctx,nr_local_addr *addrs,int ct) 1.164 + { 1.165 + int _status,i,r; 1.166 + 1.167 + if(ctx->local_addrs) { 1.168 + RFREE(ctx->local_addrs); 1.169 + ctx->local_addr_ct=0; 1.170 + ctx->local_addrs=0; 1.171 + } 1.172 + 1.173 + if (ct) { 1.174 + if(!(ctx->local_addrs=RCALLOC(sizeof(nr_local_addr)*ct))) 1.175 + ABORT(R_NO_MEMORY); 1.176 + 1.177 + for (i=0;i<ct;++i) { 1.178 + if (r=nr_local_addr_copy(ctx->local_addrs+i,addrs+i)) { 1.179 + ABORT(r); 1.180 + } 1.181 + } 1.182 + ctx->local_addr_ct = ct; 1.183 + } 1.184 + 1.185 + _status=0; 1.186 + abort: 1.187 + return(_status); 1.188 + } 1.189 + 1.190 +int nr_ice_ctx_set_resolver(nr_ice_ctx *ctx, nr_resolver *resolver) 1.191 + { 1.192 + int _status; 1.193 + 1.194 + if (ctx->resolver) { 1.195 + ABORT(R_ALREADY); 1.196 + } 1.197 + 1.198 + ctx->resolver = resolver; 1.199 + 1.200 + _status=0; 1.201 + abort: 1.202 + return(_status); 1.203 + } 1.204 + 1.205 +int nr_ice_ctx_set_interface_prioritizer(nr_ice_ctx *ctx, nr_interface_prioritizer *ip) 1.206 + { 1.207 + int _status; 1.208 + 1.209 + if (ctx->interface_prioritizer) { 1.210 + ABORT(R_ALREADY); 1.211 + } 1.212 + 1.213 + ctx->interface_prioritizer = ip; 1.214 + 1.215 + _status=0; 1.216 + abort: 1.217 + return(_status); 1.218 + } 1.219 + 1.220 +#ifdef USE_TURN 1.221 +int nr_ice_fetch_turn_servers(int ct, nr_ice_turn_server **out) 1.222 + { 1.223 + int r,_status; 1.224 + nr_ice_turn_server *servers = 0; 1.225 + int i; 1.226 + NR_registry child; 1.227 + char *addr=0; 1.228 + UINT2 port; 1.229 + in_addr_t addr_int; 1.230 + Data data={0}; 1.231 + 1.232 + if(!(servers=RCALLOC(sizeof(nr_ice_turn_server)*ct))) 1.233 + ABORT(R_NO_MEMORY); 1.234 + 1.235 + for(i=0;i<ct;i++){ 1.236 + if(r=NR_reg_get_child_registry(NR_ICE_REG_TURN_SRV_PRFX,i,child)) 1.237 + ABORT(r); 1.238 + /* Assume we have a v4 addr for now */ 1.239 + if(r=NR_reg_alloc2_string(child,"addr",&addr)) 1.240 + ABORT(r); 1.241 + addr_int=inet_addr(addr); 1.242 + if(addr_int==INADDR_NONE){ 1.243 + r_log(LOG_ICE,LOG_ERR,"Invalid address %s",addr); 1.244 + ABORT(R_BAD_ARGS); 1.245 + } 1.246 + if(r=NR_reg_get2_uint2(child,"port",&port)) { 1.247 + if (r != R_NOT_FOUND) 1.248 + ABORT(r); 1.249 + port = 3478; 1.250 + } 1.251 + if(r=nr_ip4_port_to_transport_addr(ntohl(addr_int), port, IPPROTO_UDP, 1.252 + &servers[i].turn_server.u.addr)) 1.253 + ABORT(r); 1.254 + 1.255 + 1.256 + if(r=NR_reg_alloc2_string(child,NR_ICE_REG_TURN_SRV_USERNAME,&servers[i].username)){ 1.257 + if(r!=R_NOT_FOUND) 1.258 + ABORT(r); 1.259 + } 1.260 + 1.261 + if(r=NR_reg_alloc2_data(child,NR_ICE_REG_TURN_SRV_PASSWORD,&data)){ 1.262 + if(r!=R_NOT_FOUND) 1.263 + ABORT(r); 1.264 + } 1.265 + else { 1.266 + servers[i].password=RCALLOC(sizeof(*servers[i].password)); 1.267 + if(!servers[i].password) 1.268 + ABORT(R_NO_MEMORY); 1.269 + servers[i].password->data = data.data; 1.270 + servers[i].password->len = data.len; 1.271 + data.data=0; 1.272 + } 1.273 + 1.274 + servers[i].turn_server.index=i; 1.275 + 1.276 + RFREE(addr); 1.277 + addr=0; 1.278 + } 1.279 + 1.280 + *out = servers; 1.281 + 1.282 + _status=0; 1.283 + abort: 1.284 + RFREE(data.data); 1.285 + RFREE(addr); 1.286 + if (_status) RFREE(servers); 1.287 + return(_status); 1.288 + } 1.289 +#endif /* USE_TURN */ 1.290 + 1.291 +int nr_ice_ctx_create(char *label, UINT4 flags, nr_ice_ctx **ctxp) 1.292 + { 1.293 + nr_ice_ctx *ctx=0; 1.294 + int r,_status; 1.295 + char buf[100]; 1.296 + 1.297 + if(r=r_log_register("ice", &LOG_ICE)) 1.298 + ABORT(r); 1.299 + 1.300 + if(!(ctx=RCALLOC(sizeof(nr_ice_ctx)))) 1.301 + ABORT(R_NO_MEMORY); 1.302 + 1.303 + ctx->flags=flags; 1.304 + 1.305 + if(!(ctx->label=r_strdup(label))) 1.306 + ABORT(R_NO_MEMORY); 1.307 + 1.308 + if(r=nr_ice_random_string(buf,8)) 1.309 + ABORT(r); 1.310 + if(!(ctx->ufrag=r_strdup(buf))) 1.311 + ABORT(r); 1.312 + if(r=nr_ice_random_string(buf,32)) 1.313 + ABORT(r); 1.314 + if(!(ctx->pwd=r_strdup(buf))) 1.315 + ABORT(r); 1.316 + 1.317 + /* Get the STUN servers */ 1.318 + if(r=NR_reg_get_child_count(NR_ICE_REG_STUN_SRV_PRFX, 1.319 + (unsigned int *)&ctx->stun_server_ct)||ctx->stun_server_ct==0) { 1.320 + r_log(LOG_ICE,LOG_WARNING,"ICE(%s): No STUN servers specified", ctx->label); 1.321 + ctx->stun_server_ct=0; 1.322 + } 1.323 + 1.324 + /* 255 is the max for our priority algorithm */ 1.325 + if(ctx->stun_server_ct>255){ 1.326 + r_log(LOG_ICE,LOG_WARNING,"ICE(%s): Too many STUN servers specified: max=255", ctx->label); 1.327 + ctx->stun_server_ct=255; 1.328 + } 1.329 + 1.330 + if(ctx->stun_server_ct>0){ 1.331 + if(r=nr_ice_fetch_stun_servers(ctx->stun_server_ct,&ctx->stun_servers)){ 1.332 + r_log(LOG_ICE,LOG_ERR,"ICE(%s): Couldn't load STUN servers from registry", ctx->label); 1.333 + ctx->stun_server_ct=0; 1.334 + ABORT(r); 1.335 + } 1.336 + } 1.337 + 1.338 +#ifdef USE_TURN 1.339 + /* Get the TURN servers */ 1.340 + if(r=NR_reg_get_child_count(NR_ICE_REG_TURN_SRV_PRFX, 1.341 + (unsigned int *)&ctx->turn_server_ct)||ctx->turn_server_ct==0) { 1.342 + r_log(LOG_ICE,LOG_NOTICE,"ICE(%s): No TURN servers specified", ctx->label); 1.343 + ctx->turn_server_ct=0; 1.344 + } 1.345 +#else 1.346 + ctx->turn_server_ct=0; 1.347 +#endif /* USE_TURN */ 1.348 + 1.349 + ctx->local_addrs=0; 1.350 + ctx->local_addr_ct=0; 1.351 + 1.352 + /* 255 is the max for our priority algorithm */ 1.353 + if((ctx->stun_server_ct+ctx->turn_server_ct)>255){ 1.354 + r_log(LOG_ICE,LOG_WARNING,"ICE(%s): Too many STUN/TURN servers specified: max=255", ctx->label); 1.355 + ctx->turn_server_ct=255-ctx->stun_server_ct; 1.356 + } 1.357 + 1.358 +#ifdef USE_TURN 1.359 + if(ctx->turn_server_ct>0){ 1.360 + if(r=nr_ice_fetch_turn_servers(ctx->turn_server_ct,&ctx->turn_servers)){ 1.361 + ctx->turn_server_ct=0; 1.362 + r_log(LOG_ICE,LOG_ERR,"ICE(%s): Couldn't load TURN servers from registry", ctx->label); 1.363 + ABORT(r); 1.364 + } 1.365 + } 1.366 +#endif /* USE_TURN */ 1.367 + 1.368 + 1.369 + ctx->Ta = 20; 1.370 + 1.371 + STAILQ_INIT(&ctx->streams); 1.372 + STAILQ_INIT(&ctx->sockets); 1.373 + STAILQ_INIT(&ctx->foundations); 1.374 + STAILQ_INIT(&ctx->peers); 1.375 + STAILQ_INIT(&ctx->ids); 1.376 + 1.377 + *ctxp=ctx; 1.378 + 1.379 + _status=0; 1.380 + abort: 1.381 + if(_status) 1.382 + nr_ice_ctx_destroy_cb(0,0,ctx); 1.383 + 1.384 + return(_status); 1.385 + } 1.386 + 1.387 +static void nr_ice_ctx_destroy_cb(NR_SOCKET s, int how, void *cb_arg) 1.388 + { 1.389 + nr_ice_ctx *ctx=cb_arg; 1.390 + nr_ice_foundation *f1,*f2; 1.391 + nr_ice_media_stream *s1,*s2; 1.392 + int i; 1.393 + nr_ice_stun_id *id1,*id2; 1.394 + 1.395 + RFREE(ctx->label); 1.396 + 1.397 + RFREE(ctx->stun_servers); 1.398 + 1.399 + RFREE(ctx->local_addrs); 1.400 + 1.401 + for (i = 0; i < ctx->turn_server_ct; i++) { 1.402 + RFREE(ctx->turn_servers[i].username); 1.403 + r_data_destroy(&ctx->turn_servers[i].password); 1.404 + } 1.405 + RFREE(ctx->turn_servers); 1.406 + 1.407 + f1=STAILQ_FIRST(&ctx->foundations); 1.408 + while(f1){ 1.409 + f2=STAILQ_NEXT(f1,entry); 1.410 + RFREE(f1); 1.411 + f1=f2; 1.412 + } 1.413 + RFREE(ctx->pwd); 1.414 + RFREE(ctx->ufrag); 1.415 + 1.416 + STAILQ_FOREACH_SAFE(s1, &ctx->streams, entry, s2){ 1.417 + STAILQ_REMOVE(&ctx->streams,s1,nr_ice_media_stream_,entry); 1.418 + nr_ice_media_stream_destroy(&s1); 1.419 + } 1.420 + 1.421 + STAILQ_FOREACH_SAFE(id1, &ctx->ids, entry, id2){ 1.422 + STAILQ_REMOVE(&ctx->ids,id1,nr_ice_stun_id_,entry); 1.423 + RFREE(id1); 1.424 + } 1.425 + 1.426 + nr_resolver_destroy(&ctx->resolver); 1.427 + nr_interface_prioritizer_destroy(&ctx->interface_prioritizer); 1.428 + 1.429 + RFREE(ctx); 1.430 + } 1.431 + 1.432 +int nr_ice_ctx_destroy(nr_ice_ctx **ctxp) 1.433 + { 1.434 + if(!ctxp || !*ctxp) 1.435 + return(0); 1.436 + 1.437 + (*ctxp)->done_cb=0; 1.438 + (*ctxp)->trickle_cb=0; 1.439 + 1.440 + NR_ASYNC_SCHEDULE(nr_ice_ctx_destroy_cb,*ctxp); 1.441 + 1.442 + *ctxp=0; 1.443 + 1.444 + return(0); 1.445 + } 1.446 + 1.447 +void nr_ice_initialize_finished_cb(NR_SOCKET s, int h, void *cb_arg) 1.448 + { 1.449 + int r,_status; 1.450 + nr_ice_candidate *cand=cb_arg; 1.451 + nr_ice_ctx *ctx; 1.452 + 1.453 + 1.454 + assert(cb_arg); 1.455 + if (!cb_arg) 1.456 + return; 1.457 + ctx = cand->ctx; 1.458 + 1.459 + ctx->uninitialized_candidates--; 1.460 + 1.461 + if (cand->state == NR_ICE_CAND_STATE_INITIALIZED) { 1.462 + int was_pruned = 0; 1.463 + 1.464 + if (r=nr_ice_component_maybe_prune_candidate(ctx, cand->component, 1.465 + cand, &was_pruned)) { 1.466 + r_log(LOG_ICE, LOG_NOTICE, "ICE(%s): Problem pruning candidates",ctx->label); 1.467 + } 1.468 + 1.469 + /* If we are initialized, the candidate wasn't pruned, 1.470 + and we have a trickle ICE callback fire the callback */ 1.471 + if (ctx->trickle_cb && !was_pruned) { 1.472 + ctx->trickle_cb(ctx->trickle_cb_arg, ctx, cand->stream, cand->component_id, cand); 1.473 + 1.474 + if (r=nr_ice_ctx_pair_new_trickle_candidates(ctx, cand)) { 1.475 + r_log(LOG_ICE,LOG_ERR, "ICE(%s): All could not pair new trickle candidate",ctx->label); 1.476 + /* But continue */ 1.477 + } 1.478 + } 1.479 + } 1.480 + 1.481 + if(ctx->uninitialized_candidates==0){ 1.482 + r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): All candidates initialized",ctx->label); 1.483 + ctx->state=NR_ICE_STATE_INITIALIZED; 1.484 + if (ctx->done_cb) { 1.485 + ctx->done_cb(0,0,ctx->cb_arg); 1.486 + } 1.487 + else { 1.488 + r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): No done_cb. We were probably destroyed.",ctx->label); 1.489 + } 1.490 + } 1.491 + else { 1.492 + r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): Waiting for %d candidates to be initialized",ctx->label, ctx->uninitialized_candidates); 1.493 + } 1.494 + } 1.495 + 1.496 +static int nr_ice_ctx_pair_new_trickle_candidates(nr_ice_ctx *ctx, nr_ice_candidate *cand) 1.497 + { 1.498 + int r,_status; 1.499 + nr_ice_peer_ctx *pctx; 1.500 + 1.501 + pctx=STAILQ_FIRST(&ctx->peers); 1.502 + while(pctx){ 1.503 + if (pctx->state == NR_ICE_PEER_STATE_PAIRED) { 1.504 + r = nr_ice_peer_ctx_pair_new_trickle_candidate(ctx, pctx, cand); 1.505 + if (r) 1.506 + ABORT(r); 1.507 + } 1.508 + 1.509 + pctx=STAILQ_NEXT(pctx,entry); 1.510 + } 1.511 + 1.512 + _status=0; 1.513 + abort: 1.514 + return(_status); 1.515 + } 1.516 + 1.517 + 1.518 +#define MAXADDRS 100 // Ridiculously high 1.519 +int nr_ice_initialize(nr_ice_ctx *ctx, NR_async_cb done_cb, void *cb_arg) 1.520 + { 1.521 + int r,_status; 1.522 + nr_ice_media_stream *stream; 1.523 + nr_local_addr addrs[MAXADDRS]; 1.524 + int i,addr_ct; 1.525 + 1.526 + r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): Initializing candidates",ctx->label); 1.527 + ctx->state=NR_ICE_STATE_INITIALIZING; 1.528 + ctx->done_cb=done_cb; 1.529 + ctx->cb_arg=cb_arg; 1.530 + 1.531 + if(STAILQ_EMPTY(&ctx->streams)) { 1.532 + r_log(LOG_ICE,LOG_ERR,"ICE(%s): Missing streams to initialize",ctx->label); 1.533 + ABORT(R_BAD_ARGS); 1.534 + } 1.535 + 1.536 + /* First, gather all the local addresses we have */ 1.537 + if(r=nr_stun_find_local_addresses(addrs,MAXADDRS,&addr_ct)) { 1.538 + r_log(LOG_ICE,LOG_ERR,"ICE(%s): unable to find local addresses",ctx->label); 1.539 + ABORT(r); 1.540 + } 1.541 + 1.542 + /* Sort interfaces by preference */ 1.543 + if(ctx->interface_prioritizer) { 1.544 + for(i=0;i<addr_ct;i++){ 1.545 + if(r=nr_interface_prioritizer_add_interface(ctx->interface_prioritizer,addrs+i)) { 1.546 + r_log(LOG_ICE,LOG_ERR,"ICE(%s): unable to add interface ",ctx->label); 1.547 + ABORT(r); 1.548 + } 1.549 + } 1.550 + if(r=nr_interface_prioritizer_sort_preference(ctx->interface_prioritizer)) { 1.551 + r_log(LOG_ICE,LOG_ERR,"ICE(%s): unable to sort interface by preference",ctx->label); 1.552 + ABORT(r); 1.553 + } 1.554 + } 1.555 + 1.556 + if (r=nr_ice_ctx_set_local_addrs(ctx,addrs,addr_ct)) { 1.557 + ABORT(r); 1.558 + } 1.559 + 1.560 + /* Initialize all the media stream/component pairs */ 1.561 + stream=STAILQ_FIRST(&ctx->streams); 1.562 + while(stream){ 1.563 + if(r=nr_ice_media_stream_initialize(ctx,stream)) 1.564 + ABORT(r); 1.565 + 1.566 + stream=STAILQ_NEXT(stream,entry); 1.567 + } 1.568 + 1.569 + if(ctx->uninitialized_candidates) 1.570 + ABORT(R_WOULDBLOCK); 1.571 + 1.572 + 1.573 + _status=0; 1.574 + abort: 1.575 + return(_status); 1.576 + } 1.577 + 1.578 +int nr_ice_add_media_stream(nr_ice_ctx *ctx,char *label,int components, nr_ice_media_stream **streamp) 1.579 + { 1.580 + int r,_status; 1.581 + 1.582 + if(r=nr_ice_media_stream_create(ctx,label,components,streamp)) 1.583 + ABORT(r); 1.584 + 1.585 + STAILQ_INSERT_TAIL(&ctx->streams,*streamp,entry); 1.586 + 1.587 + _status=0; 1.588 + abort: 1.589 + return(_status); 1.590 + } 1.591 + 1.592 +int nr_ice_get_global_attributes(nr_ice_ctx *ctx,char ***attrsp, int *attrctp) 1.593 + { 1.594 + char **attrs=0; 1.595 + int _status; 1.596 + char *tmp=0; 1.597 + 1.598 + if(!(attrs=RCALLOC(sizeof(char *)*2))) 1.599 + ABORT(R_NO_MEMORY); 1.600 + 1.601 + if(!(tmp=RMALLOC(100))) 1.602 + ABORT(R_NO_MEMORY); 1.603 + snprintf(tmp,100,"ice-ufrag:%s",ctx->ufrag); 1.604 + attrs[0]=tmp; 1.605 + 1.606 + if(!(tmp=RMALLOC(100))) 1.607 + ABORT(R_NO_MEMORY); 1.608 + snprintf(tmp,100,"ice-pwd:%s",ctx->pwd); 1.609 + attrs[1]=tmp; 1.610 + 1.611 + *attrctp=2; 1.612 + *attrsp=attrs; 1.613 + 1.614 + _status=0; 1.615 + abort: 1.616 + if (_status){ 1.617 + if (attrs){ 1.618 + RFREE(attrs[0]); 1.619 + RFREE(attrs[1]); 1.620 + } 1.621 + RFREE(attrs); 1.622 + } 1.623 + return(_status); 1.624 + } 1.625 + 1.626 +static int nr_ice_random_string(char *str, int len) 1.627 + { 1.628 + unsigned char bytes[100]; 1.629 + int needed; 1.630 + int r,_status; 1.631 + 1.632 + if(len%2) ABORT(R_BAD_ARGS); 1.633 + needed=len/2; 1.634 + 1.635 + if(needed>sizeof(bytes)) ABORT(R_BAD_ARGS); 1.636 + 1.637 + //memset(bytes,0,needed); 1.638 + 1.639 + if(r=nr_crypto_random_bytes(bytes,needed)) 1.640 + ABORT(r); 1.641 + 1.642 + if(r=nr_bin2hex(bytes,needed,(unsigned char *)str)) 1.643 + ABORT(r); 1.644 + 1.645 + _status=0; 1.646 + abort: 1.647 + return(_status); 1.648 + } 1.649 + 1.650 +/* This is incredibly annoying: we now have a datagram but we don't 1.651 + know which peer it's from, and we need to be able to tell the 1.652 + API user. So, offer it to each peer and if one bites, assume 1.653 + the others don't want it 1.654 +*/ 1.655 +int nr_ice_ctx_deliver_packet(nr_ice_ctx *ctx, nr_ice_component *comp, nr_transport_addr *source_addr, UCHAR *data, int len) 1.656 + { 1.657 + nr_ice_peer_ctx *pctx; 1.658 + int r; 1.659 + 1.660 + pctx=STAILQ_FIRST(&ctx->peers); 1.661 + while(pctx){ 1.662 + r=nr_ice_peer_ctx_deliver_packet_maybe(pctx, comp, source_addr, data, len); 1.663 + if(!r) 1.664 + break; 1.665 + 1.666 + pctx=STAILQ_NEXT(pctx,entry); 1.667 + } 1.668 + 1.669 + if(!pctx) 1.670 + r_log(LOG_ICE,LOG_WARNING,"ICE(%s): Packet received from %s which doesn't match any known peer",ctx->label,source_addr->as_string); 1.671 + 1.672 + return(0); 1.673 + } 1.674 + 1.675 +int nr_ice_ctx_is_known_id(nr_ice_ctx *ctx, UCHAR id[12]) 1.676 + { 1.677 + nr_ice_stun_id *xid; 1.678 + 1.679 + xid=STAILQ_FIRST(&ctx->ids); 1.680 + while(xid){ 1.681 + if (!memcmp(xid->id, id, 12)) 1.682 + return 1; 1.683 + 1.684 + xid=STAILQ_NEXT(xid,entry); 1.685 + } 1.686 + 1.687 + return 0; 1.688 + } 1.689 + 1.690 +int nr_ice_ctx_remember_id(nr_ice_ctx *ctx, nr_stun_message *msg) 1.691 +{ 1.692 + int _status; 1.693 + nr_ice_stun_id *xid; 1.694 + 1.695 + xid = RCALLOC(sizeof(*xid)); 1.696 + if (!xid) 1.697 + ABORT(R_NO_MEMORY); 1.698 + 1.699 + assert(sizeof(xid->id) == sizeof(msg->header.id)); 1.700 +#if __STDC_VERSION__ >= 201112L 1.701 + _Static_assert(sizeof(xid->id) == sizeof(msg->header.id),"Message ID Size Mismatch"); 1.702 +#endif 1.703 + memcpy(xid->id, &msg->header.id, sizeof(xid->id)); 1.704 + 1.705 + STAILQ_INSERT_TAIL(&ctx->ids,xid,entry); 1.706 + 1.707 + _status=0; 1.708 + abort: 1.709 + return(_status); 1.710 +} 1.711 + 1.712 + 1.713 +/* Clean up some of the resources (mostly file descriptors) used 1.714 + by candidates we didn't choose. Note that this still leaves 1.715 + a fair amount of non-system stuff floating around. This gets 1.716 + cleaned up when you destroy the ICE ctx */ 1.717 +int nr_ice_ctx_finalize(nr_ice_ctx *ctx, nr_ice_peer_ctx *pctx) 1.718 + { 1.719 + nr_ice_media_stream *lstr,*rstr; 1.720 + 1.721 + r_log(LOG_ICE,LOG_DEBUG,"Finalizing ICE ctx %s, peer=%s",ctx->label,pctx->label); 1.722 + /* 1.723 + First find the peer stream, if any 1.724 + */ 1.725 + lstr=STAILQ_FIRST(&ctx->streams); 1.726 + while(lstr){ 1.727 + rstr=STAILQ_FIRST(&pctx->peer_streams); 1.728 + 1.729 + while(rstr){ 1.730 + if(rstr->local_stream==lstr) 1.731 + break; 1.732 + 1.733 + rstr=STAILQ_NEXT(rstr,entry); 1.734 + } 1.735 + 1.736 + nr_ice_media_stream_finalize(lstr,rstr); 1.737 + 1.738 + lstr=STAILQ_NEXT(lstr,entry); 1.739 + } 1.740 + 1.741 + return(0); 1.742 + } 1.743 + 1.744 + 1.745 +int nr_ice_ctx_set_trickle_cb(nr_ice_ctx *ctx, nr_ice_trickle_candidate_cb cb, void *cb_arg) 1.746 +{ 1.747 + ctx->trickle_cb = cb; 1.748 + ctx->trickle_cb_arg = cb_arg; 1.749 + 1.750 + return 0; 1.751 +}