media/mtransport/third_party/nICEr/src/ice/ice_component.c

changeset 0
6474c204b198
     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 +

mercurial