1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/media/mtransport/third_party/nICEr/src/ice/ice_component.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1115 @@ 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_component.c,v 1.2 2008/04/28 17:59:01 ekr Exp $"; 1.39 + 1.40 +#include <string.h> 1.41 +#include <assert.h> 1.42 +#include <nr_api.h> 1.43 +#include <registry.h> 1.44 +#include <async_timer.h> 1.45 +#include "ice_ctx.h" 1.46 +#include "ice_codeword.h" 1.47 +#include "stun.h" 1.48 +#include "nr_socket_local.h" 1.49 +#include "nr_socket_turn.h" 1.50 +#include "nr_socket_buffered_stun.h" 1.51 +#include "ice_reg.h" 1.52 + 1.53 +static int nr_ice_component_stun_server_default_cb(void *cb_arg,nr_stun_server_ctx *stun_ctx,nr_socket *sock, nr_stun_server_request *req, int *dont_free, int *error); 1.54 +static int nr_ice_pre_answer_request_destroy(nr_ice_pre_answer_request **parp); 1.55 + 1.56 +/* This function takes ownership of the contents of req (but not req itself) */ 1.57 +static int nr_ice_pre_answer_request_create(nr_socket *sock, nr_stun_server_request *req, nr_ice_pre_answer_request **parp) 1.58 + { 1.59 + int r, _status; 1.60 + nr_ice_pre_answer_request *par = 0; 1.61 + nr_stun_message_attribute *attr; 1.62 + 1.63 + if (!(par = RCALLOC(sizeof(nr_ice_pre_answer_request)))) 1.64 + ABORT(R_NO_MEMORY); 1.65 + 1.66 + par->req = *req; /* Struct assignment */ 1.67 + memset(req, 0, sizeof(*req)); /* Zero contents to avoid confusion */ 1.68 + 1.69 + if (r=nr_socket_getaddr(sock, &par->local_addr)) 1.70 + ABORT(r); 1.71 + if (!nr_stun_message_has_attribute(par->req.request, NR_STUN_ATTR_USERNAME, &attr)) 1.72 + ABORT(R_INTERNAL); 1.73 + if (!(par->username = r_strdup(attr->u.username))) 1.74 + ABORT(R_NO_MEMORY); 1.75 + 1.76 + *parp=par; 1.77 + _status=0; 1.78 + abort: 1.79 + if (_status) { 1.80 + /* Erase the request so we don't free it */ 1.81 + memset(&par->req, 0, sizeof(nr_stun_server_request)); 1.82 + nr_ice_pre_answer_request_destroy(&par); 1.83 + } 1.84 + 1.85 + return(_status); 1.86 + } 1.87 + 1.88 +static int nr_ice_pre_answer_request_destroy(nr_ice_pre_answer_request **parp) 1.89 + { 1.90 + nr_ice_pre_answer_request *par; 1.91 + 1.92 + if (!parp || !*parp) 1.93 + return(0); 1.94 + 1.95 + par = *parp; 1.96 + *parp = 0; 1.97 + 1.98 + nr_stun_message_destroy(&par->req.request); 1.99 + nr_stun_message_destroy(&par->req.response); 1.100 + 1.101 + RFREE(par->username); 1.102 + 1.103 + return(0); 1.104 + } 1.105 + 1.106 +int nr_ice_component_create(nr_ice_media_stream *stream, int component_id, nr_ice_component **componentp) 1.107 + { 1.108 + int _status; 1.109 + nr_ice_component *comp=0; 1.110 + 1.111 + if(!(comp=RCALLOC(sizeof(nr_ice_component)))) 1.112 + ABORT(R_NO_MEMORY); 1.113 + 1.114 + comp->state=NR_ICE_COMPONENT_UNPAIRED; 1.115 + comp->component_id=component_id; 1.116 + comp->stream=stream; 1.117 + comp->ctx=stream->ctx; 1.118 + 1.119 + STAILQ_INIT(&comp->sockets); 1.120 + TAILQ_INIT(&comp->candidates); 1.121 + STAILQ_INIT(&comp->pre_answer_reqs); 1.122 + 1.123 + STAILQ_INSERT_TAIL(&stream->components,comp,entry); 1.124 + 1.125 + _status=0; 1.126 + abort: 1.127 + return(_status); 1.128 + } 1.129 + 1.130 +int nr_ice_component_destroy(nr_ice_component **componentp) 1.131 + { 1.132 + nr_ice_component *component; 1.133 + nr_ice_socket *s1,*s2; 1.134 + nr_ice_candidate *c1,*c2; 1.135 + nr_ice_pre_answer_request *r1,*r2; 1.136 + 1.137 + if(!componentp || !*componentp) 1.138 + return(0); 1.139 + 1.140 + component=*componentp; 1.141 + *componentp=0; 1.142 + 1.143 + /* Detach ourselves from the sockets */ 1.144 + if (component->local_component){ 1.145 + nr_ice_socket *isock=STAILQ_FIRST(&component->local_component->sockets); 1.146 + while(isock){ 1.147 + nr_stun_server_remove_client(isock->stun_server, component); 1.148 + isock=STAILQ_NEXT(isock, entry); 1.149 + } 1.150 + } 1.151 + 1.152 + /* candidates MUST be destroyed before the sockets so that 1.153 + they can deregister */ 1.154 + TAILQ_FOREACH_SAFE(c1, &component->candidates, entry_comp, c2){ 1.155 + TAILQ_REMOVE(&component->candidates,c1,entry_comp); 1.156 + nr_ice_candidate_destroy(&c1); 1.157 + } 1.158 + 1.159 + STAILQ_FOREACH_SAFE(s1, &component->sockets, entry, s2){ 1.160 + STAILQ_REMOVE(&component->sockets,s1,nr_ice_socket_,entry); 1.161 + nr_ice_socket_destroy(&s1); 1.162 + } 1.163 + 1.164 + STAILQ_FOREACH_SAFE(r1, &component->pre_answer_reqs, entry, r2){ 1.165 + STAILQ_REMOVE(&component->pre_answer_reqs,r1,nr_ice_pre_answer_request_, entry); 1.166 + nr_ice_pre_answer_request_destroy(&r1); 1.167 + } 1.168 + 1.169 + if(component->keepalive_timer) 1.170 + NR_async_timer_cancel(component->keepalive_timer); 1.171 + nr_stun_client_ctx_destroy(&component->keepalive_ctx); 1.172 + 1.173 + RFREE(component); 1.174 + return(0); 1.175 + } 1.176 + 1.177 +static int nr_ice_component_initialize_udp(struct nr_ice_ctx_ *ctx,nr_ice_component *component, nr_local_addr *addrs, int addr_ct, char *lufrag, Data *pwd) 1.178 + { 1.179 + nr_socket *sock; 1.180 + nr_ice_socket *isock=0; 1.181 + nr_ice_candidate *cand=0; 1.182 + int i; 1.183 + int j; 1.184 + char label[256]; 1.185 + int r,_status; 1.186 + 1.187 + /* Now one ice_socket for each address */ 1.188 + for(i=0;i<addr_ct;i++){ 1.189 + char suppress; 1.190 + 1.191 + if(r=NR_reg_get2_char(NR_ICE_REG_SUPPRESS_INTERFACE_PRFX,addrs[i].addr.ifname,&suppress)){ 1.192 + if(r!=R_NOT_FOUND) 1.193 + ABORT(r); 1.194 + } 1.195 + else{ 1.196 + if(suppress) 1.197 + continue; 1.198 + } 1.199 + r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): host address %s",ctx->label,addrs[i].addr.as_string); 1.200 + if(r=nr_socket_local_create(&addrs[i].addr,&sock)){ 1.201 + r_log(LOG_ICE,LOG_WARNING,"ICE(%s): couldn't create socket for address %s",ctx->label,addrs[i].addr.as_string); 1.202 + continue; 1.203 + } 1.204 + 1.205 + if(r=nr_ice_socket_create(ctx,component,sock,&isock)) 1.206 + ABORT(r); 1.207 + /* Create one host candidate */ 1.208 + if(r=nr_ice_candidate_create(ctx,component,isock,sock,HOST,0, 1.209 + component->component_id,&cand)) 1.210 + ABORT(r); 1.211 + 1.212 + TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp); 1.213 + component->candidate_ct++; 1.214 + cand=0; 1.215 + 1.216 + /* And a srvrflx candidate for each STUN server */ 1.217 + for(j=0;j<ctx->stun_server_ct;j++){ 1.218 + if(r=nr_ice_candidate_create(ctx,component, 1.219 + isock,sock,SERVER_REFLEXIVE, 1.220 + &ctx->stun_servers[j],component->component_id,&cand)) 1.221 + ABORT(r); 1.222 + TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp); 1.223 + component->candidate_ct++; 1.224 + cand=0; 1.225 + } 1.226 + 1.227 +#ifdef USE_TURN 1.228 + /* And both a srvrflx and relayed candidate for each TURN server */ 1.229 + for(j=0;j<ctx->turn_server_ct;j++){ 1.230 + nr_socket *turn_sock; 1.231 + nr_ice_candidate *srvflx_cand; 1.232 + 1.233 + /* Skip non-UDP */ 1.234 + if (ctx->turn_servers[j].transport != IPPROTO_UDP) 1.235 + continue; 1.236 + 1.237 + /* srvrflx */ 1.238 + if(r=nr_ice_candidate_create(ctx,component, 1.239 + isock,sock,SERVER_REFLEXIVE, 1.240 + &ctx->turn_servers[j].turn_server,component->component_id,&cand)) 1.241 + ABORT(r); 1.242 + cand->state=NR_ICE_CAND_STATE_INITIALIZING; /* Don't start */ 1.243 + cand->done_cb=nr_ice_initialize_finished_cb; 1.244 + cand->cb_arg=cand; 1.245 + 1.246 + TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp); 1.247 + component->candidate_ct++; 1.248 + srvflx_cand=cand; 1.249 + 1.250 + /* relayed*/ 1.251 + if(r=nr_socket_turn_create(sock, &turn_sock)) 1.252 + ABORT(r); 1.253 + if(r=nr_ice_candidate_create(ctx,component, 1.254 + isock,turn_sock,RELAYED, 1.255 + &ctx->turn_servers[j].turn_server,component->component_id,&cand)) 1.256 + ABORT(r); 1.257 + cand->u.relayed.srvflx_candidate=srvflx_cand; 1.258 + cand->u.relayed.server=&ctx->turn_servers[j]; 1.259 + TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp); 1.260 + component->candidate_ct++; 1.261 + 1.262 + cand=0; 1.263 + } 1.264 +#endif /* USE_TURN */ 1.265 + 1.266 + /* Create a STUN server context for this socket */ 1.267 + snprintf(label, sizeof(label), "server(%s)", addrs[i].addr.as_string); 1.268 + if(r=nr_stun_server_ctx_create(label,sock,&isock->stun_server)) 1.269 + ABORT(r); 1.270 + if(r=nr_ice_socket_register_stun_server(isock,isock->stun_server,&isock->stun_server_handle)) 1.271 + ABORT(r); 1.272 + 1.273 + /* Add the default STUN credentials so that we can respond before 1.274 + we hear about the peer. */ 1.275 + if(r=nr_stun_server_add_default_client(isock->stun_server, lufrag, pwd, nr_ice_component_stun_server_default_cb, component)) 1.276 + ABORT(r); 1.277 + 1.278 + STAILQ_INSERT_TAIL(&component->sockets,isock,entry); 1.279 + } 1.280 + 1.281 + _status = 0; 1.282 + abort: 1.283 + return(_status); 1.284 + } 1.285 + 1.286 +static int nr_ice_component_initialize_tcp(struct nr_ice_ctx_ *ctx,nr_ice_component *component, nr_local_addr *addrs, int addr_ct, char *lufrag, Data *pwd) 1.287 + { 1.288 + nr_ice_socket *isock=0; 1.289 + nr_ice_candidate *cand=0; 1.290 + int i; 1.291 + int j; 1.292 + char label[256]; 1.293 + int r,_status; 1.294 + 1.295 + /* Create a new relayed candidate for each addr/TURN server pair */ 1.296 + for(i=0;i<addr_ct;i++){ 1.297 + char suppress; 1.298 + 1.299 + if(r=NR_reg_get2_char(NR_ICE_REG_SUPPRESS_INTERFACE_PRFX,addrs[i].addr.ifname,&suppress)){ 1.300 + if(r!=R_NOT_FOUND) 1.301 + ABORT(r); 1.302 + } 1.303 + else{ 1.304 + if(suppress) 1.305 + continue; 1.306 + } 1.307 + 1.308 +#ifdef USE_TURN 1.309 + for(j=0;j<ctx->turn_server_ct;j++){ 1.310 + nr_transport_addr addr; 1.311 + nr_socket *sock; 1.312 + nr_socket *buffered_sock; 1.313 + nr_socket *turn_sock; 1.314 + 1.315 + /* Skip non-TCP */ 1.316 + if (ctx->turn_servers[j].transport != IPPROTO_TCP) 1.317 + continue; 1.318 + 1.319 + /* Create a local socket */ 1.320 + if ((r=nr_transport_addr_copy(&addr, &addrs[i].addr))) 1.321 + ABORT(r); 1.322 + addr.protocol = IPPROTO_TCP; 1.323 + if ((r=nr_transport_addr_fmt_addr_string(&addr))) 1.324 + ABORT(r); 1.325 + if((r=nr_socket_local_create(&addr, &sock))){ 1.326 + r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): couldn't create socket for address %s",ctx->label,addr.as_string); 1.327 + continue; 1.328 + } 1.329 + /* Wrap it */ 1.330 + if((r=nr_socket_buffered_stun_create(sock, NR_STUN_MAX_MESSAGE_SIZE, &buffered_sock))) 1.331 + ABORT(r); 1.332 + 1.333 + /* The TURN socket */ 1.334 + if(r=nr_socket_turn_create(buffered_sock, &turn_sock)) 1.335 + ABORT(r); 1.336 + 1.337 + /* Create an ICE socket */ 1.338 + if((r=nr_ice_socket_create(ctx, component, buffered_sock, &isock))) 1.339 + ABORT(r); 1.340 + 1.341 + /* Attach ourselves to it */ 1.342 + if(r=nr_ice_candidate_create(ctx,component, 1.343 + isock,turn_sock,RELAYED, 1.344 + &ctx->turn_servers[j].turn_server,component->component_id,&cand)) 1.345 + ABORT(r); 1.346 + cand->u.relayed.srvflx_candidate=NULL; 1.347 + cand->u.relayed.server=&ctx->turn_servers[j]; 1.348 + TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp); 1.349 + component->candidate_ct++; 1.350 + cand=0; 1.351 + 1.352 + /* Create a STUN server context for this socket */ 1.353 + snprintf(label, sizeof(label), "server(%s)", addr.as_string); 1.354 + if(r=nr_stun_server_ctx_create(label,sock,&isock->stun_server)) 1.355 + ABORT(r); 1.356 + if(r=nr_ice_socket_register_stun_server(isock,isock->stun_server,&isock->stun_server_handle)) 1.357 + ABORT(r); 1.358 + 1.359 + /* Add the default STUN credentials so that we can respond before 1.360 + we hear about the peer.*/ 1.361 + if(r=nr_stun_server_add_default_client(isock->stun_server, lufrag, pwd, nr_ice_component_stun_server_default_cb, component)) 1.362 + ABORT(r); 1.363 + 1.364 + STAILQ_INSERT_TAIL(&component->sockets,isock,entry); 1.365 + } 1.366 + } 1.367 +#endif 1.368 + 1.369 + _status = 0; 1.370 + abort: 1.371 + return(_status); 1.372 + } 1.373 + 1.374 + 1.375 +/* Make all the candidates we can make at the beginning */ 1.376 +int nr_ice_component_initialize(struct nr_ice_ctx_ *ctx,nr_ice_component *component) 1.377 + { 1.378 + int r,_status; 1.379 + nr_local_addr *addrs=ctx->local_addrs; 1.380 + int addr_ct=ctx->local_addr_ct; 1.381 + char *lufrag; 1.382 + char *lpwd; 1.383 + Data pwd; 1.384 + nr_ice_candidate *cand; 1.385 + 1.386 + r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): initializing component with id %d",ctx->label,component->component_id); 1.387 + 1.388 + if(addr_ct==0){ 1.389 + r_log(LOG_ICE,LOG_ERR,"ICE(%s): no local addresses available",ctx->label); 1.390 + ABORT(R_NOT_FOUND); 1.391 + } 1.392 + 1.393 + /* Note: we need to recompute these because 1.394 + we have not yet computed the values in the peer media stream.*/ 1.395 + lufrag=component->stream->ufrag ? component->stream->ufrag : ctx->ufrag; 1.396 + assert(lufrag); 1.397 + if (!lufrag) 1.398 + ABORT(R_INTERNAL); 1.399 + lpwd=component->stream->pwd ? component->stream->pwd :ctx->pwd; 1.400 + assert(lpwd); 1.401 + if (!lpwd) 1.402 + ABORT(R_INTERNAL); 1.403 + INIT_DATA(pwd, (UCHAR *)lpwd, strlen(lpwd)); 1.404 + 1.405 + /* Initialize the UDP candidates */ 1.406 + if (r=nr_ice_component_initialize_udp(ctx, component, addrs, addr_ct, lufrag, &pwd)) 1.407 + ABORT(r); 1.408 + /* And the TCP candidates */ 1.409 + if (r=nr_ice_component_initialize_tcp(ctx, component, addrs, addr_ct, lufrag, &pwd)) 1.410 + ABORT(r); 1.411 + 1.412 + /* count the candidates that will be initialized */ 1.413 + cand=TAILQ_FIRST(&component->candidates); 1.414 + if(!cand){ 1.415 + r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): couldn't create any valid candidates",ctx->label); 1.416 + ABORT(R_NOT_FOUND); 1.417 + } 1.418 + 1.419 + while(cand){ 1.420 + ctx->uninitialized_candidates++; 1.421 + cand=TAILQ_NEXT(cand,entry_comp); 1.422 + } 1.423 + 1.424 + /* Now initialize all the candidates */ 1.425 + cand=TAILQ_FIRST(&component->candidates); 1.426 + while(cand){ 1.427 + if(cand->state!=NR_ICE_CAND_STATE_INITIALIZING){ 1.428 + if(r=nr_ice_candidate_initialize(cand,nr_ice_initialize_finished_cb,cand)){ 1.429 + if(r!=R_WOULDBLOCK){ 1.430 + ctx->uninitialized_candidates--; 1.431 + cand->state=NR_ICE_CAND_STATE_FAILED; 1.432 + } 1.433 + } 1.434 + } 1.435 + cand=TAILQ_NEXT(cand,entry_comp); 1.436 + } 1.437 + _status=0; 1.438 + abort: 1.439 + return(_status); 1.440 + } 1.441 + 1.442 +static int nr_ice_any_peer_paired(nr_ice_candidate* cand) { 1.443 + nr_ice_peer_ctx* pctx=STAILQ_FIRST(&cand->ctx->peers); 1.444 + while(pctx && pctx->state == NR_ICE_PEER_STATE_UNPAIRED){ 1.445 + /* Is it worth actually looking through the check lists? Probably not. */ 1.446 + pctx=STAILQ_NEXT(pctx,entry); 1.447 + } 1.448 + return pctx != NULL; 1.449 +} 1.450 + 1.451 +/* 1.452 + Compare this newly initialized candidate against the other initialized 1.453 + candidates and discard the lower-priority one if they are redundant. 1.454 + 1.455 + This algorithm combined with the other algorithms, favors 1.456 + host > srflx > relay 1.457 + */ 1.458 +int nr_ice_component_maybe_prune_candidate(nr_ice_ctx *ctx, nr_ice_component *comp, nr_ice_candidate *c1, int *was_pruned) 1.459 + { 1.460 + nr_ice_candidate *c2, *tmp = NULL; 1.461 + 1.462 + *was_pruned = 0; 1.463 + c2 = TAILQ_FIRST(&comp->candidates); 1.464 + while(c2){ 1.465 + if((c1 != c2) && 1.466 + (c2->state == NR_ICE_CAND_STATE_INITIALIZED) && 1.467 + !nr_transport_addr_cmp(&c1->base,&c2->base,NR_TRANSPORT_ADDR_CMP_MODE_ALL) && 1.468 + !nr_transport_addr_cmp(&c1->addr,&c2->addr,NR_TRANSPORT_ADDR_CMP_MODE_ALL)){ 1.469 + 1.470 + if((c1->type == c2->type) || 1.471 + (c1->type==HOST && c2->type == SERVER_REFLEXIVE) || 1.472 + (c2->type==HOST && c1->type == SERVER_REFLEXIVE)){ 1.473 + 1.474 + /* 1.475 + These are redundant. Remove the lower pri one, or if pairing has 1.476 + already occurred, remove the newest one. 1.477 + 1.478 + Since this algorithmis run whenever a new candidate 1.479 + is initialized, there should at most one duplicate. 1.480 + */ 1.481 + if ((c1->priority <= c2->priority) || nr_ice_any_peer_paired(c2)) { 1.482 + tmp = c1; 1.483 + *was_pruned = 1; 1.484 + } 1.485 + else { 1.486 + tmp = c2; 1.487 + } 1.488 + break; 1.489 + } 1.490 + } 1.491 + 1.492 + c2=TAILQ_NEXT(c2,entry_comp); 1.493 + } 1.494 + 1.495 + if (tmp) { 1.496 + r_log(LOG_ICE,LOG_DEBUG,"ICE(%s)/CAND(%s): Removing redundant candidate", 1.497 + ctx->label,tmp->label); 1.498 + 1.499 + TAILQ_REMOVE(&comp->candidates,tmp,entry_comp); 1.500 + comp->candidate_ct--; 1.501 + TAILQ_REMOVE(&tmp->isock->candidates,tmp,entry_sock); 1.502 + 1.503 + nr_ice_candidate_destroy(&tmp); 1.504 + } 1.505 + 1.506 + return 0; 1.507 + } 1.508 + 1.509 +/* Section 7.2.1 */ 1.510 +static int nr_ice_component_process_incoming_check(nr_ice_component *comp, nr_transport_addr *local_addr, nr_stun_server_request *req, int *error) 1.511 + { 1.512 + nr_ice_cand_pair *pair; 1.513 + nr_ice_candidate *pcand=0; 1.514 + nr_stun_message *sreq=req->request; 1.515 + nr_stun_message_attribute *attr; 1.516 + int component_id_matched; 1.517 + int local_addr_matched; 1.518 + int remote_addr_matched; 1.519 + nr_ice_cand_pair *found_invalid=0; 1.520 + int r=0,_status; 1.521 + 1.522 + r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/STREAM(%s)/COMP(%d): received request from %s",comp->stream->pctx->label,comp->stream->label,comp->component_id,req->src_addr.as_string); 1.523 + 1.524 + if (comp->state == NR_ICE_COMPONENT_DISABLED) 1.525 + ABORT(R_REJECTED); 1.526 + 1.527 + /* Check for role conficts (7.2.1.1) */ 1.528 + if(comp->stream->pctx->controlling){ 1.529 + if(nr_stun_message_has_attribute(sreq,NR_STUN_ATTR_ICE_CONTROLLING,&attr)){ 1.530 + /* OK, there is a conflict. Who's right? */ 1.531 + r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s): role conflict, both controlling",comp->stream->pctx->label); 1.532 + 1.533 + if(attr->u.ice_controlling > comp->stream->pctx->tiebreaker){ 1.534 + /* They are: switch */ 1.535 + r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s): switching to controlled",comp->stream->pctx->label); 1.536 + 1.537 + comp->stream->pctx->controlling=0; 1.538 + } 1.539 + else { 1.540 + /* We are: throw an error */ 1.541 + r_log(LOG_ICE,LOG_WARNING,"ICE-PEER(%s): returning 487 role conflict",comp->stream->pctx->label); 1.542 + 1.543 + *error=487; 1.544 + ABORT(R_REJECTED); 1.545 + } 1.546 + } 1.547 + } 1.548 + else{ 1.549 + if(nr_stun_message_has_attribute(sreq,NR_STUN_ATTR_ICE_CONTROLLED,&attr)){ 1.550 + /* OK, there is a conflict. Who's right? */ 1.551 + r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s): role conflict, both controlled",comp->stream->pctx->label); 1.552 + 1.553 + if(attr->u.ice_controlling < comp->stream->pctx->tiebreaker){ 1.554 + r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s): switching to controlling",comp->stream->pctx->label); 1.555 + 1.556 + /* They are: switch */ 1.557 + comp->stream->pctx->controlling=1; 1.558 + } 1.559 + else { 1.560 + /* We are: throw an error */ 1.561 + r_log(LOG_ICE,LOG_WARNING,"ICE-PEER(%s): returning 487 role conflict",comp->stream->pctx->label); 1.562 + 1.563 + *error=487; 1.564 + ABORT(R_REJECTED); 1.565 + } 1.566 + } 1.567 + } 1.568 + 1.569 + r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s): This STUN request appears to map to local addr %s",comp->stream->pctx->label,local_addr->as_string); 1.570 + 1.571 + pair=TAILQ_FIRST(&comp->stream->check_list); 1.572 + while(pair){ 1.573 + component_id_matched = 0; 1.574 + local_addr_matched = 0; 1.575 + remote_addr_matched = 0; 1.576 + 1.577 + if(pair->remote->component->component_id!=comp->component_id) 1.578 + goto next_pair; 1.579 + component_id_matched = 1; 1.580 + 1.581 + if(nr_transport_addr_cmp(&pair->local->base,local_addr,NR_TRANSPORT_ADDR_CMP_MODE_ALL)) 1.582 + goto next_pair; 1.583 + local_addr_matched=1; 1.584 + 1.585 + 1.586 + if(nr_transport_addr_cmp(&pair->remote->addr,&req->src_addr,NR_TRANSPORT_ADDR_CMP_MODE_ALL)) 1.587 + goto next_pair; 1.588 + remote_addr_matched = 1; 1.589 + 1.590 + if(pair->state==NR_ICE_PAIR_STATE_FAILED){ 1.591 + found_invalid=pair; 1.592 + goto next_pair; 1.593 + } 1.594 + 1.595 + if (local_addr_matched && remote_addr_matched){ 1.596 + r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/CAND_PAIR(%s): Found a matching pair for received check: %s",comp->stream->pctx->label,pair->codeword,pair->as_string); 1.597 + break; /* OK, this is a known pair */ 1.598 + } 1.599 + 1.600 + next_pair: 1.601 + pair=TAILQ_NEXT(pair,entry); 1.602 + } 1.603 + 1.604 + if(!pair){ 1.605 + if(!found_invalid){ 1.606 + /* First find our local component candidate */ 1.607 + nr_ice_candidate *cand; 1.608 + 1.609 + r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s): no matching pair",comp->stream->pctx->label); 1.610 + cand=TAILQ_FIRST(&comp->local_component->candidates); 1.611 + while(cand){ 1.612 + if(!nr_transport_addr_cmp(&cand->addr,local_addr,NR_TRANSPORT_ADDR_CMP_MODE_ALL)) 1.613 + break; 1.614 + 1.615 + cand=TAILQ_NEXT(cand,entry_comp); 1.616 + } 1.617 + 1.618 + /* Well, this really shouldn't happen, but it's an error from the 1.619 + other side, so we just throw an error and keep going */ 1.620 + if(!cand){ 1.621 + r_log(LOG_ICE,LOG_WARNING,"ICE-PEER(%s): stun request to unknown local address %s, discarding",comp->stream->pctx->label,local_addr->as_string); 1.622 + 1.623 + *error=400; 1.624 + ABORT(R_NOT_FOUND); 1.625 + } 1.626 + 1.627 + /* We now need to make a peer reflexive */ 1.628 + if(r=nr_ice_peer_peer_rflx_candidate_create(comp->stream->pctx->ctx,"prflx",comp,&req->src_addr,&pcand)) { 1.629 + *error=(r==R_NO_MEMORY)?500:400; 1.630 + ABORT(r); 1.631 + } 1.632 + if(!nr_stun_message_has_attribute(sreq,NR_STUN_ATTR_PRIORITY,&attr)){ 1.633 + r_log(LOG_ICE,LOG_WARNING,"ICE-PEER(%s): Rejecting stun request without priority",comp->stream->pctx->label); 1.634 + *error=487; 1.635 + ABORT(R_BAD_DATA); 1.636 + } 1.637 + pcand->priority=attr->u.priority; 1.638 + pcand->state=NR_ICE_CAND_PEER_CANDIDATE_PAIRED; 1.639 + 1.640 + if(r=nr_ice_candidate_pair_create(comp->stream->pctx,cand,pcand, 1.641 + &pair)) { 1.642 + *error=(r==R_NO_MEMORY)?500:400; 1.643 + ABORT(r); 1.644 + } 1.645 + nr_ice_candidate_pair_set_state(pair->pctx,pair,NR_ICE_PAIR_STATE_FROZEN); 1.646 + 1.647 + if(r=nr_ice_component_insert_pair(comp,pair)) { 1.648 + *error=(r==R_NO_MEMORY)?500:400; 1.649 + nr_ice_candidate_pair_destroy(&pair); 1.650 + ABORT(r); 1.651 + } 1.652 + 1.653 + /* Do this last, since any call to ABORT will destroy pcand */ 1.654 + TAILQ_INSERT_TAIL(&comp->candidates,pcand,entry_comp); 1.655 + pcand=0; 1.656 + } 1.657 + else{ 1.658 + /* OK, there was a pair, it's just invalid: According to Section 1.659 + 7.2.1.4, we need to resurrect it 1.660 + */ 1.661 + if(found_invalid->state == NR_ICE_PAIR_STATE_FAILED){ 1.662 + pair=found_invalid; 1.663 + 1.664 + r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s)/CAND-PAIR(%s): received STUN check on invalid pair, resurrecting: %s",comp->stream->pctx->label,pair->codeword,pair->as_string); 1.665 + nr_ice_candidate_pair_set_state(pair->pctx,pair,NR_ICE_PAIR_STATE_WAITING); 1.666 + } 1.667 + else{ 1.668 + /* This shouldn't happen */ 1.669 + r_log(LOG_ICE,LOG_ERR,"ICE-PEER(%s)/CAND-PAIR(%s): received STUN check on invalid pair that was not in state FAILED; this should not happen: %s",comp->stream->pctx->label,pair->codeword,pair->as_string); 1.670 + *error=500; 1.671 + ABORT(R_BAD_DATA); 1.672 + } 1.673 + } 1.674 + } 1.675 + 1.676 + /* OK, we've got a pair to work with. Turn it on */ 1.677 + assert(pair); 1.678 + if(nr_stun_message_has_attribute(sreq,NR_STUN_ATTR_USE_CANDIDATE,0)){ 1.679 + if(comp->stream->pctx->controlling){ 1.680 + r_log(LOG_ICE,LOG_WARNING,"ICE-PEER(%s)/CAND_PAIR(%s): Peer sent USE-CANDIDATE but is controlled",comp->stream->pctx->label, pair->codeword); 1.681 + } 1.682 + else{ 1.683 + /* If this is the first time we've noticed this is nominated...*/ 1.684 + pair->peer_nominated=1; 1.685 + 1.686 + if(pair->state==NR_ICE_PAIR_STATE_SUCCEEDED && !pair->nominated){ 1.687 + pair->nominated=1; 1.688 + 1.689 + if(r=nr_ice_component_nominated_pair(pair->remote->component, pair)) { 1.690 + *error=(r==R_NO_MEMORY)?500:400; 1.691 + ABORT(r); 1.692 + } 1.693 + } 1.694 + } 1.695 + } 1.696 + 1.697 + if(r=nr_ice_candidate_pair_do_triggered_check(comp->stream->pctx,pair)) { 1.698 + *error=(r==R_NO_MEMORY)?500:400; 1.699 + ABORT(r); 1.700 + } 1.701 + 1.702 + _status=0; 1.703 + abort: 1.704 + if(_status){ 1.705 + nr_ice_candidate_destroy(&pcand); 1.706 + assert(*error != 0); 1.707 + if(r!=R_NO_MEMORY) assert(*error != 500); 1.708 + } 1.709 + return(_status); 1.710 + } 1.711 + 1.712 +static int nr_ice_component_stun_server_cb(void *cb_arg,nr_stun_server_ctx *stun_ctx,nr_socket *sock, nr_stun_server_request *req, int *dont_free, int *error) 1.713 + { 1.714 + nr_ice_component *comp=cb_arg; 1.715 + nr_transport_addr local_addr; 1.716 + int r,_status; 1.717 + 1.718 + /* Find the candidate pair that this maps to */ 1.719 + if(r=nr_socket_getaddr(sock,&local_addr)) { 1.720 + *error=500; 1.721 + ABORT(r); 1.722 + } 1.723 + 1.724 + if (r=nr_ice_component_process_incoming_check(comp, &local_addr, req, error)) 1.725 + ABORT(r); 1.726 + 1.727 + _status=0; 1.728 + abort: 1.729 + return(_status); 1.730 + } 1.731 + 1.732 +int nr_ice_component_service_pre_answer_requests(nr_ice_peer_ctx *pctx, nr_ice_component *pcomp, char *username, int *serviced) 1.733 + { 1.734 + nr_ice_pre_answer_request *r1,*r2; 1.735 + nr_ice_component *comp = pcomp->local_component; 1.736 + int r,_status; 1.737 + 1.738 + if (serviced) 1.739 + *serviced = 0; 1.740 + 1.741 + r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/STREAM(%s)/COMP(%d): looking for pre-answer requests",pctx->label,comp->stream->label,comp->component_id); 1.742 + 1.743 + STAILQ_FOREACH_SAFE(r1, &comp->pre_answer_reqs, entry, r2) { 1.744 + if (!strcmp(r1->username, username)) { 1.745 + int error = 0; 1.746 + 1.747 + r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/STREAM(%s)/COMP(%d): found pre-answer request",pctx->label,comp->stream->label,comp->component_id); 1.748 + r = nr_ice_component_process_incoming_check(pcomp, &r1->local_addr, &r1->req, &error); 1.749 + if (r) { 1.750 + r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s)/STREAM(%s)/COMP(%d): error processing pre-answer request. Would have returned %d",pctx->label,comp->stream->label,comp->component_id, error); 1.751 + } 1.752 + (*serviced)++; 1.753 + STAILQ_REMOVE(&comp->pre_answer_reqs,r1,nr_ice_pre_answer_request_, entry); 1.754 + nr_ice_pre_answer_request_destroy(&r1); 1.755 + } 1.756 + } 1.757 + 1.758 + _status=0; 1.759 + return(_status); 1.760 + } 1.761 + 1.762 +int nr_ice_component_pair_candidate(nr_ice_peer_ctx *pctx, nr_ice_component *pcomp, nr_ice_candidate *lcand, int pair_all_remote) 1.763 + { 1.764 + int r, _status; 1.765 + nr_ice_candidate *pcand; 1.766 + nr_ice_cand_pair *pair=0; 1.767 + char codeword[5]; 1.768 + 1.769 + nr_ice_compute_codeword(lcand->label,strlen(lcand->label),codeword); 1.770 + r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/CAND(%s): Pairing local candidate %s",pctx->label,codeword,lcand->label); 1.771 + 1.772 + switch(lcand->type){ 1.773 + case HOST: 1.774 + break; 1.775 + case SERVER_REFLEXIVE: 1.776 + case PEER_REFLEXIVE: 1.777 + /* Don't actually pair these candidates */ 1.778 + goto done; 1.779 + break; 1.780 + case RELAYED: 1.781 + break; 1.782 + default: 1.783 + assert(0); 1.784 + ABORT(R_INTERNAL); 1.785 + break; 1.786 + } 1.787 + 1.788 + pcand=TAILQ_FIRST(&pcomp->candidates); 1.789 + while(pcand){ 1.790 + /* 1.791 + Two modes, depending on |pair_all_remote| 1.792 + 1.793 + 1. Pair remote candidates which have not been paired 1.794 + (used in initial pairing or in processing the other side's 1.795 + trickle candidates). 1.796 + 2. Pair any remote candidate (used when processing our own 1.797 + trickle candidates). 1.798 + */ 1.799 + if (pair_all_remote || (pcand->state == NR_ICE_CAND_PEER_CANDIDATE_UNPAIRED)) { 1.800 + /* If we are pairing our own trickle candidates, the remote candidate should 1.801 + all be paired */ 1.802 + if (pair_all_remote) 1.803 + assert (pcand->state == NR_ICE_CAND_PEER_CANDIDATE_PAIRED); 1.804 + 1.805 + nr_ice_compute_codeword(pcand->label,strlen(pcand->label),codeword); 1.806 + r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/CAND(%s): Pairing with peer candidate %s", pctx->label, codeword, pcand->label); 1.807 + 1.808 + if(r=nr_ice_candidate_pair_create(pctx,lcand,pcand,&pair)) 1.809 + ABORT(r); 1.810 + 1.811 + if(r=nr_ice_component_insert_pair(pcomp, pair)) 1.812 + ABORT(r); 1.813 + } 1.814 + 1.815 + pcand=TAILQ_NEXT(pcand,entry_comp); 1.816 + } 1.817 + 1.818 + done: 1.819 + _status = 0; 1.820 + abort: 1.821 + return(_status); 1.822 + } 1.823 + 1.824 +int nr_ice_component_pair_candidates(nr_ice_peer_ctx *pctx, nr_ice_component *lcomp,nr_ice_component *pcomp) 1.825 + { 1.826 + nr_ice_candidate *lcand, *pcand; 1.827 + nr_ice_socket *isock; 1.828 + int r,_status; 1.829 + 1.830 + r_log(LOG_ICE,LOG_DEBUG,"Pairing candidates======"); 1.831 + 1.832 + /* Create the candidate pairs */ 1.833 + lcand=TAILQ_FIRST(&lcomp->candidates); 1.834 + while(lcand){ 1.835 + if (lcand->state == NR_ICE_CAND_STATE_INITIALIZED) { 1.836 + if ((r = nr_ice_component_pair_candidate(pctx, pcomp, lcand, 0))) 1.837 + ABORT(r); 1.838 + } 1.839 + 1.840 + lcand=TAILQ_NEXT(lcand,entry_comp); 1.841 + } 1.842 + 1.843 + /* Mark all peer candidates as paired */ 1.844 + pcand=TAILQ_FIRST(&pcomp->candidates); 1.845 + while(pcand){ 1.846 + pcand->state = NR_ICE_CAND_PEER_CANDIDATE_PAIRED; 1.847 + 1.848 + pcand=TAILQ_NEXT(pcand,entry_comp); 1.849 + 1.850 + } 1.851 + 1.852 + /* Now register the STUN server callback for this component. 1.853 + Note that this is a per-component CB so we only need to 1.854 + do this once. 1.855 + */ 1.856 + if (pcomp->state != NR_ICE_COMPONENT_RUNNING) { 1.857 + isock=STAILQ_FIRST(&lcomp->sockets); 1.858 + while(isock){ 1.859 + if(r=nr_stun_server_add_client(isock->stun_server,pctx->label, 1.860 + pcomp->stream->r2l_user,&pcomp->stream->r2l_pass,nr_ice_component_stun_server_cb,pcomp)) { 1.861 + ABORT(r); 1.862 + } 1.863 + isock=STAILQ_NEXT(isock,entry); 1.864 + } 1.865 + } 1.866 + 1.867 + pcomp->state = NR_ICE_COMPONENT_RUNNING; 1.868 + 1.869 + _status=0; 1.870 + abort: 1.871 + return(_status); 1.872 + } 1.873 + 1.874 +/* Fires when we have an incoming candidate that doesn't correspond to an existing 1.875 + remote peer. This is either pre-answer or just spurious. Store it in the 1.876 + component for use when we see the actual answer, at which point we need 1.877 + to do the procedures from S 7.2.1 in nr_ice_component_stun_server_cb. 1.878 + */ 1.879 +static int nr_ice_component_stun_server_default_cb(void *cb_arg,nr_stun_server_ctx *stun_ctx,nr_socket *sock, nr_stun_server_request *req, int *dont_free, int *error) 1.880 + { 1.881 + int r, _status; 1.882 + nr_ice_component *comp = (nr_ice_component *)cb_arg; 1.883 + nr_ice_pre_answer_request *par = 0; 1.884 + r_log(LOG_ICE,LOG_DEBUG,"ICE(%s)/STREAM(%s)/COMP(%d): Received STUN request pre-answer from %s", 1.885 + comp->ctx->label, comp->stream->label, comp->component_id, req->src_addr.as_string); 1.886 + 1.887 + if (r=nr_ice_pre_answer_request_create(sock, req, &par)) 1.888 + ABORT(r); 1.889 + 1.890 + *dont_free = 1; 1.891 + STAILQ_INSERT_TAIL(&comp->pre_answer_reqs, par, entry); 1.892 + 1.893 + _status=0; 1.894 + abort: 1.895 + return 0; 1.896 + } 1.897 + 1.898 +int nr_ice_component_nominated_pair(nr_ice_component *comp, nr_ice_cand_pair *pair) 1.899 + { 1.900 + int r,_status; 1.901 + int fire_cb=0; 1.902 + nr_ice_cand_pair *p2; 1.903 + 1.904 + if(!comp->nominated) 1.905 + fire_cb=1; 1.906 + 1.907 + /* Are we changing what the nominated pair is? */ 1.908 + if(comp->nominated){ 1.909 + if(comp->nominated->priority > pair->priority) 1.910 + return(0); 1.911 + r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s)/STREAM(%s)/COMP(%d)/CAND-PAIR(%s): replacing pair %s with CAND-PAIR(%s)",comp->stream->pctx->label,comp->stream->label,comp->component_id,comp->nominated->codeword,comp->nominated->as_string,pair->codeword); 1.912 + } 1.913 + 1.914 + /* Set the new nominated pair */ 1.915 + r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s)/STREAM(%s)/COMP(%d)/CAND-PAIR(%s): nominated pair is %s",comp->stream->pctx->label,comp->stream->label,comp->component_id,pair->codeword,pair->as_string); 1.916 + comp->state=NR_ICE_COMPONENT_NOMINATED; 1.917 + comp->nominated=pair; 1.918 + comp->active=pair; 1.919 + 1.920 + r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s)/STREAM(%s)/COMP(%d)/CAND-PAIR(%s): cancelling all pairs but %s",comp->stream->pctx->label,comp->stream->label,comp->component_id,pair->codeword,pair->as_string); 1.921 + 1.922 + /* Cancel checks in WAITING and FROZEN per ICE S 8.1.2 */ 1.923 + p2=TAILQ_FIRST(&comp->stream->check_list); 1.924 + while(p2){ 1.925 + if((p2 != pair) && 1.926 + (p2->remote->component->component_id == comp->component_id) && 1.927 + ((p2->state == NR_ICE_PAIR_STATE_FROZEN) || 1.928 + (p2->state == NR_ICE_PAIR_STATE_WAITING))) { 1.929 + r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s)/STREAM(%s)/COMP(%d)/CAND-PAIR(%s): cancelling FROZEN/WAITING pair %s because CAND-PAIR(%s) was nominated.",comp->stream->pctx->label,comp->stream->label,comp->component_id,p2->codeword,p2->as_string,pair->codeword); 1.930 + 1.931 + if(r=nr_ice_candidate_pair_cancel(pair->pctx,p2)) 1.932 + ABORT(r); 1.933 + } 1.934 + 1.935 + p2=TAILQ_NEXT(p2,entry); 1.936 + } 1.937 + r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/STREAM(%s)/COMP(%d): cancelling done",comp->stream->pctx->label,comp->stream->label,comp->component_id); 1.938 + 1.939 + if(r=nr_ice_media_stream_component_nominated(comp->stream,comp)) 1.940 + ABORT(r); 1.941 + 1.942 + _status=0; 1.943 + abort: 1.944 + return(_status); 1.945 + } 1.946 + 1.947 +int nr_ice_component_failed_pair(nr_ice_component *comp, nr_ice_cand_pair *pair) 1.948 + { 1.949 + int r,_status; 1.950 + nr_ice_cand_pair *p2; 1.951 + 1.952 + assert(pair->state == NR_ICE_PAIR_STATE_FAILED); 1.953 + 1.954 + p2=TAILQ_FIRST(&comp->stream->check_list); 1.955 + while(p2){ 1.956 + if(comp->component_id==p2->local->component_id){ 1.957 + switch(p2->state){ 1.958 + case NR_ICE_PAIR_STATE_FROZEN: 1.959 + case NR_ICE_PAIR_STATE_WAITING: 1.960 + case NR_ICE_PAIR_STATE_IN_PROGRESS: 1.961 + /* answer component status cannot be determined yet */ 1.962 + goto done; 1.963 + break; 1.964 + case NR_ICE_PAIR_STATE_SUCCEEDED: 1.965 + /* the component will succeed */ 1.966 + goto done; 1.967 + break; 1.968 + case NR_ICE_PAIR_STATE_FAILED: 1.969 + case NR_ICE_PAIR_STATE_CANCELLED: 1.970 + /* states that will never be recovered from */ 1.971 + break; 1.972 + default: 1.973 + assert(0); 1.974 + break; 1.975 + } 1.976 + } 1.977 + 1.978 + p2=TAILQ_NEXT(p2,entry); 1.979 + } 1.980 + 1.981 + /* all the pairs in the component are in their final states with 1.982 + * none of them being SUCCEEDED, so the component fails entirely, 1.983 + * tell the media stream that this component has failed */ 1.984 + 1.985 + if(r=nr_ice_media_stream_component_failed(comp->stream,comp)) 1.986 + ABORT(r); 1.987 + 1.988 + done: 1.989 + _status=0; 1.990 + abort: 1.991 + return(_status); 1.992 + } 1.993 + 1.994 +int nr_ice_component_select_pair(nr_ice_peer_ctx *pctx, nr_ice_component *comp) 1.995 + { 1.996 + nr_ice_cand_pair **pairs=0; 1.997 + int ct=0; 1.998 + nr_ice_cand_pair *pair; 1.999 + int r,_status; 1.1000 + 1.1001 + /* Size the array */ 1.1002 + pair=TAILQ_FIRST(&comp->stream->check_list); 1.1003 + while(pair){ 1.1004 + if (comp->component_id == pair->local->component_id) 1.1005 + ct++; 1.1006 + 1.1007 + pair=TAILQ_NEXT(pair,entry); 1.1008 + } 1.1009 + 1.1010 + /* Make and fill the array */ 1.1011 + if(!(pairs=RCALLOC(sizeof(nr_ice_cand_pair *)*ct))) 1.1012 + ABORT(R_NO_MEMORY); 1.1013 + 1.1014 + ct=0; 1.1015 + pair=TAILQ_FIRST(&comp->stream->check_list); 1.1016 + while(pair){ 1.1017 + if (comp->component_id == pair->local->component_id) 1.1018 + pairs[ct++]=pair; 1.1019 + 1.1020 + pair=TAILQ_NEXT(pair,entry); 1.1021 + } 1.1022 + 1.1023 + if (pctx->handler) { 1.1024 + if(r=pctx->handler->vtbl->select_pair(pctx->handler->obj, 1.1025 + comp->stream,comp->component_id,pairs,ct)) 1.1026 + ABORT(r); 1.1027 + } 1.1028 + 1.1029 + _status=0; 1.1030 + abort: 1.1031 + RFREE(pairs); 1.1032 + return(_status); 1.1033 + } 1.1034 + 1.1035 + 1.1036 +static void nr_ice_component_keepalive_cb(NR_SOCKET s, int how, void *cb_arg) 1.1037 + { 1.1038 + nr_ice_component *comp=cb_arg; 1.1039 + UINT4 keepalive_timeout; 1.1040 + 1.1041 + assert(comp->keepalive_ctx); 1.1042 + 1.1043 + if(NR_reg_get_uint4(NR_ICE_REG_KEEPALIVE_TIMER,&keepalive_timeout)){ 1.1044 + keepalive_timeout=15000; /* Default */ 1.1045 + } 1.1046 + 1.1047 + 1.1048 + if(comp->keepalive_needed) 1.1049 + nr_stun_client_force_retransmit(comp->keepalive_ctx); 1.1050 + 1.1051 + comp->keepalive_needed=1; 1.1052 + NR_ASYNC_TIMER_SET(keepalive_timeout,nr_ice_component_keepalive_cb,cb_arg,&comp->keepalive_timer); 1.1053 + } 1.1054 + 1.1055 + 1.1056 +/* Close the underlying sockets for everything but the nominated candidate */ 1.1057 +int nr_ice_component_finalize(nr_ice_component *lcomp, nr_ice_component *rcomp) 1.1058 + { 1.1059 + nr_ice_socket *isock=0; 1.1060 + int r,_status; 1.1061 + nr_ice_socket *s1,*s2; 1.1062 + 1.1063 + if(rcomp->state==NR_ICE_COMPONENT_NOMINATED){ 1.1064 + assert(rcomp->active == rcomp->nominated); 1.1065 + isock=rcomp->nominated->local->isock; 1.1066 + } 1.1067 + 1.1068 + STAILQ_FOREACH_SAFE(s1, &lcomp->sockets, entry, s2){ 1.1069 + if(s1!=isock){ 1.1070 + STAILQ_REMOVE(&lcomp->sockets,s1,nr_ice_socket_,entry); 1.1071 + nr_ice_socket_destroy(&s1); 1.1072 + } 1.1073 + } 1.1074 + 1.1075 + /* Set up the keepalives for the chosen socket */ 1.1076 + if(r=nr_stun_client_ctx_create("keepalive",rcomp->nominated->local->osock, 1.1077 + &rcomp->nominated->remote->addr,0,&rcomp->keepalive_ctx)) 1.1078 + ABORT(r); 1.1079 + if(r=nr_stun_client_start(rcomp->keepalive_ctx,NR_STUN_CLIENT_MODE_KEEPALIVE,0,0)) 1.1080 + ABORT(r); 1.1081 + nr_ice_component_keepalive_cb(0,0,rcomp); 1.1082 + 1.1083 + 1.1084 + _status=0; 1.1085 + abort: 1.1086 + 1.1087 + return(_status); 1.1088 + } 1.1089 + 1.1090 + 1.1091 +int nr_ice_component_insert_pair(nr_ice_component *pcomp, nr_ice_cand_pair *pair) 1.1092 + { 1.1093 + int r,_status; 1.1094 + 1.1095 + /* Pairs for peer reflexive are marked SUCCEEDED immediately */ 1.1096 + if (pair->state != NR_ICE_PAIR_STATE_FROZEN && 1.1097 + pair->state != NR_ICE_PAIR_STATE_SUCCEEDED){ 1.1098 + assert(0); 1.1099 + ABORT(R_BAD_ARGS); 1.1100 + } 1.1101 + 1.1102 + if(r=nr_ice_candidate_pair_insert(&pair->remote->stream->check_list,pair)) 1.1103 + ABORT(r); 1.1104 + 1.1105 + /* Make sure the check timer is running, if the stream was previously 1.1106 + * started. We will not start streams just because a pair was created. */ 1.1107 + if(pair->remote->stream->ice_state == NR_ICE_MEDIA_STREAM_CHECKS_ACTIVE){ 1.1108 + if(nr_ice_media_stream_start_checks(pair->remote->stream->pctx, pair->remote->stream)) { 1.1109 + r_log(LOG_ICE,LOG_WARNING,"ICE-PEER(%s)/CAND-PAIR(%s): Could not restart checks for new pair %s.",pair->remote->stream->pctx->label, pair->codeword, pair->as_string); 1.1110 + ABORT(R_INTERNAL); 1.1111 + } 1.1112 + } 1.1113 + 1.1114 + _status=0; 1.1115 + abort: 1.1116 + return(_status); 1.1117 + } 1.1118 +